summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike A. Harris <mharris@redhat.com>2004-03-11 03:32:55 +0000
committerMike A. Harris <mharris@redhat.com>2004-03-11 03:32:55 +0000
commit5c754ceb009577a62691650dbf7c9d9739f28d2f (patch)
tree9f8034f131c2945aeee13f2f7098d3bcc8cdc5a7
parentec3f00ae3c2b6d521364161674ff5d88e10cc62c (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.c74
-rw-r--r--src/radeon_reg.h7
2 files changed, 63 insertions, 18 deletions
diff --git a/src/radeon_driver.c b/src/radeon_driver.c
index d190a52e..a733f706 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 821a087e..a623b0aa 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)