redo the PCI configuration mode detection - should make some less

standard compliant PCI chipsets work (Compaq, Connectix emulated Triton)
fix the bug reported in PR port-i386/5727 (soda@sra.co.jp)
This commit is contained in:
drochner 1998-07-09 20:19:52 +00:00
parent b5a268eddf
commit d1da31d671

View File

@ -1,4 +1,4 @@
/* $NetBSD: pci_machdep.c,v 1.31 1998/06/03 06:35:49 thorpej Exp $ */ /* $NetBSD: pci_machdep.c,v 1.32 1998/07/09 20:19:52 drochner Exp $ */
/*- /*-
* Copyright (c) 1997, 1998 The NetBSD Foundation, Inc. * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
@ -109,6 +109,28 @@ int pci_mode = -1;
#define PCI_MODE2_ENABLE_REG 0x0cf8 #define PCI_MODE2_ENABLE_REG 0x0cf8
#define PCI_MODE2_FORWARD_REG 0x0cfa #define PCI_MODE2_FORWARD_REG 0x0cfa
#define _m1tag(b, d, f) \
(PCI_MODE1_ENABLE | ((b) << 16) | ((d) << 11) | ((f) << 8))
#define _id(v, p) \
(((v) << PCI_VENDOR_SHIFT) | ((p) << PCI_PRODUCT_SHIFT))
#define _qe(bus, dev, fcn, vend, prod) \
{_m1tag(bus, dev, fcn), _id(vend, prod)}
struct {
u_int32_t tag;
pcireg_t id;
} pcim1_quirk_tbl[] = {
_qe(0, 0, 0, PCI_VENDOR_COMPAQ, PCI_PRODUCT_COMPAQ_TRIFLEX1),
/* XXX Triflex2 not tested */
_qe(0, 0, 0, PCI_VENDOR_COMPAQ, PCI_PRODUCT_COMPAQ_TRIFLEX2),
_qe(0, 0, 0, PCI_VENDOR_COMPAQ, PCI_PRODUCT_COMPAQ_TRIFLEX4),
/* Triton needed for Connectix Virtual PC */
_qe(0, 0, 0, PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82437FX),
{0, 0xffffffff} /* patchable */
};
#undef _m1tag
#undef _id
#undef _qe
/* /*
* PCI doesn't have any special needs; just use the generic versions * PCI doesn't have any special needs; just use the generic versions
* of these functions. * of these functions.
@ -313,6 +335,7 @@ mode1:
outl(PCI_MODE1_ADDRESS_REG, tag.mode1 | reg); outl(PCI_MODE1_ADDRESS_REG, tag.mode1 | reg);
outl(PCI_MODE1_DATA_REG, data); outl(PCI_MODE1_DATA_REG, data);
outl(PCI_MODE1_ADDRESS_REG, 0); outl(PCI_MODE1_ADDRESS_REG, 0);
return;
#endif #endif
#if !defined(PCI_CONF_MODE) || (PCI_CONF_MODE == 2) #if !defined(PCI_CONF_MODE) || (PCI_CONF_MODE == 2)
@ -337,35 +360,79 @@ pci_mode_detect()
#error Invalid PCI configuration mode. #error Invalid PCI configuration mode.
#endif #endif
#else #else
u_int32_t sav, val;
int i;
pcireg_t idreg;
if (pci_mode != -1) if (pci_mode != -1)
return pci_mode; return pci_mode;
/* /*
* We try to divine which configuration mode the host bridge wants. We * We try to divine which configuration mode the host bridge wants.
* try mode 2 first, because our probe for mode 1 is likely to succeed
* for mode 2 also.
*
* XXX
* This should really be done using the PCI BIOS.
*/ */
sav = inl(PCI_MODE1_ADDRESS_REG);
pci_mode = 1; /* assume this for now */
/*
* catch some known buggy implementations of mode 1
*/
for (i = 0; i < sizeof(pcim1_quirk_tbl) / sizeof(pcim1_quirk_tbl[0]);
i++) {
pcitag_t t;
if (!pcim1_quirk_tbl[i].tag)
break;
t.mode1 = pcim1_quirk_tbl[i].tag;
idreg = pci_conf_read(0, t, PCI_ID_REG); /* needs "pci_mode" */
if (idreg == pcim1_quirk_tbl[i].id) {
#ifdef DEBUG
printf("known mode 1 PCI chipset (%08x)\n",
idreg);
#endif
return (pci_mode);
}
}
/*
* Strong check for standard compliant mode 1:
* 1. bit 31 ("enable") can be set
* 2. byte/word access does not affect register
*/
outl(PCI_MODE1_ADDRESS_REG, PCI_MODE1_ENABLE);
outb(PCI_MODE1_ADDRESS_REG + 3, 0);
outw(PCI_MODE1_ADDRESS_REG + 2, 0);
val = inl(PCI_MODE1_ADDRESS_REG);
if ((val & 0x80fffffc) != PCI_MODE1_ENABLE) {
#ifdef DEBUG
printf("pci_mode_detect: mode 1 enable failed (%x)\n",
val);
#endif
goto not1;
}
outl(PCI_MODE1_ADDRESS_REG, 0);
val = inl(PCI_MODE1_ADDRESS_REG);
if ((val & 0x80fffffc) != 0)
goto not1;
return (pci_mode);
not1:
outl(PCI_MODE1_ADDRESS_REG, sav);
/*
* This mode 2 check is quite weak (and known to give false
* positives on some Compaq machines).
* However, this doesn't matter, because this is the
* last test, and simply no PCI devices will be found if
* this happens.
*/
outb(PCI_MODE2_ENABLE_REG, 0); outb(PCI_MODE2_ENABLE_REG, 0);
outb(PCI_MODE2_FORWARD_REG, 0); outb(PCI_MODE2_FORWARD_REG, 0);
if (inb(PCI_MODE2_ENABLE_REG) != 0 || if (inb(PCI_MODE2_ENABLE_REG) != 0 ||
inb(PCI_MODE2_FORWARD_REG) != 0) inb(PCI_MODE2_FORWARD_REG) != 0)
goto not2; goto not2;
return (pci_mode = 2); return (pci_mode = 2);
not2: not2:
outl(PCI_MODE1_ADDRESS_REG, PCI_MODE1_ENABLE);
if (inl(PCI_MODE1_ADDRESS_REG) != PCI_MODE1_ENABLE)
goto not1;
outl(PCI_MODE1_ADDRESS_REG, 0);
if (inl(PCI_MODE1_ADDRESS_REG) != 0)
goto not1;
return (pci_mode = 1);
not1:
return (pci_mode = 0); return (pci_mode = 0);
#endif #endif
} }