X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fchar%2Fagp%2Fintel-agp.c;h=ed1d380905c71c8dd2db6835ab0a92ec0555dce7;hb=refs%2Fheads%2Fvserver;hp=f8b991673465686f73c53043de0137cc053c32a4;hpb=9213980e6a70d8473e0ffd4b39ab5b6caaba9ff5;p=linux-2.6.git diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c index f8b991673..ed1d38090 100644 --- a/drivers/char/agp/intel-agp.c +++ b/drivers/char/agp/intel-agp.c @@ -2,17 +2,28 @@ * Intel AGPGART routines. */ -/* - * Intel(R) 855GM/852GM and 865G support added by David Dawes - * . - */ - #include #include #include +#include #include #include "agp.h" +#define PCI_DEVICE_ID_INTEL_82946GZ_HB 0x2970 +#define PCI_DEVICE_ID_INTEL_82946GZ_IG 0x2972 +#define PCI_DEVICE_ID_INTEL_82965G_1_HB 0x2980 +#define PCI_DEVICE_ID_INTEL_82965G_1_IG 0x2982 +#define PCI_DEVICE_ID_INTEL_82965Q_HB 0x2990 +#define PCI_DEVICE_ID_INTEL_82965Q_IG 0x2992 +#define PCI_DEVICE_ID_INTEL_82965G_HB 0x29A0 +#define PCI_DEVICE_ID_INTEL_82965G_IG 0x29A2 + +#define IS_I965 (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82946GZ_HB || \ + agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965G_1_HB || \ + agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965Q_HB || \ + agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965G_HB) + + /* Intel 815 register */ #define INTEL_815_APCONT 0x51 #define INTEL_815_ATTBASE_MASK ~0x1FFFFFFF @@ -29,6 +40,16 @@ #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 965G registers */ +#define I965_MSAC 0x62 + /* Intel 7505 registers */ #define INTEL_I7505_APSIZE 0x74 #define INTEL_I7505_NCAPID 0x60 @@ -57,7 +78,7 @@ static struct gatt_mask intel_i810_masks[] = static struct _intel_i810_private { struct pci_dev *i810_dev; /* device one */ - volatile u8 *registers; + volatile u8 __iomem *registers; int num_dcache_entries; } intel_i810_private; @@ -96,16 +117,18 @@ static int intel_i810_configure(void) 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 = (volatile u8 *) ioremap(temp, 128 * 4096); if (!intel_i810_private.registers) { - printk(KERN_ERR PFX "Unable to remap memory.\n"); - return -ENOMEM; + 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 ((INREG32(intel_i810_private.registers, I810_DRAM_CTL) + 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"); @@ -113,24 +136,24 @@ static int intel_i810_configure(void) } pci_read_config_dword(intel_i810_private.i810_dev, I810_GMADDR, &temp); agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); - OUTREG32(intel_i810_private.registers, I810_PGETBL_CTL, - agp_bridge->gatt_bus_addr | I810_PGETBL_ENABLED); - global_cache_flush(); + 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++) { - OUTREG32(intel_i810_private.registers, - I810_PTE_BASE + (i * 4), - agp_bridge->scratch_page); + 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) { - OUTREG32(intel_i810_private.registers, I810_PGETBL_CTL, 0); - iounmap((void *) intel_i810_private.registers); + 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) @@ -138,55 +161,101 @@ static void intel_i810_tlbflush(struct agp_memory *mem) return; } -static void intel_i810_agp_enable(u32 mode) +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 | GFP_DMA32, 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; + if (mem->page_count == 0) + return 0; + temp = agp_bridge->current_size; num_entries = A_SIZE_FIX(temp)->num_entries; - if ((pg_start + mem->page_count) > 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, agp_bridge->gatt_table[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(); + if (!mem->is_flushed) { + global_cache_flush(); + mem->is_flushed = TRUE; + } + for (i = pg_start; i < (pg_start + mem->page_count); i++) { - OUTREG32(intel_i810_private.registers, - I810_PTE_BASE + (i * 4), - (i * 4096) | I810_PTE_LOCAL | - I810_PTE_VALID); + writel((i*4096)|I810_PTE_LOCAL|I810_PTE_VALID, intel_i810_private.registers+I810_PTE_BASE+(i*4)); } - global_cache_flush(); + readl(intel_i810_private.registers+I810_PTE_BASE+((i-1)*4)); /* PCI Posting. */ + agp_bridge->driver->tlb_flush(mem); return 0; } - if((type == AGP_PHYS_MEMORY) && (mem->type == AGP_PHYS_MEMORY)) + if ((type == AGP_PHYS_MEMORY) && (mem->type == AGP_PHYS_MEMORY)) goto insert; return -EINVAL; } insert: - global_cache_flush(); + if (!mem->is_flushed) { + global_cache_flush(); + mem->is_flushed = TRUE; + } + for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { - OUTREG32(intel_i810_private.registers, - I810_PTE_BASE + (j * 4), - agp_bridge->driver->mask_memory(mem->memory[i], mem->type)); + writel(agp_bridge->driver->mask_memory(agp_bridge, + mem->memory[i], mem->type), + intel_i810_private.registers+I810_PTE_BASE+(j*4)); } - global_cache_flush(); + readl(intel_i810_private.registers+I810_PTE_BASE+((j-1)*4)); /* PCI Posting. */ agp_bridge->driver->tlb_flush(mem); return 0; @@ -197,13 +266,14 @@ static int intel_i810_remove_entries(struct agp_memory *mem, off_t pg_start, { int i; + if (mem->page_count == 0) + return 0; + for (i = pg_start; i < (mem->page_count + pg_start); i++) { - OUTREG32(intel_i810_private.registers, - I810_PTE_BASE + (i * 4), - agp_bridge->scratch_page); + writel(agp_bridge->scratch_page, intel_i810_private.registers+I810_PTE_BASE+(i*4)); } + readl(intel_i810_private.registers+I810_PTE_BASE+((i-1)*4)); - global_cache_flush(); agp_bridge->driver->tlb_flush(mem); return 0; } @@ -218,20 +288,37 @@ static struct agp_memory *alloc_agpphysmem_i8xx(size_t pg_count, int type) struct agp_memory *new; void *addr; - if (pg_count != 1) + if (pg_count != 1 && pg_count != 4) return NULL; - addr = agp_bridge->driver->agp_alloc_page(); + 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(1); + new = agp_create_memory(pg_count); if (new == NULL) return NULL; - new->memory[0] = agp_bridge->driver->mask_memory(virt_to_phys(addr), type); - new->page_count = 1; - new->num_scratch_pages = 1; + 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; @@ -256,7 +343,7 @@ static struct agp_memory *intel_i810_alloc_by_type(size_t pg_count, int type) return new; } if (type == AGP_PHYS_MEMORY) - return(alloc_agpphysmem_i8xx(pg_count, type)); + return alloc_agpphysmem_i8xx(pg_count, type); return NULL; } @@ -264,29 +351,44 @@ static struct agp_memory *intel_i810_alloc_by_type(size_t pg_count, int type) static void intel_i810_free_by_type(struct agp_memory *curr) { agp_free_key(curr->key); - if(curr->type == AGP_PHYS_MEMORY) { - agp_bridge->driver->agp_destroy_page(phys_to_virt(curr->memory[0])); + 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(unsigned long addr, int type) +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 | agp_bridge->driver->masks[type].mask; + 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} + {64, 16384, 5}, + {256, 65536, 6}, + {512, 131072, 7}, }; static struct _intel_i830_private { struct pci_dev *i830_dev; /* device one */ - volatile u8 *registers; + volatile u8 __iomem *registers; + volatile u32 __iomem *gtt; /* I915G */ + /* gtt_entries is the number of gtt entries that are already mapped + * to stolen memory. Stolen memory is larger than the memory mapped + * through gtt_entries, as it includes some reserved space for the BIOS + * popup and for the GTT. + */ int gtt_entries; } intel_i830_private; @@ -297,24 +399,55 @@ static void intel_i830_init_gtt_entries(void) u8 rdct; int local = 0; static const int ddt[4] = { 0, 16, 32, 64 }; + int size; /* reserved space (in kb) at the top of stolen memory */ pci_read_config_word(agp_bridge->dev,I830_GMCH_CTRL,&gmch_ctrl); + if (IS_I965) { + u32 pgetbl_ctl; + pgetbl_ctl = readl(intel_i830_private.registers+I810_PGETBL_CTL); + + /* The 965 has a field telling us the size of the GTT, + * which may be larger than what is necessary to map the + * aperture. + */ + switch (pgetbl_ctl & I965_PGETBL_SIZE_MASK) { + case I965_PGETBL_SIZE_128KB: + size = 128; + break; + case I965_PGETBL_SIZE_256KB: + size = 256; + break; + case I965_PGETBL_SIZE_512KB: + size = 512; + break; + default: + printk(KERN_INFO PFX "Unknown page table size, " + "assuming 512KB\n"); + size = 512; + } + size += 4; /* add in BIOS popup space */ + } else { + /* On previous hardware, the GTT size was just what was + * required to map the aperture. + */ + 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(132); + gtt_entries = KB(512) - KB(size); break; case I830_GMCH_GMS_STOLEN_1024: - gtt_entries = MB(1) - KB(132); + gtt_entries = MB(1) - KB(size); break; case I830_GMCH_GMS_STOLEN_8192: - gtt_entries = MB(8) - KB(132); + gtt_entries = MB(8) - KB(size); break; case I830_GMCH_GMS_LOCAL: - rdct = INREG8(intel_i830_private.registers, - I830_RDRAM_CHANNEL_TYPE); + 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; @@ -326,20 +459,39 @@ static void intel_i830_init_gtt_entries(void) } else { switch (gmch_ctrl & I830_GMCH_GMS_MASK) { case I855_GMCH_GMS_STOLEN_1M: - gtt_entries = MB(1) - KB(132); + gtt_entries = MB(1) - KB(size); break; case I855_GMCH_GMS_STOLEN_4M: - gtt_entries = MB(4) - KB(132); + gtt_entries = MB(4) - KB(size); break; case I855_GMCH_GMS_STOLEN_8M: - gtt_entries = MB(8) - KB(132); + gtt_entries = MB(8) - KB(size); break; case I855_GMCH_GMS_STOLEN_16M: - gtt_entries = MB(16) - KB(132); + gtt_entries = MB(16) - KB(size); break; case I855_GMCH_GMS_STOLEN_32M: - gtt_entries = MB(32) - KB(132); + 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 || + agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GM_HB || IS_I965 ) + 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 || + agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GM_HB || IS_I965) + gtt_entries = MB(64) - KB(size); + else + gtt_entries = 0; default: gtt_entries = 0; break; @@ -359,7 +511,7 @@ static void intel_i830_init_gtt_entries(void) /* 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(void) +static int intel_i830_create_gatt_table(struct agp_bridge_data *bridge) { int page_order; struct aper_size_info_fixed *size; @@ -369,17 +521,17 @@ static int intel_i830_create_gatt_table(void) size = agp_bridge->current_size; page_order = size->page_order; num_entries = size->num_entries; - agp_bridge->gatt_table_real = 0; + agp_bridge->gatt_table_real = NULL; pci_read_config_dword(intel_i830_private.i830_dev,I810_MMADDR,&temp); temp &= 0xfff80000; - intel_i830_private.registers = (volatile u8 *) ioremap(temp,128 * 4096); + intel_i830_private.registers = ioremap(temp,128 * 4096); if (!intel_i830_private.registers) - return (-ENOMEM); + return -ENOMEM; - temp = INREG32(intel_i830_private.registers,I810_PGETBL_CTL) & 0xfffff000; - global_cache_flush(); + temp = readl(intel_i830_private.registers+I810_PGETBL_CTL) & 0xfffff000; + global_cache_flush(); /* FIXME: ?? */ /* we have to call this as early as possible after the MMIO base address is known */ intel_i830_init_gtt_entries(); @@ -388,15 +540,15 @@ static int intel_i830_create_gatt_table(void) agp_bridge->gatt_bus_addr = temp; - return(0); + return 0; } /* Return the gatt table to a sane state. Use the top of stolen * memory for the GTT. */ -static int intel_i830_free_gatt_table(void) +static int intel_i830_free_gatt_table(struct agp_bridge_data *bridge) { - return(0); + return 0; } static int intel_i830_fetch_size(void) @@ -411,7 +563,7 @@ static int intel_i830_fetch_size(void) /* 855GM/852GM/865G has 128MB aperture size */ agp_bridge->previous_size = agp_bridge->current_size = (void *) values; agp_bridge->aperture_size_idx = 0; - return(values[0].size); + return values[0].size; } pci_read_config_word(agp_bridge->dev,I830_GMCH_CTRL,&gmch_ctrl); @@ -419,14 +571,14 @@ static int intel_i830_fetch_size(void) if ((gmch_ctrl & I830_GMCH_MEM_MASK) == I830_GMCH_MEM_128M) { agp_bridge->previous_size = agp_bridge->current_size = (void *) values; agp_bridge->aperture_size_idx = 0; - return(values[0].size); + return values[0].size; } else { - agp_bridge->previous_size = agp_bridge->current_size = (void *) values; + agp_bridge->previous_size = agp_bridge->current_size = (void *) (values + 1); agp_bridge->aperture_size_idx = 1; - return(values[1].size); + return values[1].size; } - return(0); + return 0; } static int intel_i830_configure(void) @@ -445,27 +597,33 @@ static int intel_i830_configure(void) gmch_ctrl |= I830_GMCH_ENABLED; pci_write_config_word(agp_bridge->dev,I830_GMCH_CTRL,gmch_ctrl); - OUTREG32(intel_i830_private.registers,I810_PGETBL_CTL,agp_bridge->gatt_bus_addr | I810_PGETBL_ENABLED); - global_cache_flush(); + writel(agp_bridge->gatt_bus_addr|I810_PGETBL_ENABLED, intel_i830_private.registers+I810_PGETBL_CTL); + readl(intel_i830_private.registers+I810_PGETBL_CTL); /* PCI Posting. */ - if (agp_bridge->driver->needs_scratch_page) - for (i = intel_i830_private.gtt_entries; i < current_size->num_entries; i++) - OUTREG32(intel_i830_private.registers,I810_PTE_BASE + (i * 4),agp_bridge->scratch_page); + if (agp_bridge->driver->needs_scratch_page) { + for (i = intel_i830_private.gtt_entries; i < current_size->num_entries; i++) { + writel(agp_bridge->scratch_page, intel_i830_private.registers+I810_PTE_BASE+(i*4)); + readl(intel_i830_private.registers+I810_PTE_BASE+(i*4)); /* PCI Posting. */ + } + } - return (0); + global_cache_flush(); + return 0; } static void intel_i830_cleanup(void) { - iounmap((void *) intel_i830_private.registers); + iounmap(intel_i830_private.registers); } -static int intel_i830_insert_entries(struct agp_memory *mem,off_t pg_start, - int type) +static int intel_i830_insert_entries(struct agp_memory *mem,off_t pg_start, int type) { int i,j,num_entries; void *temp; + if (mem->page_count == 0) + return 0; + temp = agp_bridge->current_size; num_entries = A_SIZE_FIX(temp)->num_entries; @@ -474,11 +632,11 @@ static int intel_i830_insert_entries(struct agp_memory *mem,off_t pg_start, pg_start,intel_i830_private.gtt_entries); printk (KERN_INFO PFX "Trying to insert into local/stolen memory\n"); - return (-EINVAL); + return -EINVAL; } if ((pg_start + mem->page_count) > num_entries) - return (-EINVAL); + return -EINVAL; /* The i830 can't check the GTT for entries since its read only, * depend on the caller to make the correct offset decisions. @@ -486,19 +644,22 @@ static int intel_i830_insert_entries(struct agp_memory *mem,off_t pg_start, if ((type != 0 && type != AGP_PHYS_MEMORY) || (mem->type != 0 && mem->type != AGP_PHYS_MEMORY)) - return (-EINVAL); - - global_cache_flush(); + return -EINVAL; - for (i = 0, j = pg_start; i < mem->page_count; i++, j++) - OUTREG32(intel_i830_private.registers,I810_PTE_BASE + (j * 4), - agp_bridge->driver->mask_memory(mem->memory[i], mem->type)); + if (!mem->is_flushed) { + global_cache_flush(); + mem->is_flushed = TRUE; + } - 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_i830_private.registers+I810_PTE_BASE+(j*4)); + } + readl(intel_i830_private.registers+I810_PTE_BASE+((j-1)*4)); agp_bridge->driver->tlb_flush(mem); - - return(0); + return 0; } static int intel_i830_remove_entries(struct agp_memory *mem,off_t pg_start, @@ -506,32 +667,262 @@ static int intel_i830_remove_entries(struct agp_memory *mem,off_t pg_start, { int i; - global_cache_flush(); + if (mem->page_count == 0) + return 0; if (pg_start < intel_i830_private.gtt_entries) { printk (KERN_INFO PFX "Trying to disable local/stolen memory\n"); - return (-EINVAL); + return -EINVAL; } - for (i = pg_start; i < (mem->page_count + pg_start); i++) - OUTREG32(intel_i830_private.registers,I810_PTE_BASE + (i * 4),agp_bridge->scratch_page); - - global_cache_flush(); + for (i = pg_start; i < (mem->page_count + pg_start); i++) { + writel(agp_bridge->scratch_page, intel_i830_private.registers+I810_PTE_BASE+(i*4)); + } + readl(intel_i830_private.registers+I810_PTE_BASE+((i-1)*4)); agp_bridge->driver->tlb_flush(mem); - - return (0); + return 0; } static struct agp_memory *intel_i830_alloc_by_type(size_t pg_count,int type) { if (type == AGP_PHYS_MEMORY) - return(alloc_agpphysmem_i8xx(pg_count, type)); + return alloc_agpphysmem_i8xx(pg_count, type); /* always return NULL for other allocation types for now */ - return(NULL); + return NULL; +} + +static int intel_i915_configure(void) +{ + struct aper_size_info_fixed *current_size; + u32 temp; + u16 gmch_ctrl; + int i; + + current_size = A_SIZE_FIX(agp_bridge->current_size); + + pci_read_config_dword(intel_i830_private.i830_dev, I915_GMADDR, &temp); + + agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); + + pci_read_config_word(agp_bridge->dev,I830_GMCH_CTRL,&gmch_ctrl); + gmch_ctrl |= I830_GMCH_ENABLED; + pci_write_config_word(agp_bridge->dev,I830_GMCH_CTRL,gmch_ctrl); + + writel(agp_bridge->gatt_bus_addr|I810_PGETBL_ENABLED, intel_i830_private.registers+I810_PGETBL_CTL); + readl(intel_i830_private.registers+I810_PGETBL_CTL); /* PCI Posting. */ + + if (agp_bridge->driver->needs_scratch_page) { + for (i = intel_i830_private.gtt_entries; i < current_size->num_entries; i++) { + writel(agp_bridge->scratch_page, intel_i830_private.gtt+i); + readl(intel_i830_private.gtt+i); /* PCI Posting. */ + } + } + + global_cache_flush(); + return 0; +} + +static void intel_i915_cleanup(void) +{ + iounmap(intel_i830_private.gtt); + iounmap(intel_i830_private.registers); } +static int intel_i915_insert_entries(struct agp_memory *mem,off_t pg_start, + int type) +{ + int i,j,num_entries; + void *temp; + + if (mem->page_count == 0) + return 0; + + temp = agp_bridge->current_size; + num_entries = A_SIZE_FIX(temp)->num_entries; + + if (pg_start < intel_i830_private.gtt_entries) { + printk (KERN_DEBUG PFX "pg_start == 0x%.8lx,intel_i830_private.gtt_entries == 0x%.8x\n", + pg_start,intel_i830_private.gtt_entries); + + printk (KERN_INFO PFX "Trying to insert into local/stolen memory\n"); + return -EINVAL; + } + + if ((pg_start + mem->page_count) > num_entries) + return -EINVAL; + + /* The i830 can't check the GTT for entries since its read only, + * depend on the caller to make the correct offset decisions. + */ + + if ((type != 0 && type != AGP_PHYS_MEMORY) || + (mem->type != 0 && mem->type != AGP_PHYS_MEMORY)) + return -EINVAL; + + if (!mem->is_flushed) { + global_cache_flush(); + mem->is_flushed = TRUE; + } + + 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_i830_private.gtt+j); + } + readl(intel_i830_private.gtt+j-1); + + agp_bridge->driver->tlb_flush(mem); + return 0; +} + +static int intel_i915_remove_entries(struct agp_memory *mem,off_t pg_start, + int type) +{ + int i; + + if (mem->page_count == 0) + return 0; + + if (pg_start < intel_i830_private.gtt_entries) { + printk (KERN_INFO PFX "Trying to disable local/stolen memory\n"); + return -EINVAL; + } + + for (i = pg_start; i < (mem->page_count + pg_start); i++) { + writel(agp_bridge->scratch_page, intel_i830_private.gtt+i); + } + readl(intel_i830_private.gtt+i-1); + + agp_bridge->driver->tlb_flush(mem); + return 0; +} + +/* Return the aperture size by just checking the resource length. The effect + * described in the spec of the MSAC registers is just changing of the + * resource size. + */ +static int intel_i9xx_fetch_size(void) +{ + int num_sizes = sizeof(intel_i830_sizes) / sizeof(*intel_i830_sizes); + int aper_size; /* size in megabytes */ + int i; + + aper_size = pci_resource_len(intel_i830_private.i830_dev, 2) / MB(1); + + for (i = 0; i < num_sizes; i++) { + if (aper_size == intel_i830_sizes[i].size) { + agp_bridge->current_size = intel_i830_sizes + i; + agp_bridge->previous_size = agp_bridge->current_size; + return aper_size; + } + } + + return 0; +} + +/* The intel i915 automatically initializes the agp aperture during POST. + * Use the memory already set aside for in the GTT. + */ +static int intel_i915_create_gatt_table(struct agp_bridge_data *bridge) +{ + int page_order; + struct aper_size_info_fixed *size; + int num_entries; + u32 temp, temp2; + + size = agp_bridge->current_size; + page_order = size->page_order; + num_entries = size->num_entries; + agp_bridge->gatt_table_real = NULL; + + pci_read_config_dword(intel_i830_private.i830_dev, I915_MMADDR, &temp); + pci_read_config_dword(intel_i830_private.i830_dev, I915_PTEADDR,&temp2); + + intel_i830_private.gtt = ioremap(temp2, 256 * 1024); + if (!intel_i830_private.gtt) + return -ENOMEM; + + temp &= 0xfff80000; + + intel_i830_private.registers = ioremap(temp,128 * 4096); + if (!intel_i830_private.registers) + return -ENOMEM; + + temp = readl(intel_i830_private.registers+I810_PGETBL_CTL) & 0xfffff000; + global_cache_flush(); /* FIXME: ? */ + + /* we have to call this as early as possible after the MMIO base address is known */ + intel_i830_init_gtt_entries(); + + agp_bridge->gatt_table = NULL; + + agp_bridge->gatt_bus_addr = temp; + + return 0; +} + +/* + * The i965 supports 36-bit physical addresses, but to keep + * the format of the GTT the same, the bits that don't fit + * in a 32-bit word are shifted down to bits 4..7. + * + * Gcc is smart enough to notice that "(addr >> 28) & 0xf0" + * is always zero on 32-bit architectures, so no need to make + * this conditional. + */ +static unsigned long intel_i965_mask_memory(struct agp_bridge_data *bridge, + unsigned long addr, int type) +{ + /* Shift high bits down */ + addr |= (addr >> 28) & 0xf0; + + /* Type checking must be done elsewhere */ + return addr | bridge->driver->masks[type].mask; +} + +/* The intel i965 automatically initializes the agp aperture during POST. + * Use the memory already set aside for in the GTT. + */ +static int intel_i965_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; + page_order = size->page_order; + num_entries = size->num_entries; + agp_bridge->gatt_table_real = NULL; + + pci_read_config_dword(intel_i830_private.i830_dev, I915_MMADDR, &temp); + + temp &= 0xfff00000; + intel_i830_private.gtt = ioremap((temp + (512 * 1024)) , 512 * 1024); + + if (!intel_i830_private.gtt) + return -ENOMEM; + + + intel_i830_private.registers = ioremap(temp,128 * 4096); + if (!intel_i830_private.registers) + return -ENOMEM; + + temp = readl(intel_i830_private.registers+I810_PGETBL_CTL) & 0xfffff000; + global_cache_flush(); /* FIXME: ? */ + + /* we have to call this as early as possible after the MMIO base address is known */ + intel_i830_init_gtt_entries(); + + agp_bridge->gatt_table = NULL; + + agp_bridge->gatt_bus_addr = temp; + + return 0; +} + + static int intel_fetch_size(void) { int i; @@ -679,7 +1070,7 @@ static int intel_815_configure(void) /* aperture size */ pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, - current_size->size_value); + current_size->size_value); /* address to map to */ pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp); @@ -691,7 +1082,7 @@ static int intel_815_configure(void) pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, addr); /* agpctrl */ - pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x0000); + pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x0000); /* apcont */ pci_read_config_byte(agp_bridge->dev, INTEL_815_APCONT, &temp2); @@ -714,7 +1105,7 @@ static void intel_820_cleanup(void) previous_size = A_SIZE_8(agp_bridge->previous_size); pci_read_config_byte(agp_bridge->dev, INTEL_I820_RDCR, &temp); - pci_write_config_byte(agp_bridge->dev, INTEL_I820_RDCR, + pci_write_config_byte(agp_bridge->dev, INTEL_I820_RDCR, temp & ~(1 << 1)); pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, previous_size->size_value); @@ -724,23 +1115,23 @@ static void intel_820_cleanup(void) static int intel_820_configure(void) { u32 temp; - u8 temp2; + u8 temp2; struct aper_size_info_8 *current_size; current_size = A_SIZE_8(agp_bridge->current_size); /* aperture size */ - pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, current_size->size_value); + pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, current_size->size_value); /* address to map to */ pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp); agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); /* attbase - aperture base */ - pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr); + pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr); /* agpctrl */ - pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x0000); + pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x0000); /* global enable aperture access */ /* This flag is not accessed through MCHCFG register as in */ @@ -748,7 +1139,7 @@ static int intel_820_configure(void) pci_read_config_byte(agp_bridge->dev, INTEL_I820_RDCR, &temp2); pci_write_config_byte(agp_bridge->dev, INTEL_I820_RDCR, temp2 | (1 << 1)); /* clear any possible AGP-related error conditions */ - pci_write_config_word(agp_bridge->dev, INTEL_I820_ERRSTS, 0x001c); + pci_write_config_word(agp_bridge->dev, INTEL_I820_ERRSTS, 0x001c); return 0; } @@ -761,23 +1152,23 @@ static int intel_840_configure(void) current_size = A_SIZE_8(agp_bridge->current_size); /* aperture size */ - pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, current_size->size_value); + pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, current_size->size_value); /* address to map to */ pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp); agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); /* attbase - aperture base */ - pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr); + pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr); /* agpctrl */ - pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x0000); + pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x0000); /* mcgcfg */ pci_read_config_word(agp_bridge->dev, INTEL_I840_MCHCFG, &temp2); pci_write_config_word(agp_bridge->dev, INTEL_I840_MCHCFG, temp2 | (1 << 9)); /* clear any possible error conditions */ - pci_write_config_word(agp_bridge->dev, INTEL_I840_ERRSTS, 0xc000); + pci_write_config_word(agp_bridge->dev, INTEL_I840_ERRSTS, 0xc000); return 0; } @@ -790,23 +1181,29 @@ static int intel_845_configure(void) current_size = A_SIZE_8(agp_bridge->current_size); /* aperture size */ - pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, current_size->size_value); + pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, current_size->size_value); - /* address to map to */ - pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp); - agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); + if (agp_bridge->apbase_config != 0) { + pci_write_config_dword(agp_bridge->dev, AGP_APBASE, + agp_bridge->apbase_config); + } else { + /* address to map to */ + pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp); + agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); + agp_bridge->apbase_config = temp; + } /* attbase - aperture base */ - pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr); + pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr); /* agpctrl */ - pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x0000); + pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x0000); /* agpm */ pci_read_config_byte(agp_bridge->dev, INTEL_I845_AGPM, &temp2); pci_write_config_byte(agp_bridge->dev, INTEL_I845_AGPM, temp2 | (1 << 1)); /* clear any possible error conditions */ - pci_write_config_word(agp_bridge->dev, INTEL_I845_ERRSTS, 0x001c); + pci_write_config_word(agp_bridge->dev, INTEL_I845_ERRSTS, 0x001c); return 0; } @@ -819,23 +1216,23 @@ static int intel_850_configure(void) current_size = A_SIZE_8(agp_bridge->current_size); /* aperture size */ - pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, current_size->size_value); + pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, current_size->size_value); /* address to map to */ pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp); agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); /* attbase - aperture base */ - pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr); + pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr); /* agpctrl */ - pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x0000); + pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x0000); /* mcgcfg */ pci_read_config_word(agp_bridge->dev, INTEL_I850_MCHCFG, &temp2); pci_write_config_word(agp_bridge->dev, INTEL_I850_MCHCFG, temp2 | (1 << 9)); /* clear any possible AGP-related error conditions */ - pci_write_config_word(agp_bridge->dev, INTEL_I850_ERRSTS, 0x001c); + pci_write_config_word(agp_bridge->dev, INTEL_I850_ERRSTS, 0x001c); return 0; } @@ -921,7 +1318,7 @@ static int intel_7505_configure(void) /* mchcfg */ pci_read_config_word(agp_bridge->dev, INTEL_I7505_MCHCFG, &temp2); pci_write_config_word(agp_bridge->dev, INTEL_I7505_MCHCFG, temp2 | (1 << 9)); - + return 0; } @@ -936,7 +1333,7 @@ static struct aper_size_info_8 intel_815_sizes[2] = {64, 16384, 4, 0}, {32, 8192, 3, 8}, }; - + static struct aper_size_info_8 intel_8xx_sizes[7] = { {256, 65536, 6, 0}, @@ -959,7 +1356,7 @@ static struct aper_size_info_16 intel_generic_sizes[7] = {4, 1024, 0, 63} }; -static struct aper_size_info_8 intel_830mp_sizes[4] = +static struct aper_size_info_8 intel_830mp_sizes[4] = { {256, 65536, 6, 0}, {128, 32768, 5, 32}, @@ -1041,7 +1438,7 @@ static struct agp_bridge_driver intel_830_driver = { .owner = THIS_MODULE, .aperture_sizes = intel_i830_sizes, .size_type = FIXED_APER_SIZE, - .num_aperture_sizes = 2, + .num_aperture_sizes = 4, .needs_scratch_page = TRUE, .configure = intel_i830_configure, .fetch_size = intel_i830_fetch_size, @@ -1199,6 +1596,54 @@ static struct agp_bridge_driver intel_860_driver = { .agp_destroy_page = agp_generic_destroy_page, }; +static struct agp_bridge_driver intel_915_driver = { + .owner = THIS_MODULE, + .aperture_sizes = intel_i830_sizes, + .size_type = FIXED_APER_SIZE, + .num_aperture_sizes = 4, + .needs_scratch_page = TRUE, + .configure = intel_i915_configure, + .fetch_size = intel_i9xx_fetch_size, + .cleanup = intel_i915_cleanup, + .tlb_flush = intel_i810_tlbflush, + .mask_memory = intel_i810_mask_memory, + .masks = intel_i810_masks, + .agp_enable = intel_i810_agp_enable, + .cache_flush = global_cache_flush, + .create_gatt_table = intel_i915_create_gatt_table, + .free_gatt_table = intel_i830_free_gatt_table, + .insert_memory = intel_i915_insert_entries, + .remove_memory = intel_i915_remove_entries, + .alloc_by_type = intel_i830_alloc_by_type, + .free_by_type = intel_i810_free_by_type, + .agp_alloc_page = agp_generic_alloc_page, + .agp_destroy_page = agp_generic_destroy_page, +}; + +static struct agp_bridge_driver intel_i965_driver = { + .owner = THIS_MODULE, + .aperture_sizes = intel_i830_sizes, + .size_type = FIXED_APER_SIZE, + .num_aperture_sizes = 4, + .needs_scratch_page = TRUE, + .configure = intel_i915_configure, + .fetch_size = intel_i9xx_fetch_size, + .cleanup = intel_i915_cleanup, + .tlb_flush = intel_i810_tlbflush, + .mask_memory = intel_i965_mask_memory, + .masks = intel_i810_masks, + .agp_enable = intel_i810_agp_enable, + .cache_flush = global_cache_flush, + .create_gatt_table = intel_i965_create_gatt_table, + .free_gatt_table = intel_i830_free_gatt_table, + .insert_memory = intel_i915_insert_entries, + .remove_memory = intel_i915_remove_entries, + .alloc_by_type = intel_i830_alloc_by_type, + .free_by_type = intel_i810_free_by_type, + .agp_alloc_page = agp_generic_alloc_page, + .agp_destroy_page = agp_generic_destroy_page, +}; + static struct agp_bridge_driver intel_7505_driver = { .owner = THIS_MODULE, .aperture_sizes = intel_8xx_sizes, @@ -1222,18 +1667,13 @@ static struct agp_bridge_driver intel_7505_driver = { .agp_destroy_page = agp_generic_destroy_page, }; -static int find_i810(u16 device, const char *name) +static int find_i810(u16 device) { struct pci_dev *i810_dev; - i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL, device, NULL); - if (!i810_dev) { - printk(KERN_ERR PFX "Detected an Intel %s Chipset, " - "but could not find the secondary device.\n", - name); + i810_dev = pci_get_device(PCI_VENDOR_ID_INTEL, device, NULL); + if (!i810_dev) return 0; - } - intel_i810_private.i810_dev = i810_dev; return 1; } @@ -1242,9 +1682,9 @@ static int find_i830(u16 device) { struct pci_dev *i830_dev; - i830_dev = pci_find_device(PCI_VENDOR_ID_INTEL, device, NULL); + i830_dev = pci_get_device(PCI_VENDOR_ID_INTEL, device, NULL); if (i830_dev && PCI_FUNC(i830_dev->devfn) != 0) { - i830_dev = pci_find_device(PCI_VENDOR_ID_INTEL, + i830_dev = pci_get_device(PCI_VENDOR_ID_INTEL, device, i830_dev); } @@ -1283,29 +1723,29 @@ static int __devinit agp_intel_probe(struct pci_dev *pdev, name = "440GX"; break; case PCI_DEVICE_ID_INTEL_82810_MC1: - if (!find_i810(PCI_DEVICE_ID_INTEL_82810_IG1, "i810")) + name = "i810"; + if (!find_i810(PCI_DEVICE_ID_INTEL_82810_IG1)) goto fail; bridge->driver = &intel_810_driver; - name = "i810"; break; case PCI_DEVICE_ID_INTEL_82810_MC3: - if (!find_i810(PCI_DEVICE_ID_INTEL_82810_IG3, "i810 DC100")) + name = "i810 DC100"; + if (!find_i810(PCI_DEVICE_ID_INTEL_82810_IG3)) goto fail; bridge->driver = &intel_810_driver; - name = "i810 DC100"; break; case PCI_DEVICE_ID_INTEL_82810E_MC: - if (!find_i810(PCI_DEVICE_ID_INTEL_82810E_IG, "i810 E")) + name = "i810 E"; + if (!find_i810(PCI_DEVICE_ID_INTEL_82810E_IG)) goto fail; bridge->driver = &intel_810_driver; - name = "i810 E"; break; case PCI_DEVICE_ID_INTEL_82815_MC: /* * The i815 can operate either as an i810 style * integrated device, or as an AGP4X motherboard. */ - if (find_i810(PCI_DEVICE_ID_INTEL_82815_CGC, "i815")) + if (find_i810(PCI_DEVICE_ID_INTEL_82815_CGC)) bridge->driver = &intel_810_driver; else bridge->driver = &intel_815_driver; @@ -1317,11 +1757,10 @@ static int __devinit agp_intel_probe(struct pci_dev *pdev, name = "i820"; break; case PCI_DEVICE_ID_INTEL_82830_HB: - if (find_i830(PCI_DEVICE_ID_INTEL_82830_CGC)) { + if (find_i830(PCI_DEVICE_ID_INTEL_82830_CGC)) bridge->driver = &intel_830_driver; - } else { + else bridge->driver = &intel_830mp_driver; - } name = "830M"; break; case PCI_DEVICE_ID_INTEL_82840_HB: @@ -1333,11 +1772,10 @@ static int __devinit agp_intel_probe(struct pci_dev *pdev, name = "i845"; break; case PCI_DEVICE_ID_INTEL_82845G_HB: - if (find_i830(PCI_DEVICE_ID_INTEL_82845G_IG)) { + if (find_i830(PCI_DEVICE_ID_INTEL_82845G_IG)) bridge->driver = &intel_830_driver; - } else { + else bridge->driver = &intel_845_driver; - } name = "845G"; break; case PCI_DEVICE_ID_INTEL_82850_HB: @@ -1362,20 +1800,76 @@ static int __devinit agp_intel_probe(struct pci_dev *pdev, name = "i860"; break; case PCI_DEVICE_ID_INTEL_82865_HB: - if (find_i830(PCI_DEVICE_ID_INTEL_82865_IG)) { + if (find_i830(PCI_DEVICE_ID_INTEL_82865_IG)) bridge->driver = &intel_830_driver; - } else { + else bridge->driver = &intel_845_driver; - } name = "865"; break; case PCI_DEVICE_ID_INTEL_82875_HB: bridge->driver = &intel_845_driver; name = "i875"; break; + case PCI_DEVICE_ID_INTEL_82915G_HB: + if (find_i830(PCI_DEVICE_ID_INTEL_82915G_IG)) + bridge->driver = &intel_915_driver; + else + bridge->driver = &intel_845_driver; + name = "915G"; + break; + case PCI_DEVICE_ID_INTEL_82915GM_HB: + if (find_i830(PCI_DEVICE_ID_INTEL_82915GM_IG)) + bridge->driver = &intel_915_driver; + else + bridge->driver = &intel_845_driver; + name = "915GM"; + break; + case PCI_DEVICE_ID_INTEL_82945G_HB: + if (find_i830(PCI_DEVICE_ID_INTEL_82945G_IG)) + bridge->driver = &intel_915_driver; + else + bridge->driver = &intel_845_driver; + name = "945G"; + break; + case PCI_DEVICE_ID_INTEL_82945GM_HB: + if (find_i830(PCI_DEVICE_ID_INTEL_82945GM_IG)) + bridge->driver = &intel_915_driver; + else + bridge->driver = &intel_845_driver; + name = "945GM"; + break; + case PCI_DEVICE_ID_INTEL_82946GZ_HB: + if (find_i830(PCI_DEVICE_ID_INTEL_82946GZ_IG)) + bridge->driver = &intel_i965_driver; + else + bridge->driver = &intel_845_driver; + name = "946GZ"; + break; + case PCI_DEVICE_ID_INTEL_82965G_1_HB: + if (find_i830(PCI_DEVICE_ID_INTEL_82965G_1_IG)) + bridge->driver = &intel_i965_driver; + else + bridge->driver = &intel_845_driver; + name = "965G"; + break; + case PCI_DEVICE_ID_INTEL_82965Q_HB: + if (find_i830(PCI_DEVICE_ID_INTEL_82965Q_IG)) + bridge->driver = &intel_i965_driver; + else + bridge->driver = &intel_845_driver; + name = "965Q"; + break; + case PCI_DEVICE_ID_INTEL_82965G_HB: + if (find_i830(PCI_DEVICE_ID_INTEL_82965G_IG)) + bridge->driver = &intel_i965_driver; + else + bridge->driver = &intel_845_driver; + name = "965G"; + break; + case PCI_DEVICE_ID_INTEL_7505_0: bridge->driver = &intel_7505_driver; - name = "E7505"; + name = "E7505"; break; case PCI_DEVICE_ID_INTEL_7205_0: bridge->driver = &intel_7505_driver; @@ -1406,7 +1900,7 @@ static int __devinit agp_intel_probe(struct pci_dev *pdev, */ r = &pdev->resource[0]; if (!r->start && r->end) { - if(pci_assign_resource(pdev, 0)) { + if (pci_assign_resource(pdev, 0)) { printk(KERN_ERR PFX "could not assign resource 0\n"); agp_put_bridge(bridge); return -ENODEV; @@ -1433,7 +1927,10 @@ static int __devinit agp_intel_probe(struct pci_dev *pdev, pci_set_drvdata(pdev, bridge); return agp_add_bridge(bridge); - fail: + +fail: + printk(KERN_ERR PFX "Detected an Intel %s chipset, " + "but could not find the secondary device.\n", name); agp_put_bridge(bridge); return -ENODEV; } @@ -1443,28 +1940,55 @@ static void __devexit agp_intel_remove(struct pci_dev *pdev) struct agp_bridge_data *bridge = pci_get_drvdata(pdev); agp_remove_bridge(bridge); + + if (intel_i810_private.i810_dev) + pci_dev_put(intel_i810_private.i810_dev); + if (intel_i830_private.i830_dev) + pci_dev_put(intel_i830_private.i830_dev); + agp_put_bridge(bridge); } +#ifdef CONFIG_PM static int agp_intel_resume(struct pci_dev *pdev) { struct agp_bridge_data *bridge = pci_get_drvdata(pdev); - - pci_restore_state(pdev, pdev->saved_config_space); + + pci_restore_state(pdev); + + /* We should restore our graphics device's config space, + * as host bridge (00:00) resumes before graphics device (02:00), + * then our access to its pci space can work right. + */ + if (intel_i810_private.i810_dev) + pci_restore_state(intel_i810_private.i810_dev); + if (intel_i830_private.i830_dev) + pci_restore_state(intel_i830_private.i830_dev); if (bridge->driver == &intel_generic_driver) intel_configure(); + else if (bridge->driver == &intel_850_driver) + intel_850_configure(); else if (bridge->driver == &intel_845_driver) intel_845_configure(); else if (bridge->driver == &intel_830mp_driver) intel_830mp_configure(); + else if (bridge->driver == &intel_915_driver) + intel_i915_configure(); + else if (bridge->driver == &intel_830_driver) + intel_i830_configure(); + else if (bridge->driver == &intel_810_driver) + intel_i810_configure(); + else if (bridge->driver == &intel_i965_driver) + intel_i915_configure(); return 0; } +#endif static struct pci_device_id agp_intel_pci_table[] = { #define ID(x) \ - { \ + { \ .class = (PCI_CLASS_BRIDGE_HOST << 8), \ .class_mask = ~0, \ .vendor = PCI_VENDOR_ID_INTEL, \ @@ -1492,7 +2016,15 @@ static struct pci_device_id agp_intel_pci_table[] = { ID(PCI_DEVICE_ID_INTEL_82865_HB), ID(PCI_DEVICE_ID_INTEL_82875_HB), ID(PCI_DEVICE_ID_INTEL_7505_0), - ID(PCI_DEVICE_ID_INTEL_7205_0), + ID(PCI_DEVICE_ID_INTEL_7205_0), + ID(PCI_DEVICE_ID_INTEL_82915G_HB), + ID(PCI_DEVICE_ID_INTEL_82915GM_HB), + ID(PCI_DEVICE_ID_INTEL_82945G_HB), + ID(PCI_DEVICE_ID_INTEL_82945GM_HB), + ID(PCI_DEVICE_ID_INTEL_82946GZ_HB), + ID(PCI_DEVICE_ID_INTEL_82965G_1_HB), + ID(PCI_DEVICE_ID_INTEL_82965Q_HB), + ID(PCI_DEVICE_ID_INTEL_82965G_HB), { } }; @@ -1502,21 +2034,17 @@ static struct pci_driver agp_intel_pci_driver = { .name = "agpgart-intel", .id_table = agp_intel_pci_table, .probe = agp_intel_probe, - .remove = agp_intel_remove, + .remove = __devexit_p(agp_intel_remove), +#ifdef CONFIG_PM .resume = agp_intel_resume, +#endif }; -/* intel_agp_init() must not be declared static for explicit - early initialization to work (ie i810fb) */ -int __init agp_intel_init(void) +static int __init agp_intel_init(void) { - static int agp_initialised=0; - - if (agp_initialised == 1) - return 0; - agp_initialised=1; - - return pci_module_init(&agp_intel_pci_driver); + if (agp_off) + return -EINVAL; + return pci_register_driver(&agp_intel_pci_driver); } static void __exit agp_intel_cleanup(void)