summaryrefslogtreecommitdiffstats
path: root/sys/dev/pci
diff options
context:
space:
mode:
authorse <se@FreeBSD.org>1996-01-30 01:14:29 +0000
committerse <se@FreeBSD.org>1996-01-30 01:14:29 +0000
commit42c5ea8f892c16aa6049850dce80b04b6e632d6a (patch)
treec22adbf3a2f4ca81cdb0e8e82f2ab5353714c17c /sys/dev/pci
parent0d925cfda358e9042c94c2db98bcdcba43830080 (diff)
downloadFreeBSD-src-42c5ea8f892c16aa6049850dce80b04b6e632d6a.zip
FreeBSD-src-42c5ea8f892c16aa6049850dce80b04b6e632d6a.tar.gz
Add heuristic to detect multi-function devices that don't announce this
feature in the header type register, though it is required by the PCI spec. This should correctly probe both functions of the Intel 82371FB chip, without the need for a special case based on the device ID.
Diffstat (limited to 'sys/dev/pci')
-rw-r--r--sys/dev/pci/pci.c113
1 files changed, 79 insertions, 34 deletions
diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c
index 9f2b0e0..d34c99e 100644
--- a/sys/dev/pci/pci.c
+++ b/sys/dev/pci/pci.c
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** $Id: pci.c,v 1.42 1996/01/25 18:31:58 se Exp $
+** $Id: pci.c,v 1.43 1996/01/27 20:14:31 wollman Exp $
**
** General subroutines for the PCI bus.
** pci_configure ()
@@ -122,9 +122,12 @@ not_supported (pcici_t tag, u_long type);
static void
pci_bus_config (void);
-static void
+static int
pci_bridge_config (void);
+static int
+pci_mfdev (int bus, int device);
+
/*========================================================
**
** Variables
@@ -344,28 +347,69 @@ done:
**========================================================
*/
+static int
+pci_mfdev (int bus, int device)
+{
+ pcici_t tag0,tag1;
+ int pci_id0, pci_id1;
+
+ /*
+ ** Detect a multi-function device that complies to the PCI 2.0 spec
+ */
+ tag0 = pcibus->pb_tag (bus, device, 0);
+ if (pcibus->pb_read (tag0, PCI_HEADER_MISC) & PCI_HEADER_MULTIFUNCTION)
+ return 1;
+
+ /*
+ ** Well, as always: Theory and implementation of PCI ...
+ **
+ ** If there is a valid device ID returned for function 1 AND
+ ** the device ID of function 0 and 1 is different OR
+ ** the first mapping register of 0 and 1 differs,
+ ** then assume a multi-function device anyway ...
+ **
+ ** Example of such a broken device: ISA and IDE chip i83371FB (Triton)
+ */
+ tag1 = pcibus->pb_tag (bus, device, 1);
+ pci_id1 = pcibus->pb_read (tag1, PCI_ID_REG);
+
+ if (pci_id1 != 0xffffffff) {
+
+ pci_id0 = pcibus->pb_read (tag0, PCI_ID_REG);
+
+ if (pci_id0 != pci_id1)
+ return 1;
+
+ if (pcibus->pb_read (tag0, PCI_MAP_REG_START)
+ != pcibus->pb_read (tag1, PCI_MAP_REG_START))
+ return 1;
+ }
+ return 0;
+}
+
static void
pci_bus_config (void)
{
+ int bus_no;
u_char device;
u_char reg;
pcici_t tag, mtag;
pcidi_t type;
u_long data;
int unit;
- int pciint;
- int irq;
+ u_char pciint;
+ u_char irq;
- struct pci_device *dvp;
+ struct pci_device *dvp;
- struct pci_devconf *pdcp;
+ struct pci_devconf *pdcp;
/*
** first initialize the bridge (bus controller chip)
*/
- pci_bridge_config ();
+ bus_no = pci_bridge_config ();
- printf ("Probing for devices on PCI bus %d:\n", pcicb->pcicb_bus);
+ printf ("Probing for devices on PCI bus %d:\n", bus_no);
#ifndef PCI_QUIET
if (bootverbose && !pci_info_done) {
pci_info_done=1;
@@ -382,7 +426,7 @@ pci_bus_config (void)
continue;
for (func=0; func <= maxfunc; func++) {
- tag = pcibus->pb_tag (pcicb->pcicb_bus, device, func);
+ tag = pcibus->pb_tag (bus_no, device, func);
type = pcibus->pb_read (tag, PCI_ID_REG);
if ((!type) || (type==0xfffffffful)) continue;
@@ -406,10 +450,10 @@ pci_bus_config (void)
goto real_device;
}
if (device & 0x10) {
- mtag=pcibus->pb_tag (pcicb->pcicb_bus,
+ mtag=pcibus->pb_tag (bus_no,
(u_char)(device & ~0x10), 0);
} else if (device & 0x08) {
- mtag=pcibus->pb_tag (pcicb->pcicb_bus,
+ mtag=pcibus->pb_tag (bus_no,
(u_char)(device & ~0x08), 0);
} else goto real_device;
@@ -424,21 +468,21 @@ pci_bus_config (void)
if (dvp==NULL) continue;
if (bootverbose)
printf ("%s? <%s> mirrored on pci%d:%d\n",
- dvp->pd_name, name, pcicb->pcicb_bus, device);
+ dvp->pd_name, name, bus_no, device);
#endif
continue;
real_device:
- /*
- * Ack. The Triton PIIX doesn't correctly set
- * the multifunction bit. Fake it.
- */
- if (type == 0x122e8086) {
- maxfunc = 1;
+
+ if (bootverbose) {
+ printf ("\tconfig header: 0x%08x 0x%08x 0x%08x 0x%08x\n",
+ pci_conf_read (tag, 0),
+ pci_conf_read (tag, 4),
+ pci_conf_read (tag, 8),
+ pci_conf_read (tag, 12));
}
- if (func == 0 && (pcibus->pb_read (tag, PCI_HEADER_MISC)
- & PCI_HEADER_MULTIFUNCTION)) {
+ if (func == 0 && pci_mfdev (bus_no, device)) {
maxfunc = 7;
}
@@ -446,8 +490,7 @@ pci_bus_config (void)
#ifndef PCI_QUIET
if (pci_conf_count)
continue;
- printf("%s%d:%d: ", pcibus->pb_name,
- pcicb->pcicb_bus, device);
+ printf("%s%d:%d: ", pcibus->pb_name, bus_no, device);
not_supported (tag, type);
#endif
continue;
@@ -493,13 +536,13 @@ pci_bus_config (void)
** and we cannot bind the pci interrupt.
*/
- if (irq)
+ if (irq && (irq != 0xff))
printf ("%d", irq);
else
printf ("??");
};
- printf (" on pci%d:%d\n", pcicb->pcicb_bus, device);
+ printf (" on pci%d:%d\n", bus_no, device);
/*
** Read the current mapping,
@@ -566,7 +609,7 @@ pci_bus_config (void)
malloc (sizeof (struct pci_devconf),M_DEVBUF,M_WAITOK);
bzero(pdcp, sizeof(struct pci_devconf));
- pdcp -> pdc_pi.pi_bus = pcicb->pcicb_bus;
+ pdcp -> pdc_pi.pi_bus = bus_no;
pdcp -> pdc_pi.pi_device = device;
pdcp -> pdc_pi.pi_func = func;
@@ -632,7 +675,7 @@ pci_bus_config (void)
** check for uninitialized bridge.
*/
if (secondary == 0 || secondary < primary ||
- pcicb->pcicb_bus != primary)
+ bus_no != primary)
{
printf ("\tINCORRECTLY or NEVER CONFIGURED.\n");
/*
@@ -776,17 +819,17 @@ pci_bus_config (void)
if (bootverbose) {
if (pcicb->pcicb_mamount)
printf ("%s%d: uses %d bytes of memory from %x upto %x.\n",
- pcibus->pb_name, pcicb->pcicb_bus,
+ pcibus->pb_name, bus_no,
pcicb->pcicb_mamount,
pcicb->pcicb_mfrom, pcicb->pcicb_mupto);
if (pcicb->pcicb_pamount)
printf ("%s%d: uses %d bytes of I/O space from %x upto %x.\n",
- pcibus->pb_name, pcicb->pcicb_bus,
+ pcibus->pb_name, bus_no,
pcicb->pcicb_pamount,
pcicb->pcicb_pfrom, pcicb->pcicb_pupto);
if (pcicb->pcicb_bfrom)
printf ("%s%d: subordinate busses from %x upto %x.\n",
- pcibus->pb_name, pcicb->pcicb_bus,
+ pcibus->pb_name, bus_no,
pcicb->pcicb_bfrom, pcicb->pcicb_bupto);
}
#endif
@@ -801,16 +844,16 @@ pci_bus_config (void)
**========================================================
*/
-static void
+static int
pci_bridge_config (void)
{
pcici_t tag;
struct pcicb* parent;
tag = pcicb->pcicb_bridge;
- if (!tag.tag) return;
+ if (tag.tag) {
- if (!pcicb->pcicb_bus) {
+ if (!pcicb->pcicb_bus) {
u_int data;
/*
** Get the lowest available bus number.
@@ -844,14 +887,16 @@ pci_bridge_config (void)
pci_conf_write (parent->pcicb_bridge,
PCI_PCI_BRIDGE_BUS_REG, data);
}
- }
+ }
- if (!pcicb->pcicb_membase) {
+ if (!pcicb->pcicb_membase) {
u_int size = 0x100000;
pcicb->pcicb_membase = pci_memalloc (pcicb->pcicb_up, 0, size);
if (pcicb->pcicb_membase)
pcicb->pcicb_memlimit = pcicb->pcicb_membase+size-1;
+ }
}
+ return pcicb->pcicb_bus;
}
/*-----------------------------------------------------------------
OpenPOWER on IntegriCloud