1
0
mirror of https://git.FreeBSD.org/src.git synced 2024-12-17 10:26:15 +00:00

Add a workaround for quirky PCI devices that set the intpin register to

0, but use this mechanism to generate interrupts.
Preserve the child device when setting up and tearing down interrupts.
Some style nits.
This commit is contained in:
Thomas Moestl 2001-12-21 21:35:47 +00:00
parent 279367f3ce
commit 70527a680b
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=88371

View File

@ -805,6 +805,28 @@ psycho_maxslots(device_t dev)
return (31);
}
/*
* Keep a table of quirky PCI devices that need fixups before the MI PCI code
* creates the resource lists. This needs to be moved around once other bus
* drivers are added. Moving it to the MI code should maybe be reconsidered
* if one of these devices appear in non-sparc64 boxen. It's likely that not
* all BIOSes/firmwares can deal with them.
*/
struct psycho_dquirk {
u_int32_t dq_devid;
int dq_quirk;
};
/* Quirk types. May be or'ed together. */
#define DQT_BAD_INTPIN 1 /* Intpin reg 0, but intpin used */
static struct psycho_dquirk dquirks[] = {
{ 0x1001108e, DQT_BAD_INTPIN }, /* Sun HME (PCIO func. 1) */
{ 0x1101108e, DQT_BAD_INTPIN }, /* Sun GEM (PCIO2 func. 1) */
};
#define NDQUIRKS (sizeof(dquirks) / sizeof(dquirks[0]))
static u_int32_t
psycho_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg,
int width)
@ -812,15 +834,17 @@ psycho_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg,
struct psycho_softc *sc;
bus_space_handle_t bh;
u_long offset = 0;
u_int32_t r;
u_int32_t r, devid;
int i;
/*
* The psycho bridge does not tolerate accesses to unconfigured PCI
* devices' or function's config space, so look up the device in the
* first, and if it is not present, return a value that will make the
* detection think that there is no device here. This is somehow ugly...
* firmware device tree first, and if it is not present, return a value
* that will make the detection code think that there is no device here.
* This is ugly...
*/
if (ofw_pci_find_node(bus, slot, func) == 0)
if (reg == 0 && ofw_pci_find_node(bus, slot, func) == 0)
return (0xffffffff);
sc = (struct psycho_softc *)device_get_softc(dev);
offset = PSYCHO_CONF_OFF(bus, slot, func, reg);
@ -838,6 +862,27 @@ psycho_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg,
default:
panic("psycho_read_config: bad width");
}
if (reg == PCIR_INTPIN && r == 0) {
/* Check for DQT_BAD_INTPIN quirk. */
devid = psycho_read_config(dev, bus, slot, func,
PCIR_DEVVENDOR, 4);
for (i = 0; i < NDQUIRKS; i++) {
if (dquirks[i].dq_devid == devid) {
/*
* Need to set the intpin to a value != 0 so
* that the MI code will think that this device
* has an interrupt.
* Just use 1 (intpin a) for now. This is, of
* course, bogus, but since interrupts are
* routed in advance, this does not really
* matter.
*/
if ((dquirks[i].dq_quirk & DQT_BAD_INTPIN) != 0)
r = 1;
break;
}
}
}
return (r);
}
@ -964,8 +1009,8 @@ psycho_setup_intr(device_t dev, device_t child,
/* Disable the interrupt while we fiddle with it */
*intrmapptr &= ~INTMAP_V;
membar(Sync);
error = bus_setup_intr(dev, ires, flags, psycho_intr_stub, pc,
cookiep);
error = BUS_SETUP_INTR(device_get_parent(dev), child, ires, flags,
psycho_intr_stub, pc, cookiep);
if (error != 0) {
free(pc, M_DEVBUF);
return (error);
@ -996,7 +1041,8 @@ psycho_teardown_intr(device_t dev, device_t child,
int error;
pc = (struct psycho_clr *)cookie;
error = bus_teardown_intr(dev, vec, pc->pci_cookie);
error = BUS_TEARDOWN_INTR(device_get_parent(dev), child, vec,
pc->pci_cookie);
/*
* Don't disable the interrupt for now, so that stray interupts get
* detected...