📄 i460-agp.c
字号:
WR_FLUSH_GATT(j - 1); return 0;}static int i460_remove_memory_small_io_page(struct agp_memory *mem, off_t pg_start, int type){ int i; pr_debug("i460_remove_memory_small_io_page(mem=%p, pg_start=%ld, type=%d)\n", mem, pg_start, type); pg_start = I460_IOPAGES_PER_KPAGE * pg_start; for (i = pg_start; i < (pg_start + I460_IOPAGES_PER_KPAGE * mem->page_count); i++) WR_GATT(i, 0); WR_FLUSH_GATT(i - 1); return 0;}#if I460_LARGE_IO_PAGES/* * These functions are called when the I/O (GART) page size exceeds PAGE_SIZE. * * This situation is interesting since AGP memory allocations that are smaller than a * single GART page are possible. The i460.lp_desc array tracks partial allocation of the * large GART pages to work around this issue. * * i460.lp_desc[pg_num].refcount tracks the number of kernel pages in use within GART page * pg_num. i460.lp_desc[pg_num].paddr is the physical address of the large page and * i460.lp_desc[pg_num].alloced_map is a bitmap of kernel pages that are in use (allocated). */static int i460_alloc_large_page (struct lp_desc *lp){ unsigned long order = I460_IO_PAGE_SHIFT - PAGE_SHIFT; size_t map_size; void *lpage; lpage = (void *) __get_free_pages(GFP_KERNEL, order); if (!lpage) { printk(KERN_ERR PFX "Couldn't alloc 4M GART page...\n"); return -ENOMEM; } map_size = ((I460_KPAGES_PER_IOPAGE + BITS_PER_LONG - 1) & -BITS_PER_LONG)/8; lp->alloced_map = kmalloc(map_size, GFP_KERNEL); if (!lp->alloced_map) { free_pages((unsigned long) lpage, order); printk(KERN_ERR PFX "Out of memory, we're in trouble...\n"); return -ENOMEM; } memset(lp->alloced_map, 0, map_size); lp->paddr = virt_to_phys(lpage); lp->refcount = 0; atomic_add(I460_KPAGES_PER_IOPAGE, &agp_bridge->current_memory_agp); return 0;}static void i460_free_large_page (struct lp_desc *lp){ kfree(lp->alloced_map); lp->alloced_map = NULL; free_pages((unsigned long) phys_to_virt(lp->paddr), I460_IO_PAGE_SHIFT - PAGE_SHIFT); atomic_sub(I460_KPAGES_PER_IOPAGE, &agp_bridge->current_memory_agp);}static int i460_insert_memory_large_io_page (struct agp_memory *mem, off_t pg_start, int type){ int i, start_offset, end_offset, idx, pg, num_entries; struct lp_desc *start, *end, *lp; void *temp; temp = agp_bridge->current_size; num_entries = A_SIZE_8(temp)->num_entries; /* Figure out what pg_start means in terms of our large GART pages */ start = &i460.lp_desc[pg_start / I460_KPAGES_PER_IOPAGE]; end = &i460.lp_desc[(pg_start + mem->page_count - 1) / I460_KPAGES_PER_IOPAGE]; start_offset = pg_start % I460_KPAGES_PER_IOPAGE; end_offset = (pg_start + mem->page_count - 1) % I460_KPAGES_PER_IOPAGE; if (end > i460.lp_desc + num_entries) { printk(KERN_ERR PFX "Looks like we're out of AGP memory\n"); return -EINVAL; } /* Check if the requested region of the aperture is free */ for (lp = start; lp <= end; ++lp) { if (!lp->alloced_map) continue; /* OK, the entire large page is available... */ for (idx = ((lp == start) ? start_offset : 0); idx < ((lp == end) ? (end_offset + 1) : I460_KPAGES_PER_IOPAGE); idx++) { if (test_bit(idx, lp->alloced_map)) return -EBUSY; } } for (lp = start, i = 0; lp <= end; ++lp) { if (!lp->alloced_map) { /* Allocate new GART pages... */ if (i460_alloc_large_page(lp) < 0) return -ENOMEM; pg = lp - i460.lp_desc; WR_GATT(pg, agp_bridge->driver->mask_memory(lp->paddr, 0)); WR_FLUSH_GATT(pg); } for (idx = ((lp == start) ? start_offset : 0); idx < ((lp == end) ? (end_offset + 1) : I460_KPAGES_PER_IOPAGE); idx++, i++) { mem->memory[i] = lp->paddr + idx*PAGE_SIZE; __set_bit(idx, lp->alloced_map); ++lp->refcount; } } return 0;}static int i460_remove_memory_large_io_page (struct agp_memory *mem, off_t pg_start, int type){ int i, pg, start_offset, end_offset, idx, num_entries; struct lp_desc *start, *end, *lp; void *temp; temp = agp_bridge->driver->current_size; num_entries = A_SIZE_8(temp)->num_entries; /* Figure out what pg_start means in terms of our large GART pages */ start = &i460.lp_desc[pg_start / I460_KPAGES_PER_IOPAGE]; end = &i460.lp_desc[(pg_start + mem->page_count - 1) / I460_KPAGES_PER_IOPAGE]; start_offset = pg_start % I460_KPAGES_PER_IOPAGE; end_offset = (pg_start + mem->page_count - 1) % I460_KPAGES_PER_IOPAGE; for (i = 0, lp = start; lp <= end; ++lp) { for (idx = ((lp == start) ? start_offset : 0); idx < ((lp == end) ? (end_offset + 1) : I460_KPAGES_PER_IOPAGE); idx++, i++) { mem->memory[i] = 0; __clear_bit(idx, lp->alloced_map); --lp->refcount; } /* Free GART pages if they are unused */ if (lp->refcount == 0) { pg = lp - i460.lp_desc; WR_GATT(pg, 0); WR_FLUSH_GATT(pg); i460_free_large_page(lp); } } return 0;}/* Wrapper routines to call the approriate {small_io_page,large_io_page} function */static int i460_insert_memory (struct agp_memory *mem, off_t pg_start, int type){ if (I460_IO_PAGE_SHIFT <= PAGE_SHIFT) return i460_insert_memory_small_io_page(mem, pg_start, type); else return i460_insert_memory_large_io_page(mem, pg_start, type);}static int i460_remove_memory (struct agp_memory *mem, off_t pg_start, int type){ if (I460_IO_PAGE_SHIFT <= PAGE_SHIFT) return i460_remove_memory_small_io_page(mem, pg_start, type); else return i460_remove_memory_large_io_page(mem, pg_start, type);}/* * If the I/O (GART) page size is bigger than the kernel page size, we don't want to * allocate memory until we know where it is to be bound in the aperture (a * multi-kernel-page alloc might fit inside of an already allocated GART page). * * Let's just hope nobody counts on the allocated AGP memory being there before bind time * (I don't think current drivers do)... */static void *i460_alloc_page (void){ void *page; if (I460_IO_PAGE_SHIFT <= PAGE_SHIFT) page = agp_generic_alloc_page(); else /* Returning NULL would cause problems */ /* AK: really dubious code. */ page = (void *)~0UL; return page;}static void i460_destroy_page (void *page){ if (I460_IO_PAGE_SHIFT <= PAGE_SHIFT) agp_generic_destroy_page(page);}#endif /* I460_LARGE_IO_PAGES */static unsigned long i460_mask_memory (unsigned long addr, int type){ /* Make sure the returned address is a valid GATT entry */ return (agp_bridge->driver->masks[0].mask | (((addr & ~((1 << I460_IO_PAGE_SHIFT) - 1)) & 0xffffff000) >> 12));}struct agp_bridge_driver intel_i460_driver = { .owner = THIS_MODULE, .aperture_sizes = i460_sizes, .size_type = U8_APER_SIZE, .num_aperture_sizes = 3, .configure = i460_configure, .fetch_size = i460_fetch_size, .cleanup = i460_cleanup, .tlb_flush = i460_tlb_flush, .mask_memory = i460_mask_memory, .masks = i460_masks, .agp_enable = agp_generic_enable, .cache_flush = global_cache_flush, .create_gatt_table = i460_create_gatt_table, .free_gatt_table = i460_free_gatt_table,#if I460_LARGE_IO_PAGES .insert_memory = i460_insert_memory, .remove_memory = i460_remove_memory, .agp_alloc_page = i460_alloc_page, .agp_destroy_page = i460_destroy_page,#else .insert_memory = i460_insert_memory_small_io_page, .remove_memory = i460_remove_memory_small_io_page, .agp_alloc_page = agp_generic_alloc_page, .agp_destroy_page = agp_generic_destroy_page,#endif .alloc_by_type = agp_generic_alloc_by_type, .free_by_type = agp_generic_free_by_type, .cant_use_aperture = 1,};static int __devinit agp_intel_i460_probe(struct pci_dev *pdev, const struct pci_device_id *ent){ struct agp_bridge_data *bridge; u8 cap_ptr; cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP); if (!cap_ptr) return -ENODEV; bridge = agp_alloc_bridge(); if (!bridge) return -ENOMEM; bridge->driver = &intel_i460_driver; bridge->dev = pdev; bridge->capndx = cap_ptr; pci_set_drvdata(pdev, bridge); return agp_add_bridge(bridge);}static void __devexit agp_intel_i460_remove(struct pci_dev *pdev){ struct agp_bridge_data *bridge = pci_get_drvdata(pdev); agp_remove_bridge(bridge); agp_put_bridge(bridge);}static struct pci_device_id agp_intel_i460_pci_table[] = { { .class = (PCI_CLASS_BRIDGE_HOST << 8), .class_mask = ~0, .vendor = PCI_VENDOR_ID_INTEL, .device = PCI_DEVICE_ID_INTEL_84460GX, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, }, { }};MODULE_DEVICE_TABLE(pci, agp_intel_i460_pci_table);static struct pci_driver agp_intel_i460_pci_driver = { .name = "agpgart-intel-i460", .id_table = agp_intel_i460_pci_table, .probe = agp_intel_i460_probe, .remove = __devexit_p(agp_intel_i460_remove),};static int __init agp_intel_i460_init(void){ return pci_module_init(&agp_intel_i460_pci_driver);}static void __exit agp_intel_i460_cleanup(void){ pci_unregister_driver(&agp_intel_i460_pci_driver);}module_init(agp_intel_i460_init);module_exit(agp_intel_i460_cleanup);MODULE_AUTHOR("Chris Ahna <Christopher.J.Ahna@intel.com>");MODULE_LICENSE("GPL and additional rights");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -