From 3b98be3cc44741c04fefddc14d7b34a7735468a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Wall?= Date: Thu, 4 Oct 2012 21:17:45 +0000 Subject: [PATCH] USB OHCI: Fix ownership handover from SMM to OS. * Disabling all interrupts prior to ownership handover from SMM to OS can prevent propper OHCI and PS/2 functionality as described in #8987 and #8984. In that case SMM does not respond to the ownership change request. On the other hand not disabling the interrupts can lead to interrupt storms (discussed in #8085) since no interrupt handler is installed at that moment. As suggested by mmlr this patch attempts to address both issues by keeping the ownership change request interrupt enabled. * Removed an unnecessary reset upon non-responding SMM for now, since we reset a few lines later anyway and added TODOs respectively. That should safe a bit boot time. Signed-off-by: Michael Lotz --- src/add-ons/kernel/busses/usb/ohci.cpp | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/src/add-ons/kernel/busses/usb/ohci.cpp b/src/add-ons/kernel/busses/usb/ohci.cpp index df38174c20..73bc7692a1 100644 --- a/src/add-ons/kernel/busses/usb/ohci.cpp +++ b/src/add-ons/kernel/busses/usb/ohci.cpp @@ -206,8 +206,15 @@ OHCI::OHCI(pci_info *info, Stack *stack) fInterruptEndpoints[0]->next_physical_endpoint = fDummyIsochronous->physical_address; - // Disable all interrupts before handoff/reset - _WriteReg(OHCI_INTERRUPT_DISABLE, OHCI_ALL_INTERRUPTS); + // When the handover from SMM takes place, all interrupts are routed to the + // OS. As we don't yet have an interrupt handler installed at this point, + // this may cause interrupt storms if the firmware does not disable the + // interrupts during handover. Therefore we disable interrupts before + // requesting ownership. We have to keep the ownership change interrupt + // enabled though, as otherwise the SMM will not be notified of the + // ownership change request we trigger below. + _WriteReg(OHCI_INTERRUPT_DISABLE, OHCI_ALL_INTERRUPTS & + ~OHCI_OWNERSHIP_CHANGE) ; // Determine in what context we are running (Kindly copied from FreeBSD) uint32 control = _ReadReg(OHCI_CONTROL); @@ -221,9 +228,12 @@ OHCI::OHCI(pci_info *info, Stack *stack) } if ((control & OHCI_INTERRUPT_ROUTING) != 0) { - TRACE_ERROR("smm does not respond. resetting...\n"); - _WriteReg(OHCI_CONTROL, OHCI_HC_FUNCTIONAL_STATE_RESET); - snooze(USB_DELAY_BUS_RESET); + TRACE_ERROR("smm does not respond.\n"); + + // TODO: Enable this reset as soon as the non-specified + // reset a few lines later is replaced by a better solution. + //_WriteReg(OHCI_CONTROL, OHCI_HC_FUNCTIONAL_STATE_RESET); + //snooze(USB_DELAY_BUS_RESET); } else TRACE_ALWAYS("ownership change successful\n"); } else { @@ -231,8 +241,8 @@ OHCI::OHCI(pci_info *info, Stack *stack) snooze(USB_DELAY_BUS_RESET); } - // This reset should not be necessary according to the OHCI spec, but - // without it some controllers do not start. + // TODO: This reset delays system boot time. It should not be necessary + // according to the OHCI spec, but without it some controllers don't start. _WriteReg(OHCI_CONTROL, OHCI_HC_FUNCTIONAL_STATE_RESET); snooze(USB_DELAY_BUS_RESET);