Ticket #8085: usbOHCIStartupV2.diff

File usbOHCIStartupV2.diff, 3.2 KB (added by kallisti5, 8 years ago)

better ensure interrupts are disabled on smm takeover in case of reset

  • src/add-ons/kernel/busses/usb/ohci.cpp

    diff --git a/src/add-ons/kernel/busses/usb/ohci.cpp b/src/add-ons/kernel/busses/usb/ohci.cpp
    index c9f2c1a..7123b3b 100644
    a b OHCI::OHCI(pci_info *info, Stack *stack)  
    204204    fInterruptEndpoints[0]->next_physical_endpoint
    205205        = fDummyIsochronous->physical_address;
    206206
    207     // Disable all interrupts before handoff/reset
    208     _WriteReg(OHCI_INTERRUPT_DISABLE, OHCI_ALL_INTERRUPTS);
    209 
    210207    // Determine in what context we are running (Kindly copied from FreeBSD)
    211208    uint32 control = _ReadReg(OHCI_CONTROL);
    212     if (control & OHCI_INTERRUPT_ROUTING) {
     209    if ((control & OHCI_INTERRUPT_ROUTING) != 0) {
     210        // SMM in control, ask for control of USB
    213211        TRACE_ALWAYS("smm is in control of the host controller\n");
    214212        uint32 status = _ReadReg(OHCI_COMMAND_STATUS);
    215213        _WriteReg(OHCI_COMMAND_STATUS, status | OHCI_OWNERSHIP_CHANGE_REQUEST);
    OHCI::OHCI(pci_info *info, Stack *stack)  
    218216            control = _ReadReg(OHCI_CONTROL);
    219217        }
    220218
     219        // Disable all interrupts to prevent interrupt storm
     220        _WriteReg(OHCI_INTERRUPT_DISABLE, OHCI_ALL_INTERRUPTS);
     221
    221222        if ((control & OHCI_INTERRUPT_ROUTING) != 0) {
    222             TRACE_ERROR("smm does not respond. resetting...\n");
     223            TRACE_ERROR("smm is not responding. Resetting...\n");
     224            // Last resort
    223225            _WriteReg(OHCI_CONTROL, OHCI_HC_FUNCTIONAL_STATE_RESET);
    224226            snooze(USB_DELAY_BUS_RESET);
    225         } else
     227        } else {
    226228            TRACE_ALWAYS("ownership change successful\n");
     229        }
    227230    } else {
    228         TRACE("cold started\n");
    229         snooze(USB_DELAY_BUS_RESET);
     231        // SMM *not* in control, resume or reset USB bus
     232
     233        // Disable all interrupts to prevent interrupt storm
     234        _WriteReg(OHCI_INTERRUPT_DISABLE, OHCI_ALL_INTERRUPTS);
     235
     236        control = _ReadReg(OHCI_CONTROL) & OHCI_HC_FUNCTIONAL_STATE_MASK;
     237        if ((control & OHCI_HC_FUNCTIONAL_STATE_RESET) == 0) {
     238            TRACE("no smm, BIOS active. Attempting resume...\n");
     239            if ((control & OHCI_HC_FUNCTIONAL_STATE_OPERATIONAL) == 0) {
     240                _WriteReg(OHCI_CONTROL, OHCI_HC_FUNCTIONAL_STATE_RESUME);
     241                for (uint32 i = 0; i < 100
     242                    && !(control & OHCI_HC_FUNCTIONAL_STATE_RESUME); i++) {
     243                    snooze(1000);
     244                    control = _ReadReg(OHCI_CONTROL)
     245                        & OHCI_HC_FUNCTIONAL_STATE_MASK;
     246                }
     247                if ((control & OHCI_HC_FUNCTIONAL_STATE_RESUME) == 0)
     248                    TRACE_ALWAYS("failed to resume controller\n");
     249            } else {
     250                TRACE_ALWAYS("bus not reset, and not operational?\n");
     251            }
     252        } else {
     253            TRACE("no smm, no BIOS. Attempting reset...\n");
     254
     255            _WriteReg(OHCI_CONTROL, OHCI_HC_FUNCTIONAL_STATE_RESET);
     256            snooze(USB_DELAY_BUS_RESET);
     257            for (uint32 i = 0; i < 100
     258                && !(control & OHCI_HC_FUNCTIONAL_STATE_RESET); i++) {
     259                snooze(1000);
     260                control = _ReadReg(OHCI_CONTROL)
     261                    & OHCI_HC_FUNCTIONAL_STATE_MASK;
     262            }
     263            if ((control & OHCI_HC_FUNCTIONAL_STATE_RESET) == 0)
     264                TRACE_ALWAYS("failed to reset controller\n");
     265        }
    230266    }
    231267
     268    #if 0
    232269    // This reset should not be necessary according to the OHCI spec, but
    233270    // without it some controllers do not start.
    234271    _WriteReg(OHCI_CONTROL, OHCI_HC_FUNCTIONAL_STATE_RESET);
    235272    snooze(USB_DELAY_BUS_RESET);
     273    #endif
    236274
    237275    // We now own the host controller and the bus has been reset
    238276    uint32 frameInterval = _ReadReg(OHCI_FRAME_INTERVAL);