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 <mmlr@mlotz.ch>
This commit is contained in:
Jürgen Wall 2012-10-04 21:17:45 +00:00 committed by Jérôme Duval
parent c530d46cca
commit 3b98be3cc4
1 changed files with 17 additions and 7 deletions

View File

@ -206,8 +206,15 @@ OHCI::OHCI(pci_info *info, Stack *stack)
fInterruptEndpoints[0]->next_physical_endpoint fInterruptEndpoints[0]->next_physical_endpoint
= fDummyIsochronous->physical_address; = fDummyIsochronous->physical_address;
// Disable all interrupts before handoff/reset // When the handover from SMM takes place, all interrupts are routed to the
_WriteReg(OHCI_INTERRUPT_DISABLE, OHCI_ALL_INTERRUPTS); // 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) // Determine in what context we are running (Kindly copied from FreeBSD)
uint32 control = _ReadReg(OHCI_CONTROL); uint32 control = _ReadReg(OHCI_CONTROL);
@ -221,9 +228,12 @@ OHCI::OHCI(pci_info *info, Stack *stack)
} }
if ((control & OHCI_INTERRUPT_ROUTING) != 0) { if ((control & OHCI_INTERRUPT_ROUTING) != 0) {
TRACE_ERROR("smm does not respond. resetting...\n"); TRACE_ERROR("smm does not respond.\n");
_WriteReg(OHCI_CONTROL, OHCI_HC_FUNCTIONAL_STATE_RESET);
snooze(USB_DELAY_BUS_RESET); // 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 } else
TRACE_ALWAYS("ownership change successful\n"); TRACE_ALWAYS("ownership change successful\n");
} else { } else {
@ -231,8 +241,8 @@ OHCI::OHCI(pci_info *info, Stack *stack)
snooze(USB_DELAY_BUS_RESET); snooze(USB_DELAY_BUS_RESET);
} }
// This reset should not be necessary according to the OHCI spec, but // TODO: This reset delays system boot time. It should not be necessary
// without it some controllers do not start. // according to the OHCI spec, but without it some controllers don't start.
_WriteReg(OHCI_CONTROL, OHCI_HC_FUNCTIONAL_STATE_RESET); _WriteReg(OHCI_CONTROL, OHCI_HC_FUNCTIONAL_STATE_RESET);
snooze(USB_DELAY_BUS_RESET); snooze(USB_DELAY_BUS_RESET);