Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]
Version: [ 2.6.11.8 ] [ 2.6.25 ] [ 2.6.25.8 ] [ 2.6.31.13 ] Architecture: [ i386 ]
  1 /*
  2  * AMD K7 AGPGART routines.
  3  */
  4 
  5 #include <linux/module.h>
  6 #include <linux/pci.h>
  7 #include <linux/init.h>
  8 #include <linux/agp_backend.h>
  9 #include <linux/gfp.h>
 10 #include <linux/page-flags.h>
 11 #include <linux/mm.h>
 12 #include "agp.h"
 13 
 14 #define AMD_MMBASE      0x14
 15 #define AMD_APSIZE      0xac
 16 #define AMD_MODECNTL    0xb0
 17 #define AMD_MODECNTL2   0xb2
 18 #define AMD_GARTENABLE  0x02    /* In mmio region (16-bit register) */
 19 #define AMD_ATTBASE     0x04    /* In mmio region (32-bit register) */
 20 #define AMD_TLBFLUSH    0x0c    /* In mmio region (32-bit register) */
 21 #define AMD_CACHEENTRY  0x10    /* In mmio region (32-bit register) */
 22 
 23 static struct pci_device_id agp_amdk7_pci_table[];
 24 
 25 struct amd_page_map {
 26         unsigned long *real;
 27         unsigned long __iomem *remapped;
 28 };
 29 
 30 static struct _amd_irongate_private {
 31         volatile u8 __iomem *registers;
 32         struct amd_page_map **gatt_pages;
 33         int num_tables;
 34 } amd_irongate_private;
 35 
 36 static int amd_create_page_map(struct amd_page_map *page_map)
 37 {
 38         int i;
 39 
 40         page_map->real = (unsigned long *) __get_free_page(GFP_KERNEL);
 41         if (page_map->real == NULL)
 42                 return -ENOMEM;
 43 
 44 #ifndef CONFIG_X86
 45         SetPageReserved(virt_to_page(page_map->real));
 46         global_cache_flush();
 47         page_map->remapped = ioremap_nocache(virt_to_gart(page_map->real),
 48                                             PAGE_SIZE);
 49         if (page_map->remapped == NULL) {
 50                 ClearPageReserved(virt_to_page(page_map->real));
 51                 free_page((unsigned long) page_map->real);
 52                 page_map->real = NULL;
 53                 return -ENOMEM;
 54         }
 55         global_cache_flush();
 56 #else
 57         set_memory_uc((unsigned long)page_map->real, 1);
 58         page_map->remapped = page_map->real;
 59 #endif
 60 
 61         for (i = 0; i < PAGE_SIZE / sizeof(unsigned long); i++) {
 62                 writel(agp_bridge->scratch_page, page_map->remapped+i);
 63                 readl(page_map->remapped+i);    /* PCI Posting. */
 64         }
 65 
 66         return 0;
 67 }
 68 
 69 static void amd_free_page_map(struct amd_page_map *page_map)
 70 {
 71 #ifndef CONFIG_X86
 72         iounmap(page_map->remapped);
 73         ClearPageReserved(virt_to_page(page_map->real));
 74 #else
 75         set_memory_wb((unsigned long)page_map->real, 1);
 76 #endif
 77         free_page((unsigned long) page_map->real);
 78 }
 79 
 80 static void amd_free_gatt_pages(void)
 81 {
 82         int i;
 83         struct amd_page_map **tables;
 84         struct amd_page_map *entry;
 85 
 86         tables = amd_irongate_private.gatt_pages;
 87         for (i = 0; i < amd_irongate_private.num_tables; i++) {
 88                 entry = tables[i];
 89                 if (entry != NULL) {
 90                         if (entry->real != NULL)
 91                                 amd_free_page_map(entry);
 92                         kfree(entry);
 93                 }
 94         }
 95         kfree(tables);
 96         amd_irongate_private.gatt_pages = NULL;
 97 }
 98 
 99 static int amd_create_gatt_pages(int nr_tables)
