Re: [BUG] E7x05 chipset bug in 2.5 kernels' AGPGART driver.

ISHIKAWA Mutsumi (ishikawa@debian.org)
Thu, 03 Apr 2003 12:33:59 +0900


>>>>> In <20030402221046.GA30881@suse.de>
>>>>> Dave Jones <davej@codemonkey.org.uk> wrote:
>> On Wed, Apr 02, 2003 at 08:50:03PM +0200, Fendrakyn wrote:

>> > The last problem is more important and I have yet to find a solution. It seems
>> > like the driver stores device 0 in his agp_bridge->dev (0x255d for E7205,
>> > 0x2550 for E7505) but it uses registers from device 1 (0x2552) thus the
>> > chipset cannot be configured properly. The fetch_size function fails to
>> > determine aperture size.

>> Yep, the other issues (compile problems) are fixed up and will be going
>> to Linus real soon now, this problem though is something that is being
>> looked at by Matt (i7x05 gart driver author) right now.
>> Hopefully that'll also get fixed up with the changes being readied for 2.5.67
>>
>> The reason i7x05 does things differently is that the generic-3.0 code
>> looks at the devices hanging of the device 0 (in that case, agp gfx cards).
>> I realised last week that the generic code is broken, as every other
>> agp chipset has the agp cards as secondaries of the agp bridge, not the
>> host bridge. Rather than fudge things like this, it looks like a lot
>> of the generic-3.0 stuff will be ripped out. It doesn't really work
>> properly, and is of questionable use.

I've checked Intel E7205 and E7505 spec sheets. But I can not find
why we should use device #1 (virtual agp bridge) instaed of device
#0 (MCH). I rewrite E7x05 agpgart driver to use device #0. It
works fine for me (I tested it on E7505 motherboard with AGPx4
card and AGPx8 card). To use MCH registers (on device #0) is generic
way for Intel agpgart driver, so the driver can merge into intel-agp.c
easyly.

I put the patchset (against current agpgart BK tree)
on the URL. Please test them:

http://hanzubon.jp/agpgart/e7x05-agp-intel-agp-merge-4-1.diff
http://hanzubon.jp/agpgart/e7x05-agp-intel-agp-merge-4-2.diff
http://hanzubon.jp/agpgart/agp_enable_fallback_fix.diff

e7x05-agp-intel-agp-merge-4-1.diff:
main part of the patch to integrate e7x05 support into intel-agp.c

e7x05-agp-intel-agp-merge-4-2.diff:
drop i7505-agp.c and update Kconfig and Makefile.

agp_enable_fallback_fix.diff:
fix agp_generic_enable() function's fall back mehacnism to agp 2.0
mode. It is already sent and merged to dj's tree (thanks :-)
It is not directly related of E7x05 AGP issue, but it is needed to
test the E7x05 driver.

diff -urN linux-2.5.orig/drivers/char/agp/agp.h linux-2.5/drivers/char/agp/agp.h
--- linux-2.5.orig/drivers/char/agp/agp.h 2003-04-03 12:03:14.000000000 +0900
+++ linux-2.5/drivers/char/agp/agp.h 2003-04-03 12:12:11.000000000 +0900
@@ -273,14 +273,8 @@
#define I810_DRAM_ROW_0 0x00000001
#define I810_DRAM_ROW_0_SDRAM 0x00000001

-/* Intel 7505 registers */
-#define INTEL_I7505_NAPBASELO 0x10
-#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
+/* Intel E7205/7505 register */
+#define INTEL_E7X05_MCHCFG 0x50

/* VIA register */
#define VIA_APBASE 0x10
diff -urN linux-2.5.orig/drivers/char/agp/intel-agp.c linux-2.5/drivers/char/agp/intel-agp.c
--- linux-2.5.orig/drivers/char/agp/intel-agp.c 2003-04-03 12:03:17.000000000 +0900
+++ linux-2.5/drivers/char/agp/intel-agp.c 2003-04-03 12:16:30.000000000 +0900
@@ -5,6 +5,11 @@
/*
* Intel(R) 855GM/852GM and 865G support added by David Dawes
* <dawes@tungstengraphics.com>.
+ *
+ * Intel(R) E7205/E7505 support rewrite and added by
+ * ISHIKAWA Mutsumi <ishikawa@debian.org>.
+ * Original auther of the driver is Matthew E Tolentino
+ * <matthew.e.tolentino@intel.com>
*/

#include <linux/module.h>
@@ -647,6 +652,29 @@
return 0;
}

