root/drivers/char/agp/parisc-agp.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. parisc_agp_fetch_size
  2. parisc_agp_configure
  3. parisc_agp_tlbflush
  4. parisc_agp_create_gatt_table
  5. parisc_agp_free_gatt_table
  6. parisc_agp_insert_memory
  7. parisc_agp_remove_memory
  8. parisc_agp_mask_memory
  9. parisc_agp_enable
  10. agp_ioc_init
  11. lba_find_capability
  12. agp_lba_init
  13. parisc_agp_setup
  14. find_quicksilver
  15. parisc_agp_init

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * HP Quicksilver AGP GART routines
   4  *
   5  * Copyright (c) 2006, Kyle McMartin <kyle@parisc-linux.org>
   6  *
   7  * Based on drivers/char/agpgart/hp-agp.c which is
   8  * (c) Copyright 2002, 2003 Hewlett-Packard Development Company, L.P.
   9  *      Bjorn Helgaas <bjorn.helgaas@hp.com>
  10  */
  11 
  12 #include <linux/module.h>
  13 #include <linux/pci.h>
  14 #include <linux/init.h>
  15 #include <linux/klist.h>
  16 #include <linux/agp_backend.h>
  17 #include <linux/log2.h>
  18 #include <linux/slab.h>
  19 
  20 #include <asm/parisc-device.h>
  21 #include <asm/ropes.h>
  22 
  23 #include "agp.h"
  24 
  25 #define DRVNAME "quicksilver"
  26 #define DRVPFX  DRVNAME ": "
  27 
  28 #define AGP8X_MODE_BIT          3
  29 #define AGP8X_MODE              (1 << AGP8X_MODE_BIT)
  30 
  31 static unsigned long
  32 parisc_agp_mask_memory(struct agp_bridge_data *bridge, dma_addr_t addr,
  33                        int type);
  34 
  35 static struct _parisc_agp_info {
  36         void __iomem *ioc_regs;
  37         void __iomem *lba_regs;
  38 
  39         int lba_cap_offset;
  40 
  41         u64 *gatt;
  42         u64 gatt_entries;
  43 
  44         u64 gart_base;
  45         u64 gart_size;
  46 
  47         int io_page_size;
  48         int io_pages_per_kpage;
  49 } parisc_agp_info;
  50 
  51 static struct gatt_mask parisc_agp_masks[] =
  52 {
  53         {
  54                 .mask = SBA_PDIR_VALID_BIT,
  55                 .type = 0
  56         }
  57 };
  58 
  59 static struct aper_size_info_fixed parisc_agp_sizes[] =
  60 {
  61         {0, 0, 0},              /* filled in by parisc_agp_fetch_size() */
  62 };
  63 
  64 static int
  65 parisc_agp_fetch_size(void)
  66 {
  67         int size;
  68 
  69         size = parisc_agp_info.gart_size / MB(1);
  70         parisc_agp_sizes[0].size = size;
  71         agp_bridge->current_size = (void *) &parisc_agp_sizes[0];
  72 
  73         return size;
  74 }
  75 
  76 static int
  77 parisc_agp_configure(void)
  78 {
  79         struct _parisc_agp_info *info = &parisc_agp_info;
  80 
  81         agp_bridge->gart_bus_addr = info->gart_base;
  82         agp_bridge->capndx = info->lba_cap_offset;
  83         agp_bridge->mode = readl(info->lba_regs+info->lba_cap_offset+PCI_AGP_STATUS);
  84 
  85         return 0;
  86 }
  87 
  88 static void
  89 parisc_agp_tlbflush(struct agp_memory *mem)
  90 {
  91         struct _parisc_agp_info *info = &parisc_agp_info;
  92 
  93         writeq(info->gart_base | ilog2(info->gart_size), info->ioc_regs+IOC_PCOM);
  94         readq(info->ioc_regs+IOC_PCOM); /* flush */
  95 }
  96 
  97 static int
  98 parisc_agp_create_gatt_table(struct agp_bridge_data *bridge)
  99 {
 100         struct _parisc_agp_info *info = &parisc_agp_info;
 101         int i;
 102 
 103         for (i = 0; i < info->gatt_entries; i++) {
 104                 info->gatt[i] = (unsigned long)agp_bridge->scratch_page;
 105         }
 106 
 107         return 0;
 108 }
 109 
 110 static int
 111 parisc_agp_free_gatt_table(struct agp_bridge_data *bridge)
 112 {
 113         struct _parisc_agp_info *info = &parisc_agp_info;
 114 
 115         info->gatt[0] = SBA_AGPGART_COOKIE;
 116 
 117         return 0;
 118 }
 119 
 120 static int
 121 parisc_agp_insert_memory(struct agp_memory *mem, off_t pg_start, int type)
 122 {
 123         struct _parisc_agp_info *info = &parisc_agp_info;
 124         int i, k;
 125         off_t j, io_pg_start;
 126         int io_pg_count;
 127 
 128         if (type != mem->type ||
 129                 agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type)) {
 130                 return -EINVAL;
 131         }
 132 
 133         io_pg_start = info->io_pages_per_kpage * pg_start;
 134         io_pg_count = info->io_pages_per_kpage * mem->page_count;
 135         if ((io_pg_start + io_pg_count) > info->gatt_entries) {
 136                 return -EINVAL;
 137         }
 138 
 139         j = io_pg_start;
 140         while (j < (io_pg_start + io_pg_count)) {
 141                 if (info->gatt[j])
 142                         return -EBUSY;
 143                 j++;
 144         }
 145 
 146         if (!mem->is_flushed) {
 147                 global_cache_flush();
 148                 mem->is_flushed = true;
 149         }
 150 
 151         for (i = 0, j = io_pg_start; i < mem->page_count; i++) {
 152                 unsigned long paddr;
 153 
 154                 paddr = page_to_phys(mem->pages[i]);
 155                 for (k = 0;
 156                      k < info->io_pages_per_kpage;
 157                      k++, j++, paddr += info->io_page_size) {
 158                         info->gatt[j] =
 159                                 parisc_agp_mask_memory(agp_bridge,
 160                                         paddr, type);
 161                 }
 162         }
 163 
 164         agp_bridge->driver->tlb_flush(mem);
 165 
 166         return 0;
 167 }
 168 
 169 static int
 170 parisc_agp_remove_memory(struct agp_memory *mem, off_t pg_start, int type)
 171 {
 172         struct _parisc_agp_info *info = &parisc_agp_info;
 173         int i, io_pg_start, io_pg_count;
 174 
 175         if (type != mem->type ||
 176                 agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type)) {
 177                 return -EINVAL;
 178         }
 179 
 180         io_pg_start = info->io_pages_per_kpage * pg_start;
 181         io_pg_count = info->io_pages_per_kpage * mem->page_count;
 182         for (i = io_pg_start; i < io_pg_count + io_pg_start; i++) {
 183                 info->gatt[i] = agp_bridge->scratch_page;
 184         }
 185 
 186         agp_bridge->driver->tlb_flush(mem);
 187         return 0;
 188 }
 189 
 190 static unsigned long
 191 parisc_agp_mask_memory(struct agp_bridge_data *bridge, dma_addr_t addr,
 192                        int type)
 193 {
 194         return SBA_PDIR_VALID_BIT | addr;
 195 }
 196 
 197 static void
 198 parisc_agp_enable(struct agp_bridge_data *bridge, u32 mode)
 199 {
 200         struct _parisc_agp_info *info = &parisc_agp_info;
 201         u32 command;
 202 
 203         command = readl(info->lba_regs + info->lba_cap_offset + PCI_AGP_STATUS);
 204 
 205         command = agp_collect_device_status(bridge, mode, command);
 206         command |= 0x00000100;
 207 
 208         writel(command, info->lba_regs + info->lba_cap_offset + PCI_AGP_COMMAND);
 209 
 210         agp_device_command(command, (mode & AGP8X_MODE) != 0);
 211 }
 212 
 213 static const struct agp_bridge_driver parisc_agp_driver = {
 214         .owner                  = THIS_MODULE,
 215         .size_type              = FIXED_APER_SIZE,
 216         .configure              = parisc_agp_configure,
 217         .fetch_size             = parisc_agp_fetch_size,
 218         .tlb_flush              = parisc_agp_tlbflush,
 219         .mask_memory            = parisc_agp_mask_memory,
 220         .masks                  = parisc_agp_masks,
 221         .agp_enable             = parisc_agp_enable,
 222         .cache_flush            = global_cache_flush,
 223         .create_gatt_table      = parisc_agp_create_gatt_table,
 224         .free_gatt_table        = parisc_agp_free_gatt_table,
 225         .insert_memory          = parisc_agp_insert_memory,
 226         .remove_memory          = parisc_agp_remove_memory,
 227         .alloc_by_type          = agp_generic_alloc_by_type,
 228         .free_by_type           = agp_generic_free_by_type,
 229         .agp_alloc_page         = agp_generic_alloc_page,
 230         .agp_alloc_pages        = agp_generic_alloc_pages,
 231         .agp_destroy_page       = agp_generic_destroy_page,
 232         .agp_destroy_pages      = agp_generic_destroy_pages,
 233         .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 234         .cant_use_aperture      = true,
 235 };
 236 
 237 static int __init
 238 agp_ioc_init(void __iomem *ioc_regs)
 239 {
 240         struct _parisc_agp_info *info = &parisc_agp_info;
 241         u64 iova_base, *io_pdir, io_tlb_ps;
 242         int io_tlb_shift;
 243 
 244         printk(KERN_INFO DRVPFX "IO PDIR shared with sba_iommu\n");
 245 
 246         info->ioc_regs = ioc_regs;
 247 
 248         io_tlb_ps = readq(info->ioc_regs+IOC_TCNFG);
 249         switch (io_tlb_ps) {
 250         case 0: io_tlb_shift = 12; break;
 251         case 1: io_tlb_shift = 13; break;
 252         case 2: io_tlb_shift = 14; break;
 253         case 3: io_tlb_shift = 16; break;
 254         default:
 255                 printk(KERN_ERR DRVPFX "Invalid IOTLB page size "
 256                        "configuration 0x%llx\n", io_tlb_ps);
 257                 info->gatt = NULL;
 258                 info->gatt_entries = 0;
 259                 return -ENODEV;
 260         }
 261         info->io_page_size = 1 << io_tlb_shift;
 262         info->io_pages_per_kpage = PAGE_SIZE / info->io_page_size;
 263 
 264         iova_base = readq(info->ioc_regs+IOC_IBASE) & ~0x1;
 265         info->gart_base = iova_base + PLUTO_IOVA_SIZE - PLUTO_GART_SIZE;
 266 
 267         info->gart_size = PLUTO_GART_SIZE;
 268         info->gatt_entries = info->gart_size / info->io_page_size;
 269 
 270         io_pdir = phys_to_virt(readq(info->ioc_regs+IOC_PDIR_BASE));
 271         info->gatt = &io_pdir[(PLUTO_IOVA_SIZE/2) >> PAGE_SHIFT];
 272 
 273         if (info->gatt[0] != SBA_AGPGART_COOKIE) {
 274                 info->gatt = NULL;
 275                 info->gatt_entries = 0;
 276                 printk(KERN_ERR DRVPFX "No reserved IO PDIR entry found; "
 277                        "GART disabled\n");
 278                 return -ENODEV;
 279         }
 280 
 281         return 0;
 282 }
 283 
 284 static int
 285 lba_find_capability(int cap)
 286 {
 287         struct _parisc_agp_info *info = &parisc_agp_info;
 288         u16 status;
 289         u8 pos, id;
 290         int ttl = 48;
 291 
 292         status = readw(info->lba_regs + PCI_STATUS);
 293         if (!(status & PCI_STATUS_CAP_LIST))
 294                 return 0;
 295         pos = readb(info->lba_regs + PCI_CAPABILITY_LIST);
 296         while (ttl-- && pos >= 0x40) {
 297                 pos &= ~3;
 298                 id = readb(info->lba_regs + pos + PCI_CAP_LIST_ID);
 299                 if (id == 0xff)
 300                         break;
 301                 if (id == cap)
 302                         return pos;
 303                 pos = readb(info->lba_regs + pos + PCI_CAP_LIST_NEXT);
 304         }
 305         return 0;
 306 }
 307 
 308 static int __init
 309 agp_lba_init(void __iomem *lba_hpa)
 310 {
 311         struct _parisc_agp_info *info = &parisc_agp_info;
 312         int cap;
 313 
 314         info->lba_regs = lba_hpa;
 315         info->lba_cap_offset = lba_find_capability(PCI_CAP_ID_AGP);
 316 
 317         cap = readl(lba_hpa + info->lba_cap_offset) & 0xff;
 318         if (cap != PCI_CAP_ID_AGP) {
 319                 printk(KERN_ERR DRVPFX "Invalid capability ID 0x%02x at 0x%x\n",
 320                        cap, info->lba_cap_offset);
 321                 return -ENODEV;
 322         }
 323 
 324         return 0;
 325 }
 326 
 327 static int __init
 328 parisc_agp_setup(void __iomem *ioc_hpa, void __iomem *lba_hpa)
 329 {
 330         struct pci_dev *fake_bridge_dev = NULL;
 331         struct agp_bridge_data *bridge;
 332         int error = 0;
 333 
 334         fake_bridge_dev = pci_alloc_dev(NULL);
 335         if (!fake_bridge_dev) {
 336                 error = -ENOMEM;
 337                 goto fail;
 338         }
 339 
 340         error = agp_ioc_init(ioc_hpa);
 341         if (error)
 342                 goto fail;
 343 
 344         error = agp_lba_init(lba_hpa);
 345         if (error)
 346                 goto fail;
 347 
 348         bridge = agp_alloc_bridge();
 349         if (!bridge) {
 350                 error = -ENOMEM;
 351                 goto fail;
 352         }
 353         bridge->driver = &parisc_agp_driver;
 354 
 355         fake_bridge_dev->vendor = PCI_VENDOR_ID_HP;
 356         fake_bridge_dev->device = PCI_DEVICE_ID_HP_PCIX_LBA;
 357         bridge->dev = fake_bridge_dev;
 358 
 359         error = agp_add_bridge(bridge);
 360         if (error)
 361                 goto fail;
 362         return 0;
 363 
 364 fail:
 365         kfree(fake_bridge_dev);
 366         return error;
 367 }
 368 
 369 static int
 370 find_quicksilver(struct device *dev, void *data)
 371 {
 372         struct parisc_device **lba = data;
 373         struct parisc_device *padev = to_parisc_device(dev);
 374 
 375         if (IS_QUICKSILVER(padev))
 376                 *lba = padev;
 377 
 378         return 0;
 379 }
 380 
 381 static int
 382 parisc_agp_init(void)
 383 {
 384         extern struct sba_device *sba_list;
 385 
 386         int err = -1;
 387         struct parisc_device *sba = NULL, *lba = NULL;
 388         struct lba_device *lbadev = NULL;
 389 
 390         if (!sba_list)
 391                 goto out;
 392 
 393         /* Find our parent Pluto */
 394         sba = sba_list->dev;
 395         if (!IS_PLUTO(sba)) {
 396                 printk(KERN_INFO DRVPFX "No Pluto found, so no AGPGART for you.\n");
 397                 goto out;
 398         }
 399 
 400         /* Now search our Pluto for our precious AGP device... */
 401         device_for_each_child(&sba->dev, &lba, find_quicksilver);
 402 
 403         if (!lba) {
 404                 printk(KERN_INFO DRVPFX "No AGP devices found.\n");
 405                 goto out;
 406         }
 407 
 408         lbadev = parisc_get_drvdata(lba);
 409 
 410         /* w00t, let's go find our cookies... */
 411         parisc_agp_setup(sba_list->ioc[0].ioc_hpa, lbadev->hba.base_addr);
 412 
 413         return 0;
 414 
 415 out:
 416         return err;
 417 }
 418 
 419 module_init(parisc_agp_init);
 420 
 421 MODULE_AUTHOR("Kyle McMartin <kyle@parisc-linux.org>");
 422 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */