diff options
author | Mike A. Harris <mharris@redhat.com> | 2004-03-11 03:32:55 +0000 |
---|---|---|
committer | Mike A. Harris <mharris@redhat.com> | 2004-03-11 03:32:55 +0000 |
commit | 5c754ceb009577a62691650dbf7c9d9739f28d2f (patch) | |
tree | 9f8034f131c2945aeee13f2f7098d3bcc8cdc5a7 | |
parent | ec3f00ae3c2b6d521364161674ff5d88e10cc62c (diff) |
Fixed AGP/PCI card detection in Radeon driver, by walking the PCI
capabilities list in PCI config space (Bugzilla #255) (Mike A. Harris).
-rw-r--r-- | src/radeon_driver.c | 74 | ||||
-rw-r--r-- | src/radeon_reg.h | 7 |
2 files changed, 63 insertions, 18 deletions
diff --git a/src/radeon_driver.c b/src/radeon_driver.c index d190a52..a733f70 100644 --- a/src/radeon_driver.c +++ b/src/radeon_driver.c @@ -2258,27 +2258,65 @@ static Bool RADEONPreInitConfig(ScrnInfoPtr pScrn) #ifdef XF86DRI /* AGP/PCI */ - - /* There are signatures in BIOS and PCI-SSID for a PCI card, but - * they are not very reliable. Following detection method works for - * all cards tested so far. Note, checking AGP_ENABLE bit after - * drmAgpEnable call can also give the correct result. However, - * calling drmAgpEnable on a PCI card can cause some strange lockup - * when the server restarts next time. + /* Proper autodetection of an AGP capable device requires examining + * PCI config registers to determine if the device implements extended + * PCI capabilities, and then walking the capability list as indicated + * in the PCI 2.2 and AGP 2.0 specifications, to determine if AGP + * capability is present. The procedure is outlined as follows: + * + * 1) Test bit 4 (CAP_LIST) of the PCI status register of the device + * to determine wether or not this device implements any extended + * capabilities. If this bit is zero, then the device is a PCI 2.1 + * or earlier device and is not AGP capable, and we can conclude it + * to be a PCI device. + * + * 2) If bit 4 of the status register is set, then the device implements + * extended capabilities. There is an 8 bit wide capabilities pointer + * register located at offset 0x34 in PCI config space which points to + * the first capability in a linked list of extended capabilities that + * this device implements. The lower two bits of this register are + * reserved and MBZ so must be masked out. + * + * 3) The extended capabilities list is formed by one or more extended + * capabilities structures which are aligned on DWORD boundaries. + * The first byte of the structure is the capability ID (CAP_ID) + * indicating what extended capability this structure refers to. The + * second byte of the structure is an offset from the beginning of + * PCI config space pointing to the next capability in the linked + * list (NEXT_PTR) or NULL (0x00) at the end of the list. The lower + * two bits of this pointer are reserved and MBZ. By examining the + * CAP_ID of each capability and walking through the list, we will + * either find the AGP_CAP_ID (0x02) indicating this device is an + * AGP device, or we'll reach the end of the list, indicating it is + * a PCI device. + * + * Mike A. Harris <mharris@redhat.com> + * + * References: + * - PCI Local Bus Specification Revision 2.2, Chapter 6 + * - AGP Interface Specification Revision 2.0, Section 6.1.5 */ - agpCommand = pciReadLong(info->PciTag, RADEON_AGP_COMMAND_PCI_CONFIG); - pciWriteLong(info->PciTag, RADEON_AGP_COMMAND_PCI_CONFIG, - agpCommand | RADEON_AGP_ENABLE); - if (pciReadLong(info->PciTag, RADEON_AGP_COMMAND_PCI_CONFIG) - & RADEON_AGP_ENABLE) { - info->IsPCI = FALSE; - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "AGP card detected\n"); - } else { - info->IsPCI = TRUE; - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "PCI card detected\n"); + info->IsPCI = TRUE; + + if (pciReadWord(info->PciTag, RADEON_STATUS_PCI_CONFIG) & RADEON_CAP_LIST) { + CARD8 cap_ptr, cap_id; + + cap_ptr = pciReadByte(info->PciTag, RADEON_CAPABILITIES_PTR_PCI_CONFIG) & RADEON_CAP_PTR_MASK; + + while(cap_ptr != RADEON_CAP_ID_NULL) { + cap_id = pciReadByte(info->PciTag, cap_ptr); + if (cap_id == RADEON_CAP_ID_AGP) { + info->IsPCI = FALSE; + break; + } else { + cap_ptr = pciReadByte(info->PciTag, cap_ptr + 1) & RADEON_CAP_PTR_MASK; + } + } } - pciWriteLong(info->PciTag, RADEON_AGP_COMMAND_PCI_CONFIG, agpCommand); + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "%s card detected\n", + (info->IsPCI) ? "PCI" : "AGP"); if ((s = xf86GetOptValString(info->Options, OPTION_BUS_TYPE))) { if (strcmp(s, "AGP") == 0) { diff --git a/src/radeon_reg.h b/src/radeon_reg.h index 821a087..a623b0a 100644 --- a/src/radeon_reg.h +++ b/src/radeon_reg.h @@ -65,6 +65,13 @@ # define RADEON_AGP_APER_SIZE_8MB (0x3e << 0) # define RADEON_AGP_APER_SIZE_4MB (0x3f << 0) # define RADEON_AGP_APER_SIZE_MASK (0x3f << 0) +#define RADEON_STATUS_PCI_CONFIG 0x06 +# define RADEON_CAP_LIST 0x10 +#define RADEON_CAPABILITIES_PTR 0x0f34 /* PCI */ +#define RADEON_CAPABILITIES_PTR_PCI_CONFIG 0x34 /* offset in PCI config*/ +# define RADEON_CAP_PTR_MASK 0xfc /* mask off reserved bits of CAP_PTR */ +# define RADEON_CAP_ID_NULL 0x00 /* End of capability list */ +# define RADEON_CAP_ID_AGP 0x02 /* AGP capability ID */ #define RADEON_AGP_COMMAND 0x0f60 /* PCI */ #define RADEON_AGP_COMMAND_PCI_CONFIG 0x0060 /* offset in PCI config*/ # define RADEON_AGP_ENABLE (1<<8) |