+static int intel_e7x05_fetch_size(void)
+{
+ int i;
+ u16 tmp;
+ struct aper_size_info_16 *values;
+
+ /*
+ * For AGP 3.0 APSIZE is now 16 bits
+ */
+ pci_read_config_word (agp_bridge->dev, INTEL_APSIZE, &tmp);
+ tmp &= 0xfff;
+ values = A_SIZE_16(agp_bridge->aperture_sizes);
+
+ for (i=0; i < agp_bridge->num_aperture_sizes; i++) {
+ if (tmp == 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;
+}
+

static void intel_tlbflush(agp_memory * mem)
{
@@ -960,6 +988,35 @@
return 0;
}

+static int intel_e7x05_configure(void)
+{
+ u32 temp;
+ u16 temp2;
+ struct aper_size_info_16 *current_size;
+
+ current_size = A_SIZE_16(agp_bridge->current_size);
+
+ /* aperture size */
+ pci_write_config_word(agp_bridge->dev, INTEL_APSIZE, current_size->size_value);
+
+ /* address to map to */
+ pci_read_config_dword(agp_bridge->dev, INTEL_APBASE, &temp);
+ agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
+
+ /* attbase */
+ 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);
+
+ /* mcgcfg */
+ pci_read_config_word(agp_bridge->dev, INTEL_E7X05_MCHCFG, &temp2);
+ pci_write_config_word(agp_bridge->dev, INTEL_E7X05_MCHCFG, temp2 | (1 << 9));
+
+ return 0;
+}
+
static unsigned long intel_mask_memory(unsigned long addr, int type)
{
/* Memory type is ignored */
@@ -1246,6 +1303,35 @@
return 0;
}

+static int __init intel_e7x05_setup (struct pci_dev *pdev)
+{
+ agp_bridge->masks = intel_generic_masks;
+ agp_bridge->aperture_sizes = (void *) intel_generic_sizes;
+ agp_bridge->size_type = U16_APER_SIZE;
+ agp_bridge->num_aperture_sizes = 7;
+ agp_bridge->dev_private_data = NULL;
+ agp_bridge->needs_scratch_page = FALSE;
+ agp_bridge->configure = intel_e7x05_configure;
+ agp_bridge->fetch_size = intel_e7x05_fetch_size;
+ agp_bridge->cleanup = intel_cleanup;
+ agp_bridge->tlb_flush = intel_8xx_tlbflush;
+ agp_bridge->mask_memory = intel_mask_memory;
+ agp_bridge->agp_enable = agp_generic_enable;
+ agp_bridge->cache_flush = global_cache_flush;
+ agp_bridge->create_gatt_table = agp_generic_create_gatt_table;
+ agp_bridge->free_gatt_table = agp_generic_free_gatt_table;
+ agp_bridge->insert_memory = agp_generic_insert_memory;
+ agp_bridge->remove_memory = agp_generic_remove_memory;
+ agp_bridge->alloc_by_type = agp_generic_alloc_by_type;
+ agp_bridge->free_by_type = agp_generic_free_by_type;
+ agp_bridge->agp_alloc_page = agp_generic_alloc_page;
+ agp_bridge->agp_destroy_page = agp_generic_destroy_page;
+ agp_bridge->suspend = agp_generic_suspend;
+ agp_bridge->resume = agp_generic_resume;
+ agp_bridge->cant_use_aperture = 0;
+ return 0;
+}
+
struct agp_device_ids intel_agp_device_ids[] __initdata =
{
{
@@ -1329,6 +1415,18 @@
.chipset_name = "865G",
.chipset_setup = intel_845_setup
},
+ {
+ .device_id = PCI_DEVICE_ID_INTEL_7505_0,
+ .chipset = INTEL_E7X05,
+ .chipset_name = "E7505",
+ .chipset_setup = intel_e7x05_setup
+ },
+ {
+ .device_id = PCI_DEVICE_ID_INTEL_7205_0,
+ .chipset = INTEL_E7X05,
+ .chipset_name = "E7205",
+ .chipset_setup = intel_e7x05_setup
+ },
{ }, /* dummy final entry, always present */
};

diff -urN linux-2.5.orig/include/linux/agp_backend.h linux-2.5/include/linux/agp_backend.h
--- linux-2.5.orig/include/linux/agp_backend.h 2003-04-03 12:03:35.000000000 +0900
+++ linux-2.5/include/linux/agp_backend.h 2003-04-03 12:12:11.000000000 +0900
@@ -53,7 +53,7 @@
INTEL_I850,
INTEL_I860,
INTEL_460GX,
- INTEL_I7505,
+ INTEL_E7X05,
VIA_GENERIC,
SIS_GENERIC,
AMD_GENERIC,
diff -urN linux-2.5.orig/drivers/char/agp/Kconfig linux-2.5/drivers/char/agp/Kconfig
--- linux-2.5.orig/drivers/char/agp/Kconfig 2003-04-03 12:03:21.000000000 +0900
+++ linux-2.5/drivers/char/agp/Kconfig 2003-04-03 12:12:11.000000000 +0900
@@ -34,13 +34,14 @@
depends on AGP

config AGP_INTEL
- tristate "Intel 440LX/BX/GX and I815/I820/830M/I830MP/I840/I845/845G/I850/852GM/855GM/I860/865G support"
+ tristate "Intel 440LX/BX/GX and I815/I820/830M/I830MP/I840/I845/845G/I850/852GM/855GM/I860/865G/E7205/E7505 support"
depends on AGP
help
This option gives you AGP support for the GLX component of the
- XFree86 4.x on Intel 440LX/BX/GX, 815, 820, 830, 840, 845, 850
- and 860 chipsets and full support for the 810, 815, 830M, 845G,
- 852GM, 855GM and 865G integrated graphics chipsets.
+ XFree86 4.x on Intel 440LX/BX/GX, 815, 820, 830, 840, 845, 850,
+ 860, E7205 and E7505 chipsets and full support for the 810,
+ 815, 830M, 845G, 852GM, 855GM and 865G integrated graphics
+ chipsets.

You should say Y here if you use XFree86 3.3.6 or 4.x and want to
use GLX or DRI, or if you have any Intel integrated graphics
@@ -138,16 +139,3 @@
tristate
depends on AGP && (ALPHA_GENERIC || ALPHA_TITAN || ALPHA_MARVEL)
default AGP
-
-# Put AGP 3.0 entries below here.
-
-config AGP_I7x05
- tristate "Intel 7205/7505 support (AGP 3.0)"
- depends on AGP3
- help
- This option gives you AGP support for the GLX component of the
- XFree86 4.x on Intel I7505 chipsets.
-
- You should say Y here if you use XFree86 3.3.6 or 4.x and want to
- use GLX or DRI. If unsure, say N
-
diff -urN linux-2.5.orig/drivers/char/agp/Makefile linux-2.5/drivers/char/agp/Makefile
--- linux-2.5.orig/drivers/char/agp/Makefile 2003-04-03 12:03:10.000000000 +0900
+++ linux-2.5/drivers/char/agp/Makefile 2003-04-03 12:12:11.000000000 +0900
@@ -18,6 +18,3 @@
obj-$(CONFIG_AGP_HP_ZX1) += hp-agp.o
obj-$(CONFIG_AGP_AMD_8151) += amd-k8-agp.o
obj-$(CONFIG_AGP_ALPHA_CORE) += alpha-agp.o
-
-obj-$(CONFIG_AGP_I7x05) += i7x05-agp.o
-
diff -urN linux-2.5.orig/drivers/char/agp/i7x05-agp.c linux-2.5/drivers/char/agp/i7x05-agp.c
--- linux-2.5.orig/drivers/char/agp/i7x05-agp.c 2003-04-03 12:03:07.000000000 +0900
+++ linux-2.5/drivers/char/agp/i7x05-agp.c 1970-01-01 09:00:00.000000000 +0900
@@ -1,240 +0,0 @@
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/agp_backend.h>
-#include "agp.h"
-
-static int intel_7505_fetch_size(void)
-{
- int i;
- u16 tmp;
- struct aper_size_info_16 *values;
-
- /*
- * For AGP 3.0 APSIZE is now 16 bits
- */
- pci_read_config_word (agp_bridge->dev, INTEL_I7505_APSIZE, &tmp);
- tmp = (tmp & 0xfff);
-
- values = A_SIZE_16(agp_bridge->aperture_sizes);
-
- for (i=0; i < agp_bridge->num_aperture_sizes; i++) {
- if (tmp == 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;
-}
-
-
-static void intel_7505_tlbflush(agp_memory *mem)
-{
- u32 temp;
- pci_read_config_dword(agp_bridge->dev, INTEL_I7505_AGPCTRL, &temp);
- pci_write_config_dword(agp_bridge->dev, INTEL_I7505_AGPCTRL, temp & ~(1 << 7));
- pci_read_config_dword(agp_bridge->dev, INTEL_I7505_AGPCTRL, &temp);
- pci_write_config_dword(agp_bridge->dev, INTEL_I7505_AGPCTRL, temp | (1 << 7));
-}
-
-static void intel_7505_cleanup(void)
-{
- struct aper_size_info_16 *previous_size;
-
- previous_size = A_SIZE_16(agp_bridge->previous_size);
- pci_write_config_byte(agp_bridge->dev, INTEL_I7505_APSIZE,
- previous_size->size_value);
-}
-
-
-static int intel_7505_configure(void)
-{
- u32 temp;
- struct aper_size_info_16 *current_size;
-
- current_size = A_SIZE_16(agp_bridge->current_size);
-
- /* aperture size */
- pci_write_config_word(agp_bridge->dev, INTEL_I7505_APSIZE,
- current_size->size_value);
-
- /* address to map to */
- pci_read_config_dword(agp_bridge->dev, INTEL_I7505_NAPBASELO, &temp);
- agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
-
- /* attbase */
- pci_write_config_dword(agp_bridge->dev, INTEL_I7505_ATTBASE,
- agp_bridge->gatt_bus_addr);
-
- /* agpctrl */
- pci_write_config_dword(agp_bridge->dev, INTEL_I7505_AGPCTRL, 0x0000);
-
- /* clear error registers */
- pci_write_config_byte(agp_bridge->dev, INTEL_I7505_ERRSTS, 0xff);
- return 0;
-}
-
-static struct aper_size_info_16 intel_7505_sizes[7] =
-{
- {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}
-};
-
-static unsigned long i7x05_mask_memory(unsigned long addr, int type)
-{
- /* Memory type is ignored */
- return addr | agp_bridge->masks[0].mask;
-}
-
-static struct gatt_mask i7x05_generic_masks[] =
-{
- {.mask = 0x00000017, .type = 0}
-};
-
-
-static int __init intel_7505_setup (struct pci_dev *pdev)
-{
- agp_bridge->masks = i7x05_generic_masks;
- agp_bridge->aperture_sizes = (void *) intel_7505_sizes;
- agp_bridge->size_type = U16_APER_SIZE;
- agp_bridge->num_aperture_sizes = 7;
- agp_bridge->dev_private_data = NULL;
- agp_bridge->needs_scratch_page = FALSE;
- agp_bridge->configure = intel_7505_configure;
- agp_bridge->fetch_size = intel_7505_fetch_size;
- agp_bridge->cleanup = intel_7505_cleanup;
- agp_bridge->tlb_flush = intel_7505_tlbflush;
- agp_bridge->mask_memory = i7x05_mask_memory;
- agp_bridge->agp_enable = agp_generic_enable;
- agp_bridge->cache_flush = global_cache_flush;
- agp_bridge->create_gatt_table = agp_generic_create_gatt_table;
- agp_bridge->free_gatt_table = agp_generic_free_gatt_table;
- agp_bridge->insert_memory = agp_generic_insert_memory;
- agp_bridge->remove_memory = agp_generic_remove_memory;
- agp_bridge->alloc_by_type = agp_generic_alloc_by_type;
- agp_bridge->free_by_type = agp_generic_free_by_type;
- agp_bridge->agp_alloc_page = agp_generic_alloc_page;
- agp_bridge->agp_destroy_page = agp_generic_destroy_page;
- agp_bridge->suspend = agp_generic_suspend;
- agp_bridge->resume = agp_generic_resume;
- agp_bridge->cant_use_aperture = 0;
- return 0;
-}
-
-struct agp_device_ids i7x05_agp_device_ids[] __initdata =
-{
- {
- .device_id = PCI_DEVICE_ID_INTEL_7505_0,
- .chipset = INTEL_I7505,
- .chipset_name = "i7505",
- },
- {
- .device_id = PCI_DEVICE_ID_INTEL_7205_0,
- .chipset = INTEL_I7505,
- .chipset_name = "i7205",
- },
- { }, /* dummy final entry, always present */
-};
-
-/* scan table above for supported devices */
-static int __init agp_lookup_host_bridge (struct pci_dev *pdev)
-{
- int j=0;
- struct agp_device_ids *devs;
-
- devs = i7x05_agp_device_ids;
-
- while (devs[j].chipset_name != NULL) {
- if (pdev->device == devs[j].device_id) {
- printk (KERN_INFO PFX "Detected Intel %s chipset\n",
- devs[j].chipset_name);
- agp_bridge->type = devs[j].chipset;
-
- if (devs[j].chipset_setup != NULL)
- return devs[j].chipset_setup(pdev);
- else
- return intel_7505_setup(pdev);
- }
- j++;
- }
-
- printk(KERN_ERR PFX "Unsupported Intel chipset (device id: %04x),",
- pdev->device);
- return -ENODEV;
-}
-
-static struct agp_driver i7x05_agp_driver = {
- .owner = THIS_MODULE,
-};
-
-static int __init agp_i7x05_probe (struct pci_dev *dev, const struct pci_device_id *ent)
-{
- u8 cap_ptr = 0;
-
- cap_ptr = pci_find_capability(dev, PCI_CAP_ID_AGP);
- if (cap_ptr == 0)
- return -ENODEV;
-
- if (agp_lookup_host_bridge(dev) != -ENODEV) {
- agp_bridge->dev = dev;
- agp_bridge->capndx = cap_ptr;
- /* Fill in the mode register */
- pci_read_config_dword(agp_bridge->dev, agp_bridge->capndx+PCI_AGP_STATUS, &agp_bridge->mode);
- i7x05_agp_driver.dev = dev;
- agp_register_driver(&i7x05_agp_driver);
- return 0;
- }
- return -ENODEV;
-}
-
-
-static struct pci_device_id agp_i7x05_pci_table[] __initdata = {
- {
- .class = (PCI_CLASS_BRIDGE_HOST << 8),
- .class_mask = ~0,
- .vendor = PCI_VENDOR_ID_INTEL,
- .device = PCI_ANY_ID,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- },
- { }
-};
-
-MODULE_DEVICE_TABLE(pci, agp_i7x05_pci_table);
-
-static struct __initdata pci_driver agp_i7x05_pci_driver = {
- .name = "agpgart-i7x05",
- .id_table = agp_i7x05_pci_table,
- .probe = agp_i7x05_probe,
-};
-
-int __init agp_i7x05_init(void)
-{
- int ret_val;
-
- ret_val = pci_module_init(&agp_i7x05_pci_driver);
- if (ret_val)
- agp_bridge->type = NOT_SUPPORTED;
-
- return ret_val;
-}
-
-static void __exit agp_i7x05_cleanup(void)
-{
- agp_unregister_driver(&i7x05_agp_driver);
- pci_unregister_driver(&agp_i7x05_pci_driver);
-}
-
-module_init(agp_i7x05_init);
-module_exit(agp_i7x05_cleanup);
-
-MODULE_AUTHOR("Matthew E Tolentino <matthew.e.tolentino@intel.com>");
-MODULE_LICENSE("GPL and additional rights");
-
--- linux-2.5/drivers/char/agp/generic.c.orig 2003-03-27 01:17:44.000000000 +0900
+++ linux-2.5/drivers/char/agp/generic.c 2003-03-27 01:18:45.000000000 +0900
@@ -415,18 +415,15 @@
}
}
#endif
-
- if (major < 3) {
- pci_read_config_dword(agp_bridge->dev,
+ pci_read_config_dword(agp_bridge->dev,
agp_bridge->capndx + PCI_AGP_STATUS, &command);

- command = agp_collect_device_status(mode, command);
- command |= 0x100;
-
- pci_write_config_dword(agp_bridge->dev,
+ command = agp_collect_device_status(mode, command);
+ command |= 0x100;
+
+ pci_write_config_dword(agp_bridge->dev,
agp_bridge->capndx + PCI_AGP_COMMAND, command);
- agp_device_command(command, 0);
- }
+ agp_device_command(command, 0);
}

int agp_generic_create_gatt_table(void)

-- 
ISHIKAWA Mutsumi
 <ishikawa@linux.or.jp>, <ishikawa@debian.org>, <ishikawa@netvillage.co.jp>
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/