--- linux-2.6.2/drivers/char/agp/agp.h 2004-02-04 03:43:43.000000000 +0000 +++ linux-2.6.2/drivers/char/agp/agp.h 2004-02-09 13:01:46.000000000 +0000 @@ -402,6 +402,16 @@ void global_cache_flush(void); void get_agp_version(struct agp_bridge_data *bridge); unsigned long agp_generic_mask_memory(unsigned long addr, int type); +/* generic routines for agp>=3 */ +int agp3_generic_fetch_size(void); +void agp3_generic_tlbflush(struct agp_memory *mem); +int agp3_generic_configure(void); +void agp3_generic_cleanup(void); + +/* aperture sizes have been standardised since v3 */ +#define AGP_GENERIC_SIZES_ENTRIES 11 +extern struct aper_size_info_16 agp3_generic_sizes[]; + extern int agp_off; extern int agp_try_unsupported_boot; @@ -410,13 +420,17 @@ extern int agp_try_unsupported_boot; #define AGPCMD 0x8 #define AGPNISTAT 0xc #define AGPCTRL 0x10 +#define AGPAPSIZE 0x14 #define AGPNEPG 0x16 +#define AGPGARTLO 0x18 +#define AGPGARTHI 0x1c #define AGPNICMD 0x20 #define AGP_MAJOR_VERSION_SHIFT (20) #define AGP_MINOR_VERSION_SHIFT (16) #define AGPSTAT_RQ_DEPTH (0xff000000) +#define AGPSTAT_RQ_DEPTH_SHIFT 24 #define AGPSTAT_CAL_MASK (1<<12|1<<11|1<<10) #define AGPSTAT_ARQSZ (1<<15|1<<14|1<<13) @@ -435,4 +449,7 @@ extern int agp_try_unsupported_boot; #define AGPSTAT3_8X (1<<1) #define AGPSTAT3_4X (1) +#define AGPCTRL_APERENB (1<<8) +#define AGPCTRL_GTLBEN (1<<7) + #endif /* _AGP_BACKEND_PRIV_H */ --- linux-2.6.2/drivers/char/agp/generic.c 2004-02-04 03:43:42.000000000 +0000 +++ linux-2.6.2/drivers/char/agp/generic.c 2004-02-11 17:06:25.000000000 +0000 @@ -956,3 +956,86 @@ unsigned long agp_generic_mask_memory(un } EXPORT_SYMBOL(agp_generic_mask_memory); +/* + * These functions are implemented according to the agpV3 spec, + * which covers implementation details that had previously been + * left open. + */ + +int agp3_generic_fetch_size(void) +{ + u16 temp_size; + int i; + struct aper_size_info_16 *values; + + pci_read_config_word(agp_bridge->dev, agp_bridge->capndx+AGPAPSIZE, &temp_size); + values = A_SIZE_16(agp_bridge->driver->aperture_sizes); + + for (i = 0; i < agp_bridge->driver->num_aperture_sizes; i++) { + if (temp_size == values[i].size_value) { + agp_bridge->previous_size = + agp_bridge->current_size = (void *) (values + i); + + agp_bridge->aperture_size_idx = i; + return values[i].size; + } + } + return 0; +} +EXPORT_SYMBOL(agp3_generic_fetch_size); + +void agp3_generic_tlbflush(struct agp_memory *mem) +{ + u32 ctrl; + pci_read_config_dword(agp_bridge->dev, agp_bridge->capndx+AGPCTRL, &ctrl); + pci_write_config_dword(agp_bridge->dev, agp_bridge->capndx+AGPCTRL, ctrl & ~AGPCTRL_GTLBEN); + pci_write_config_dword(agp_bridge->dev, agp_bridge->capndx+AGPCTRL, ctrl); +} +EXPORT_SYMBOL(agp3_generic_tlbflush); + +int agp3_generic_configure(void) +{ + u32 temp; + + struct aper_size_info_16 *current_size; + current_size = A_SIZE_16(agp_bridge->current_size); + + pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp); + agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); + + // set aperture size + pci_write_config_word(agp_bridge->dev, agp_bridge->capndx+AGPAPSIZE, current_size->size_value); + // set gart pointer + pci_write_config_dword(agp_bridge->dev, agp_bridge->capndx+AGPGARTLO, agp_bridge->gatt_bus_addr); + + // enable aperture and GTLB + pci_read_config_dword(agp_bridge->dev, agp_bridge->capndx+AGPCTRL, &temp); + pci_write_config_dword(agp_bridge->dev, agp_bridge->capndx+AGPCTRL, temp | AGPCTRL_APERENB | AGPCTRL_GTLBEN); + + return 0; +} +EXPORT_SYMBOL(agp3_generic_configure); + +void agp3_generic_cleanup(void) +{ + u32 ctrl; + pci_read_config_dword(agp_bridge->dev, agp_bridge->capndx+AGPCTRL, &ctrl); + pci_write_config_dword(agp_bridge->dev, agp_bridge->capndx+AGPCTRL, ctrl & ~AGPCTRL_APERENB); +} +EXPORT_SYMBOL(agp3_generic_cleanup); + +struct aper_size_info_16 agp3_generic_sizes[AGP_GENERIC_SIZES_ENTRIES]= +{ + {4096, 1048576, 10,0x000}, + {2048, 524288, 9, 0x800}, + {1024, 262144, 8, 0xc00}, + { 512, 131072, 7, 0xe00}, + { 256, 65536, 6, 0xf00}, + { 128, 32768, 5, 0xf20}, + { 64, 16384, 4, 0xf30}, + { 32, 8192, 3, 0xf38}, + { 16, 4096, 2, 0xf3c}, + { 8, 2048, 1, 0xf3e}, + { 4, 1024, 0, 0xf3f} +}; +EXPORT_SYMBOL(agp3_generic_sizes); --- linux-2.6.2/drivers/char/agp/sis-agp.c 2004-02-04 03:43:07.000000000 +0000 +++ linux-2.6.2/drivers/char/agp/sis-agp.c 2004-02-11 16:45:39.000000000 +0000 @@ -61,6 +61,45 @@ static void sis_cleanup(void) (previous_size->size_value & ~(0x03))); } +static void sis_648_enable(u32 mode) +{ + struct pci_dev *device = NULL; + u32 command; + int rate; + + printk(KERN_INFO PFX "Found an AGP %d.%d compliant device at %s.\n", + agp_bridge->major_version, + agp_bridge->minor_version, + agp_bridge->dev->slot_name); + + pci_read_config_dword(agp_bridge->dev, + agp_bridge->capndx + PCI_AGP_STATUS, &command); + + command = agp_collect_device_status(mode, command); + command |= AGPSTAT_AGP_ENABLE; + rate = (command & 0x7) << 2; + + while ((device = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, device)) != NULL) { + u8 agp = pci_find_capability(device, PCI_CAP_ID_AGP); + if (!agp) + continue; + + printk(KERN_INFO PFX "Putting AGP V3 device at %s into %dx mode\n", + pci_name(device), rate); + + pci_write_config_dword(device, agp + PCI_AGP_COMMAND, command); + + if(device->device == PCI_DEVICE_ID_SI_741) + { + // weird: on 648 and 648fx chipsets any rate change in the target command register + // triggers a 5ms screwup during which the master cannot be configured + printk(KERN_INFO PFX "sis 741 agp fix - giving bridge time to recover\n"); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout (1+(HZ*10)/1000); + } + } +} + static struct aper_size_info_8 sis_generic_sizes[7] = { {256, 65536, 6, 99}, @@ -176,6 +215,29 @@ static struct agp_device_ids sis_agp_dev { }, /* dummy final entry, always present */ }; +static void __devinit sis_get_driver(struct agp_bridge_data *bridge) +{ + if(bridge->dev->device==PCI_DEVICE_ID_SI_741) + { + if(agp_bridge->major_version==3 && agp_bridge->minor_version < 5) + { + sis_driver.agp_enable=sis_648_enable; + } + else + { + sis_driver.agp_enable = sis_648_enable; + sis_driver.aperture_sizes = agp3_generic_sizes; + sis_driver.size_type = U16_APER_SIZE; + sis_driver.num_aperture_sizes = AGP_GENERIC_SIZES_ENTRIES; + sis_driver.configure = agp3_generic_configure; + sis_driver.fetch_size = agp3_generic_fetch_size; + sis_driver.cleanup = agp3_generic_cleanup; + sis_driver.tlb_flush = agp3_generic_tlbflush; + } + } + bridge->driver=&sis_driver; +} + static int __devinit agp_sis_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -206,14 +268,17 @@ found: if (!bridge) return -ENOMEM; - bridge->driver = &sis_driver; bridge->dev = pdev; bridge->capndx = cap_ptr; + get_agp_version(bridge); + /* Fill in the mode register */ pci_read_config_dword(pdev, - bridge->capndx+PCI_AGP_STATUS, - &bridge->mode); + bridge->capndx+PCI_AGP_STATUS, + &bridge->mode); + + sis_get_driver(bridge); pci_set_drvdata(pdev, bridge); return agp_add_bridge(bridge);