Be paranoid about disabling interrupts and acknowledging any pending
interrupts while attaching uhci. Fixes recent problems with uvm_fault during uhci attach, which appear to be caused by a pending interrupt left over from the device while it was operating in legacy support mode under the control of the BIOS. Patch by joerg@ because his was better than mine.
This commit is contained in:
parent
b79e2bcb32
commit
33bf6486d0
@ -1,4 +1,4 @@
|
|||||||
/* $NetBSD: uhci_pci.c,v 1.37 2007/10/19 12:00:56 ad Exp $ */
|
/* $NetBSD: uhci_pci.c,v 1.38 2007/11/24 02:13:49 gavan Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1998 The NetBSD Foundation, Inc.
|
* Copyright (c) 1998 The NetBSD Foundation, Inc.
|
||||||
@ -38,7 +38,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/cdefs.h>
|
#include <sys/cdefs.h>
|
||||||
__KERNEL_RCSID(0, "$NetBSD: uhci_pci.c,v 1.37 2007/10/19 12:00:56 ad Exp $");
|
__KERNEL_RCSID(0, "$NetBSD: uhci_pci.c,v 1.38 2007/11/24 02:13:49 gavan Exp $");
|
||||||
|
|
||||||
#include "ehci.h"
|
#include "ehci.h"
|
||||||
|
|
||||||
@ -105,6 +105,7 @@ uhci_pci_attach(struct device *parent, struct device *self, void *aux)
|
|||||||
const char *devname = sc->sc.sc_bus.bdev.dv_xname;
|
const char *devname = sc->sc.sc_bus.bdev.dv_xname;
|
||||||
char devinfo[256];
|
char devinfo[256];
|
||||||
usbd_status r;
|
usbd_status r;
|
||||||
|
int s;
|
||||||
|
|
||||||
aprint_naive("\n");
|
aprint_naive("\n");
|
||||||
|
|
||||||
@ -119,8 +120,13 @@ uhci_pci_attach(struct device *parent, struct device *self, void *aux)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Disable interrupts, so we don't get any spurious ones. */
|
/*
|
||||||
|
* Disable interrupts, so we don't get any spurious ones.
|
||||||
|
* Acknolewdge all pending interrupts.
|
||||||
|
*/
|
||||||
bus_space_write_2(sc->sc.iot, sc->sc.ioh, UHCI_INTR, 0);
|
bus_space_write_2(sc->sc.iot, sc->sc.ioh, UHCI_INTR, 0);
|
||||||
|
bus_space_write_2(sc->sc.iot, sc->sc.ioh, UHCI_STS,
|
||||||
|
bus_space_read_2(sc->sc.iot, sc->sc.ioh, UHCI_STS));
|
||||||
|
|
||||||
sc->sc_pc = pc;
|
sc->sc_pc = pc;
|
||||||
sc->sc_tag = tag;
|
sc->sc_tag = tag;
|
||||||
@ -147,8 +153,17 @@ uhci_pci_attach(struct device *parent, struct device *self, void *aux)
|
|||||||
}
|
}
|
||||||
aprint_normal("%s: interrupting at %s\n", devname, intrstr);
|
aprint_normal("%s: interrupting at %s\n", devname, intrstr);
|
||||||
|
|
||||||
/* Set LEGSUP register to its default value. */
|
/*
|
||||||
|
* Set LEGSUP register to its default value.
|
||||||
|
* This can reenable or trigger interrupts, so protect against them
|
||||||
|
* and explicitly disable and ACK them afterwards.
|
||||||
|
*/
|
||||||
|
s = splhardusb();
|
||||||
pci_conf_write(pc, tag, PCI_LEGSUP, PCI_LEGSUP_USBPIRQDEN);
|
pci_conf_write(pc, tag, PCI_LEGSUP, PCI_LEGSUP_USBPIRQDEN);
|
||||||
|
bus_space_write_2(sc->sc.iot, sc->sc.ioh, UHCI_INTR, 0);
|
||||||
|
bus_space_write_2(sc->sc.iot, sc->sc.ioh, UHCI_STS,
|
||||||
|
bus_space_read_2(sc->sc.iot, sc->sc.ioh, UHCI_STS));
|
||||||
|
splx(s);
|
||||||
|
|
||||||
switch(pci_conf_read(pc, tag, PCI_USBREV) & PCI_USBREV_MASK) {
|
switch(pci_conf_read(pc, tag, PCI_USBREV) & PCI_USBREV_MASK) {
|
||||||
case PCI_USBREV_PRE_1_0:
|
case PCI_USBREV_PRE_1_0:
|
||||||
|
Loading…
Reference in New Issue
Block a user