100 {
101         struct amd_page_map **tables;
102         struct amd_page_map *entry;
103         int retval = 0;
104         int i;
105 
106         tables = kzalloc((nr_tables + 1) * sizeof(struct amd_page_map *),GFP_KERNEL);
107         if (tables == NULL)
108                 return -ENOMEM;
109 
110         for (i = 0; i < nr_tables; i++) {
111                 entry = kzalloc(sizeof(struct amd_page_map), GFP_KERNEL);
112                 tables[i] = entry;
113                 if (entry == NULL) {
114                         retval = -ENOMEM;
115                         break;
116                 }
117                 retval = amd_create_page_map(entry);
118                 if (retval != 0)
119                         break;
120         }
121         amd_irongate_private.num_tables = i;
122         amd_irongate_private.gatt_pages = tables;
123 
124         if (retval != 0)
125                 amd_free_gatt_pages();
126 
127         return retval;
128 }
129 
130 /* Since we don't need contiguous memory we just try
131  * to get the gatt table once
132  */
133 
134 #define GET_PAGE_DIR_OFF(addr) (addr >> 22)
135 #define GET_PAGE_DIR_IDX(addr) (GET_PAGE_DIR_OFF(addr) - \
136         GET_PAGE_DIR_OFF(agp_bridge->gart_bus_addr))
137 #define GET_GATT_OFF(addr) ((addr & 0x003ff000) >> 12)
138 #define GET_GATT(addr) (amd_irongate_private.gatt_pages[\
139         GET_PAGE_DIR_IDX(addr)]->remapped)
140 
141 static int amd_create_gatt_table(struct agp_bridge_data *bridge)
142 {
143         struct aper_size_info_lvl2 *value;
144         struct amd_page_map page_dir;
145         unsigned long addr;
146         int retval;
147         u32 temp;
148         int i;
149 
150         value = A_SIZE_LVL2(agp_bridge->current_size);
151         retval = amd_create_page_map(&page_dir);
152         if (retval != 0)
153                 return retval;
154 
155         retval = amd_create_gatt_pages(value->num_entries / 1024);
156         if (retval != 0) {
157                 amd_free_page_map(&page_dir);
158                 return retval;
159         }
160 
161         agp_bridge->gatt_table_real = (u32 *)page_dir.real;
162         agp_bridge->gatt_table = (u32 __iomem *)page_dir.remapped;
163         agp_bridge->gatt_bus_addr = virt_to_gart(page_dir.real);
164 
165         /* Get the address for the gart region.
166          * This is a bus address even on the alpha, b/c its
167          * used to program the agp master not the cpu
168          */
169 
170         pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp);
171         addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
172         agp_bridge->gart_bus_addr = addr;
173 
174         /* Calculate the agp offset */
175         for (i = 0; i < value->num_entries / 1024; i++, addr += 0x00400000) {
176                 writel(virt_to_gart(amd_irongate_private.gatt_pages[i]->real) | 1,
177                         page_dir.remapped+GET_PAGE_DIR_OFF(addr));
178                 readl(page_dir.remapped+GET_PAGE_DIR_OFF(addr));        /* PCI Posting. */
179         }
180 
181         return 0;
182 }
183 
184 static int amd_free_gatt_table(struct agp_bridge_data *bridge)
185 {
186         struct amd_page_map page_dir;
187 
188         page_dir.real = (unsigned long *)agp_bridge->gatt_table_real;
189         page_dir.remapped = (unsigned long __iomem *)agp_bridge->gatt_table;
190 
191         amd_free_gatt_pages();
192         amd_free_page_map(&page_dir);
193         return 0;
194 }
195 
196 static int amd_irongate_fetch_size(void)
197 {
198         int i;
199         u32 temp;
200         struct aper_size_info_lvl2 *values;
201 
202         pci_read_config_dword(agp_bridge->dev, AMD_APSIZE, &temp);
203         temp = (temp & 0x0000000e);
204         values = A_SIZE_LVL2(agp_bridge->driver->aperture_sizes);
205         for (i = 0; i < agp_bridge->driver->num_aperture_sizes; i++) {
206                 if (temp == values[i].size_value) {
207                         agp_bridge->previous_size =
208                             agp_bridge->current_size = (void *) (values + i);
209 
210                         agp_bridge->aperture_size_idx = i;
211                         return values[i].size;
212                 }
213         }
214 
215         return 0;
216 }
217 
218 static int amd_irongate_configure(void)
219 {
220         struct aper_size_info_lvl2 *current_size;
221         u32 temp;
222         u16 enable_reg;
223 
224         current_size = A_SIZE_LVL2(agp_bridge->current_size);
225 
226         /* Get the memory mapped registers */
227         pci_read_config_dword(agp_bridge->dev, AMD_MMBASE, &temp);
228         temp = (temp & PCI_BASE_ADDRESS_MEM_MASK);
229         amd_irongate_private.registers = (volatile u8 __iomem *) ioremap(temp, 4096);
230         if (!amd_irongate_private.registers)
231                 return -ENOMEM;
232 
233         /* Write out the address of the gatt table */
234         writel(agp_bridge->gatt_bus_addr, amd_irongate_private.registers+AMD_ATTBASE);
235         readl(amd_irongate_private.registers+AMD_ATTBASE);      /* PCI Posting. */
236 
237         /* Write the Sync register */
238         pci_write_config_byte(agp_bridge->dev, AMD_MODECNTL, 0x80);
239 
240         /* Set indexing mode */
241         pci_write_config_byte(agp_bridge->dev, AMD_MODECNTL2, 0x00);
242 
243         /* Write the enable register */
244         enable_reg = readw(amd_irongate_private.registers+AMD_GARTENABLE);
245         enable_reg = (enable_reg | 0x0004);
246         writew(enable_reg, amd_irongate_private.registers+AMD_GARTENABLE);
247         readw(amd_irongate_private.registers+AMD_GARTENABLE);   /* PCI Posting. */
248 
249         /* Write out the size register */
250         pci_read_config_dword(agp_bridge->dev, AMD_APSIZE, &temp);
251         temp = (((temp & ~(0x0000000e)) | current_size->size_value) | 1);
252         pci_write_config_dword(agp_bridge->dev, AMD_APSIZE, temp);
253 
254         /* Flush the tlb */
255         writel(1, amd_irongate_private.registers+AMD_TLBFLUSH);
256         readl(amd_irongate_private.registers+AMD_TLBFLUSH);     /* PCI Posting.*/
257         return 0;
258 }
259 
260 static void amd_irongate_cleanup(void)
261 {
262         struct aper_size_info_lvl2 *previous_size;
263         u32 temp;
264         u16 enable_reg;
265 
266         previous_size = A_SIZE_LVL2(agp_bridge->previous_size);
267 
268         enable_reg = readw(amd_irongate_private.registers+AMD_GARTENABLE);
269         enable_reg = (enable_reg & ~(0x0004));
270         writew(enable_reg, amd_irongate_private.registers+AMD_GARTENABLE);
271         readw(amd_irongate_private.registers+AMD_GARTENABLE);   /* PCI Posting. */
272 
273         /* Write back the previous size and disable gart translation */
274         pci_read_config_dword(agp_bridge->dev, AMD_APSIZE, &temp);
275         temp = ((temp & ~(0x0000000f)) | previous_size->size_value);
276         pci_write_config_dword(agp_bridge->dev, AMD_APSIZE, temp);
277         iounmap((void __iomem *) amd_irongate_private.registers);
278 }
279 
280 /*
281  * This routine could be implemented by taking the addresses
282  * written to the GATT, and flushing them individually.  However
283  * currently it just flushes the whole table.  Which is probably
284  * more efficent, since agp_memory blocks can be a large number of
285  * entries.
286  */
287 
288 static void amd_irongate_tlbflush(struct agp_memory *temp)
289 {
290         writel(1, amd_irongate_private.registers+AMD_TLBFLUSH);
291         readl(amd_irongate_private.registers+AMD_TLBFLUSH);     /* PCI Posting. */
292 }
293 
294 static int amd_insert_memory(struct agp_memory *mem, off_t pg_start, int type)
295 {
296         int i, j, num_entries;
297         unsigned long __iomem *cur_gatt;
298         unsigned long addr;
299 
300         num_entries = A_SIZE_LVL2(agp_bridge->current_size)->num_entries;
301 
302         if (type != 0 || mem->type != 0)
303                 return -EINVAL;
304 
305         if ((pg_start + mem->page_count) > num_entries)
306                 return -EINVAL;
307 
308         j = pg_start;
309         while (j < (pg_start + mem->page_count)) {
310                 addr = (j * PAGE_SIZE) + agp_bridge->gart_bus_addr;
311                 cur_gatt = GET_GATT(addr);
312                 if (!PGE_EMPTY(agp_bridge, readl(cur_gatt+GET_GATT_OFF(addr))))
313                         return -EBUSY;
314                 j++;
315         }
316 
317         if (mem->is_flushed == FALSE) {
318                 global_cache_flush();
319                 mem->is_flushed = TRUE;
320         }
321 
322         for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
323                 addr = (j * PAGE_SIZE) + agp_bridge->gart_bus_addr;
324                 cur_gatt = GET_GATT(addr);
325                 writel(agp_generic_mask_memory(agp_bridge,
326                         mem->memory[i], mem->type), cur_gatt+GET_GATT_OFF(addr));
327                 readl(cur_gatt+GET_GATT_OFF(addr));     /* PCI Posting. */
328         }
329         amd_irongate_tlbflush(mem);
330         return 0;
331 }
332 
333 static int amd_remove_memory(struct agp_memory *mem, off_t pg_start, int type)
334 {
335         int i;
336         unsigned long __iomem *cur_gatt;
337         unsigned long addr;
338 
339         if (type != 0 || mem->type != 0)
340                 return -EINVAL;
341 
342         for (i = pg_start; i < (mem->page_count + pg_start); i++) {
343                 addr = (i * PAGE_SIZE) + agp_bridge->gart_bus_addr;
344                 cur_gatt = GET_GATT(addr);
345                 writel(agp_bridge->scratch_page, cur_gatt+GET_GATT_OFF(addr));
346                 readl(cur_gatt+GET_GATT_OFF(addr));     /* PCI Posting. */
347         }
348 
349         amd_irongate_tlbflush(mem);
350         return 0;
351 }
352 
353 static const struct aper_size_info_lvl2 amd_irongate_sizes[7] =
354 {
355         {2048, 524288, 0x0000000c},
356         {1024, 262144, 0x0000000a},
357         {512, 131072, 0x00000008},
358         {256, 65536, 0x00000006},
359         {128, 32768, 0x00000004},
360         {64, 16384, 0x00000002},
361         {32, 8192, 0x00000000}
362 };
363 
364 static const struct gatt_mask amd_irongate_masks[] =
365 {
366         {.mask = 1, .type = 0}
367 };
368 
369 static const struct agp_bridge_driver amd_irongate_driver = {
370         .owner                  = THIS_MODULE,
371         .aperture_sizes         = amd_irongate_sizes,
372         .size_type              = LVL2_APER_SIZE,
373         .num_aperture_sizes     = 7,
374         .configure              = amd_irongate_configure,
375         .fetch_size             = amd_irongate_fetch_size,
376         .cleanup                = amd_irongate_cleanup,
377         .tlb_flush              = amd_irongate_tlbflush,
378         .mask_memory            = agp_generic_mask_memory,
379         .masks                  = amd_irongate_masks,
380         .agp_enable             = agp_generic_enable,
381         .cache_flush            = global_cache_flush,
382         .create_gatt_table      = amd_create_gatt_table,
383         .free_gatt_table        = amd_free_gatt_table,
384         .insert_memory          = amd_insert_memory,
385         .remove_memory          = amd_remove_memory,
386         .alloc_by_type          = agp_generic_alloc_by_type,
387         .free_by_type           = agp_generic_free_by_type,
388         .agp_alloc_page         = agp_generic_alloc_page,
389         .agp_destroy_page       = agp_generic_destroy_page,
390         .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
391 };
392 
393 static struct agp_device_ids amd_agp_device_ids[] __devinitdata =
394 {
395         {
396                 .device_id      = PCI_DEVICE_ID_AMD_FE_GATE_7006,
397                 .chipset_name   = "Irongate",
398         },
399         {
400                 .device_id      = PCI_DEVICE_ID_AMD_FE_GATE_700E,
401                 .chipset_name   = "761",
402         },
403         {
404                 .device_id      = PCI_DEVICE_ID_AMD_FE_GATE_700C,
405                 .chipset_name   = "760MP",
406         },
407         { }, /* dummy final entry, always present */
408 };
409 
410 static int __devinit agp_amdk7_probe(struct pci_dev *pdev,
411                                      const struct pci_device_id *ent)
412 {
413         struct agp_bridge_data *bridge;
414         u8 cap_ptr;
415         int j;
416 
417         cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP);
418         if (!cap_ptr)
419                 return -ENODEV;
420 
421         j = ent - agp_amdk7_pci_table;
422         printk(KERN_INFO PFX "Detected AMD %s chipset\n",
423                amd_agp_device_ids[j].chipset_name);
424 
425         bridge = agp_alloc_bridge();
426         if (!bridge)
427                 return -ENOMEM;
428 
429         bridge->driver = &amd_irongate_driver;
430         bridge->dev_private_data = &amd_irongate_private,
431         bridge->dev = pdev;
432         bridge->capndx = cap_ptr;
433 
434         /* 751 Errata (22564_B-1.PDF)
435            erratum 20: strobe glitch with Nvidia NV10 GeForce cards.
436            system controller may experience noise due to strong drive strengths
437          */
438         if (agp_bridge->dev->device == PCI_DEVICE_ID_AMD_FE_GATE_7006) {
439                 u8 cap_ptr=0;
440                 struct pci_dev *gfxcard=NULL;
441                 while (!cap_ptr) {
442                         gfxcard = pci_get_class(PCI_CLASS_DISPLAY_VGA<<8, gfxcard);
443                         if (!gfxcard) {
444                                 printk (KERN_INFO PFX "Couldn't find an AGP VGA controller.\n");
445                                 return -ENODEV;
446                         }
447                         cap_ptr = pci_find_capability(gfxcard, PCI_CAP_ID_AGP);
448                 }
449 
450                 /* With so many variants of NVidia cards, it's simpler just
451                    to blacklist them all, and then whitelist them as needed
452                    (if necessary at all). */
453                 if (gfxcard->vendor == PCI_VENDOR_ID_NVIDIA) {
454                         agp_bridge->flags |= AGP_ERRATA_1X;
455                         printk (KERN_INFO PFX "AMD 751 chipset with NVidia GeForce detected. Forcing to 1X due to errata.\n");
456                 }
457                 pci_dev_put(gfxcard);
458         }
459 
460         /* 761 Errata (23613_F.pdf)
461          * Revisions B0/B1 were a disaster.
462          * erratum 44: SYSCLK/AGPCLK skew causes 2X failures -- Force mode to 1X
463          * erratum 45: Timing problem prevents fast writes -- Disable fast write.
464          * erratum 46: Setup violation on AGP SBA pins - Disable side band addressing.
465          * With this lot disabled, we should prevent lockups. */
466         if (agp_bridge->dev->device == PCI_DEVICE_ID_AMD_FE_GATE_700E) {
467                 if (pdev->revision == 0x10 || pdev->revision == 0x11) {
468                         agp_bridge->flags = AGP_ERRATA_FASTWRITES;
469                         agp_bridge->flags |= AGP_ERRATA_SBA;
470                         agp_bridge->flags |= AGP_ERRATA_1X;
471                         printk (KERN_INFO PFX "AMD 761 chipset with errata detected - disabling AGP fast writes & SBA and forcing to 1X.\n");
472                 }
473         }
474 
475         /* Fill in the mode register */
476         pci_read_config_dword(pdev,
477                         bridge->capndx+PCI_AGP_STATUS,
478                         &bridge->mode);
479 
480         pci_set_drvdata(pdev, bridge);
481         return agp_add_bridge(bridge);
482 }
483 
484 static void __devexit agp_amdk7_remove(struct pci_dev *pdev)
485 {
486         struct agp_bridge_data *bridge = pci_get_drvdata(pdev);
487 
488         agp_remove_bridge(bridge);
489         agp_put_bridge(bridge);
490 }
491 
492 /* must be the same order as name table above */
493 static struct pci_device_id agp_amdk7_pci_table[] = {
494         {
495         .class          = (PCI_CLASS_BRIDGE_HOST << 8),
496         .class_mask     = ~0,
497         .vendor         = PCI_VENDOR_ID_AMD,
498         .device         = PCI_DEVICE_ID_AMD_FE_GATE_7006,
499         .subvendor      = PCI_ANY_ID,
500         .subdevice      = PCI_ANY_ID,
501         },
502         {
503         .class          = (PCI_CLASS_BRIDGE_HOST << 8),
504         .class_mask     = ~0,
505         .vendor         = PCI_VENDOR_ID_AMD,
506         .device         = PCI_DEVICE_ID_AMD_FE_GATE_700E,
507         .subvendor      = PCI_ANY_ID,
508         .subdevice      = PCI_ANY_ID,
509         },
510         {
511         .class          = (PCI_CLASS_BRIDGE_HOST << 8),
512         .class_mask     = ~0,
513         .vendor         = PCI_VENDOR_ID_AMD,
514         .device         = PCI_DEVICE_ID_AMD_FE_GATE_700C,
515         .subvendor      = PCI_ANY_ID,
516         .subdevice      = PCI_ANY_ID,
517         },
518         { }
519 };
520 
521 MODULE_DEVICE_TABLE(pci, agp_amdk7_pci_table);
522 
523 static struct pci_driver agp_amdk7_pci_driver = {
524         .name           = "agpgart-amdk7",
525         .id_table       = agp_amdk7_pci_table,
526         .probe          = agp_amdk7_probe,
527         .remove         = agp_amdk7_remove,
528 };
529 
530 static int __init agp_amdk7_init(void)
531 {
532         if (agp_off)
533                 return -EINVAL;
534         return pci_register_driver(&agp_amdk7_pci_driver);
535 }
536 
537 static void __exit agp_amdk7_cleanup(void)
538 {
539         pci_unregister_driver(&agp_amdk7_pci_driver);
540 }
541 
542 module_init(agp_amdk7_init);
543 module_exit(agp_amdk7_cleanup);
544 
545 MODULE_LICENSE("GPL and additional rights");
546 
  This page was automatically generated by the LXR engine.