📄 intel-agp.c
字号:
/* * Intel AGPGART routines. *//* * Intel(R) 855GM/852GM and 865G support added by David Dawes * <dawes@tungstengraphics.com>. * * Intel(R) 915G/915GM support added by Alan Hourihane * <alanh@tungstengraphics.com>. */#include <linux/module.h>#include <linux/pci.h>#include <linux/init.h>#include <linux/pagemap.h>#include <linux/agp_backend.h>#include "agp.h"/* Intel 815 register */#define INTEL_815_APCONT 0x51#define INTEL_815_ATTBASE_MASK ~0x1FFFFFFF/* Intel i820 registers */#define INTEL_I820_RDCR 0x51#define INTEL_I820_ERRSTS 0xc8/* Intel i840 registers */#define INTEL_I840_MCHCFG 0x50#define INTEL_I840_ERRSTS 0xc8/* Intel i850 registers */#define INTEL_I850_MCHCFG 0x50#define INTEL_I850_ERRSTS 0xc8/* intel 915G registers */#define I915_GMADDR 0x18#define I915_MMADDR 0x10#define I915_PTEADDR 0x1C#define I915_GMCH_GMS_STOLEN_48M (0x6 << 4)#define I915_GMCH_GMS_STOLEN_64M (0x7 << 4)/* Intel 7505 registers */#define INTEL_I7505_APSIZE 0x74#define INTEL_I7505_NCAPID 0x60#define INTEL_I7505_NISTAT 0x6c#define INTEL_I7505_ATTBASE 0x78#define INTEL_I7505_ERRSTS 0x42#define INTEL_I7505_AGPCTRL 0x70#define INTEL_I7505_MCHCFG 0x50static struct aper_size_info_fixed intel_i810_sizes[] ={ {64, 16384, 4}, /* The 32M mode still requires a 64k gatt */ {32, 8192, 4}};#define AGP_DCACHE_MEMORY 1#define AGP_PHYS_MEMORY 2static struct gatt_mask intel_i810_masks[] ={ {.mask = I810_PTE_VALID, .type = 0}, {.mask = (I810_PTE_VALID | I810_PTE_LOCAL), .type = AGP_DCACHE_MEMORY}, {.mask = I810_PTE_VALID, .type = 0}};static struct _intel_i810_private { struct pci_dev *i810_dev; /* device one */ volatile u8 __iomem *registers; int num_dcache_entries;} intel_i810_private;static int intel_i810_fetch_size(void){ u32 smram_miscc; struct aper_size_info_fixed *values; pci_read_config_dword(agp_bridge->dev, I810_SMRAM_MISCC, &smram_miscc); values = A_SIZE_FIX(agp_bridge->driver->aperture_sizes); if ((smram_miscc & I810_GMS) == I810_GMS_DISABLE) { printk(KERN_WARNING PFX "i810 is disabled\n"); return 0; } if ((smram_miscc & I810_GFX_MEM_WIN_SIZE) == I810_GFX_MEM_WIN_32M) { agp_bridge->previous_size = agp_bridge->current_size = (void *) (values + 1); agp_bridge->aperture_size_idx = 1; return values[1].size; } else { agp_bridge->previous_size = agp_bridge->current_size = (void *) (values); agp_bridge->aperture_size_idx = 0; return values[0].size; } return 0;}static int intel_i810_configure(void){ struct aper_size_info_fixed *current_size; u32 temp; int i; current_size = A_SIZE_FIX(agp_bridge->current_size); pci_read_config_dword(intel_i810_private.i810_dev, I810_MMADDR, &temp); temp &= 0xfff80000; intel_i810_private.registers = ioremap(temp, 128 * 4096); if (!intel_i810_private.registers) { printk(KERN_ERR PFX "Unable to remap memory.\n"); return -ENOMEM; } if ((readl(intel_i810_private.registers+I810_DRAM_CTL) & I810_DRAM_ROW_0) == I810_DRAM_ROW_0_SDRAM) { /* This will need to be dynamically assigned */ printk(KERN_INFO PFX "detected 4MB dedicated video ram.\n"); intel_i810_private.num_dcache_entries = 1024; } pci_read_config_dword(intel_i810_private.i810_dev, I810_GMADDR, &temp); agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); writel(agp_bridge->gatt_bus_addr | I810_PGETBL_ENABLED, intel_i810_private.registers+I810_PGETBL_CTL); readl(intel_i810_private.registers+I810_PGETBL_CTL); /* PCI Posting. */ if (agp_bridge->driver->needs_scratch_page) { for (i = 0; i < current_size->num_entries; i++) { writel(agp_bridge->scratch_page, intel_i810_private.registers+I810_PTE_BASE+(i*4)); readl(intel_i810_private.registers+I810_PTE_BASE+(i*4)); /* PCI posting. */ } } global_cache_flush(); return 0;}static void intel_i810_cleanup(void){ writel(0, intel_i810_private.registers+I810_PGETBL_CTL); readl(intel_i810_private.registers); /* PCI Posting. */ iounmap(intel_i810_private.registers);}static void intel_i810_tlbflush(struct agp_memory *mem){ return;}static void intel_i810_agp_enable(struct agp_bridge_data *bridge, u32 mode){ return;}/* Exists to support ARGB cursors */static void *i8xx_alloc_pages(void){ struct page * page; page = alloc_pages(GFP_KERNEL, 2); if (page == NULL) return NULL; if (change_page_attr(page, 4, PAGE_KERNEL_NOCACHE) < 0) { global_flush_tlb(); __free_page(page); return NULL; } global_flush_tlb(); get_page(page); SetPageLocked(page); atomic_inc(&agp_bridge->current_memory_agp); return page_address(page);}static void i8xx_destroy_pages(void *addr){ struct page *page; if (addr == NULL) return; page = virt_to_page(addr); change_page_attr(page, 4, PAGE_KERNEL); global_flush_tlb(); put_page(page); unlock_page(page); free_pages((unsigned long)addr, 2); atomic_dec(&agp_bridge->current_memory_agp);}static int intel_i810_insert_entries(struct agp_memory *mem, off_t pg_start, int type){ int i, j, num_entries; void *temp; temp = agp_bridge->current_size; num_entries = A_SIZE_FIX(temp)->num_entries; if ((pg_start + mem->page_count) > num_entries) { return -EINVAL; } for (j = pg_start; j < (pg_start + mem->page_count); j++) { if (!PGE_EMPTY(agp_bridge, readl(agp_bridge->gatt_table+j))) return -EBUSY; } if (type != 0 || mem->type != 0) { if ((type == AGP_DCACHE_MEMORY) && (mem->type == AGP_DCACHE_MEMORY)) { /* special insert */ global_cache_flush(); for (i = pg_start; i < (pg_start + mem->page_count); i++) { writel((i*4096)|I810_PTE_LOCAL|I810_PTE_VALID, intel_i810_private.registers+I810_PTE_BASE+(i*4)); readl(intel_i810_private.registers+I810_PTE_BASE+(i*4)); /* PCI Posting. */ } global_cache_flush(); agp_bridge->driver->tlb_flush(mem); return 0; } if((type == AGP_PHYS_MEMORY) && (mem->type == AGP_PHYS_MEMORY)) goto insert; return -EINVAL; }insert: global_cache_flush(); for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { writel(agp_bridge->driver->mask_memory(agp_bridge, mem->memory[i], mem->type), intel_i810_private.registers+I810_PTE_BASE+(j*4)); readl(intel_i810_private.registers+I810_PTE_BASE+(j*4)); /* PCI Posting. */ } global_cache_flush(); agp_bridge->driver->tlb_flush(mem); return 0;}static int intel_i810_remove_entries(struct agp_memory *mem, off_t pg_start, int type){ int i; for (i = pg_start; i < (mem->page_count + pg_start); i++) { writel(agp_bridge->scratch_page, intel_i810_private.registers+I810_PTE_BASE+(i*4)); readl(intel_i810_private.registers+I810_PTE_BASE+(i*4)); /* PCI Posting. */ } global_cache_flush(); agp_bridge->driver->tlb_flush(mem); return 0;}/* * The i810/i830 requires a physical address to program its mouse * pointer into hardware. * However the Xserver still writes to it through the agp aperture. */static struct agp_memory *alloc_agpphysmem_i8xx(size_t pg_count, int type){ struct agp_memory *new; void *addr; if (pg_count != 1 && pg_count != 4) return NULL; switch (pg_count) { case 1: addr = agp_bridge->driver->agp_alloc_page(agp_bridge); global_flush_tlb(); break; case 4: /* kludge to get 4 physical pages for ARGB cursor */ addr = i8xx_alloc_pages(); break; default: return NULL; } if (addr == NULL) return NULL; new = agp_create_memory(pg_count); if (new == NULL) return NULL; new->memory[0] = virt_to_gart(addr); if (pg_count == 4) { /* kludge to get 4 physical pages for ARGB cursor */ new->memory[1] = new->memory[0] + PAGE_SIZE; new->memory[2] = new->memory[1] + PAGE_SIZE; new->memory[3] = new->memory[2] + PAGE_SIZE; } new->page_count = pg_count; new->num_scratch_pages = pg_count; new->type = AGP_PHYS_MEMORY; new->physical = new->memory[0]; return new;}static struct agp_memory *intel_i810_alloc_by_type(size_t pg_count, int type){ struct agp_memory *new; if (type == AGP_DCACHE_MEMORY) { if (pg_count != intel_i810_private.num_dcache_entries) return NULL; new = agp_create_memory(1); if (new == NULL) return NULL; new->type = AGP_DCACHE_MEMORY; new->page_count = pg_count; new->num_scratch_pages = 0; vfree(new->memory); return new; } if (type == AGP_PHYS_MEMORY) return alloc_agpphysmem_i8xx(pg_count, type); return NULL;}static void intel_i810_free_by_type(struct agp_memory *curr){ agp_free_key(curr->key); if(curr->type == AGP_PHYS_MEMORY) { if (curr->page_count == 4) i8xx_destroy_pages(gart_to_virt(curr->memory[0])); else { agp_bridge->driver->agp_destroy_page( gart_to_virt(curr->memory[0])); global_flush_tlb(); } vfree(curr->memory); } kfree(curr);}static unsigned long intel_i810_mask_memory(struct agp_bridge_data *bridge, unsigned long addr, int type){ /* Type checking must be done elsewhere */ return addr | bridge->driver->masks[type].mask;}static struct aper_size_info_fixed intel_i830_sizes[] ={ {128, 32768, 5}, /* The 64M mode still requires a 128k gatt */ {64, 16384, 5}, {256, 65536, 6},};static struct _intel_i830_private { struct pci_dev *i830_dev; /* device one */ volatile u8 __iomem *registers; volatile u32 __iomem *gtt; /* I915G */ int gtt_entries;} intel_i830_private;static void intel_i830_init_gtt_entries(void){ u16 gmch_ctrl; int gtt_entries; u8 rdct; int local = 0; static const int ddt[4] = { 0, 16, 32, 64 }; int size; pci_read_config_word(agp_bridge->dev,I830_GMCH_CTRL,&gmch_ctrl); /* We obtain the size of the GTT, which is also stored (for some * reason) at the top of stolen memory. Then we add 4KB to that * for the video BIOS popup, which is also stored in there. */ size = agp_bridge->driver->fetch_size() + 4; if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82830_HB || agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82845G_HB) { switch (gmch_ctrl & I830_GMCH_GMS_MASK) { case I830_GMCH_GMS_STOLEN_512: gtt_entries = KB(512) - KB(size); break; case I830_GMCH_GMS_STOLEN_1024: gtt_entries = MB(1) - KB(size); break; case I830_GMCH_GMS_STOLEN_8192: gtt_entries = MB(8) - KB(size); break; case I830_GMCH_GMS_LOCAL: rdct = readb(intel_i830_private.registers+I830_RDRAM_CHANNEL_TYPE); gtt_entries = (I830_RDRAM_ND(rdct) + 1) * MB(ddt[I830_RDRAM_DDT(rdct)]); local = 1; break; default: gtt_entries = 0; break; } } else { switch (gmch_ctrl & I830_GMCH_GMS_MASK) { case I855_GMCH_GMS_STOLEN_1M: gtt_entries = MB(1) - KB(size); break; case I855_GMCH_GMS_STOLEN_4M: gtt_entries = MB(4) - KB(size); break; case I855_GMCH_GMS_STOLEN_8M: gtt_entries = MB(8) - KB(size); break; case I855_GMCH_GMS_STOLEN_16M: gtt_entries = MB(16) - KB(size); break; case I855_GMCH_GMS_STOLEN_32M: gtt_entries = MB(32) - KB(size); break; case I915_GMCH_GMS_STOLEN_48M: /* Check it's really I915G */ if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915G_HB || agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB || agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945G_HB) gtt_entries = MB(48) - KB(size); else gtt_entries = 0; break; case I915_GMCH_GMS_STOLEN_64M: /* Check it's really I915G */ if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915G_HB || agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB || agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945G_HB) gtt_entries = MB(64) - KB(size); else gtt_entries = 0; default: gtt_entries = 0; break; } } if (gtt_entries > 0) printk(KERN_INFO PFX "Detected %dK %s memory.\n", gtt_entries / KB(1), local ? "local" : "stolen"); else printk(KERN_INFO PFX "No pre-allocated video memory detected.\n"); gtt_entries /= KB(4); intel_i830_private.gtt_entries = gtt_entries;}/* The intel i830 automatically initializes the agp aperture during POST. * Use the memory already set aside for in the GTT. */static int intel_i830_create_gatt_table(struct agp_bridge_data *bridge){ int page_order; struct aper_size_info_fixed *size; int num_entries; u32 temp; size = agp_bridge->current_size;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -