From 010b06a16e6bb1c84a92ed34dd410b5769a0b430 Mon Sep 17 00:00:00 2001 From: Jerome Duval Date: Tue, 30 Jul 2013 23:36:47 +0200 Subject: [PATCH] EHCI USB: add MSI support * similar to OHCI support by mmlr. * interrupt handler is removed on destruction. --- src/add-ons/kernel/busses/usb/ehci.cpp | 59 +++++++++++++++++++++++--- src/add-ons/kernel/busses/usb/ehci.h | 4 ++ 2 files changed, 58 insertions(+), 5 deletions(-) diff --git a/src/add-ons/kernel/busses/usb/ehci.cpp b/src/add-ons/kernel/busses/usb/ehci.cpp index 2c6b79b882..c6b7bbdacc 100644 --- a/src/add-ons/kernel/busses/usb/ehci.cpp +++ b/src/add-ons/kernel/busses/usb/ehci.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -19,6 +20,7 @@ #define USB_MODULE_NAME "ehci" pci_module_info *EHCI::sPCIModule = NULL; +pci_x86_module_info *EHCI::sPCIx86Module = NULL; static int32 @@ -142,7 +144,9 @@ EHCI::EHCI(pci_info *info, Stack *stack) fPortCount(0), fPortResetChange(0), fPortSuspendChange(0), - fInterruptPollThread(-1) + fInterruptPollThread(-1), + fIRQ(0), + fUseMSI(false) { // Create a lock for the isochronous transfer list mutex_init(&fIsochronousLock, "EHCI isochronous lock"); @@ -352,16 +356,31 @@ EHCI::EHCI(pci_info *info, Stack *stack) "ehci interrupt poll thread", B_NORMAL_PRIORITY, (void *)this); resume_thread(fInterruptPollThread); } else { + // Find the right interrupt vector, using MSIs if available. + fIRQ = fPCIInfo->u.h0.interrupt_line; + if (sPCIx86Module != NULL && sPCIx86Module->get_msi_count( + fPCIInfo->bus, fPCIInfo->device, fPCIInfo->function) >= 1) { + uint8 msiVector = 0; + if (sPCIx86Module->configure_msi(fPCIInfo->bus, fPCIInfo->device, + fPCIInfo->function, 1, &msiVector) == B_OK + && sPCIx86Module->enable_msi(fPCIInfo->bus, fPCIInfo->device, + fPCIInfo->function) == B_OK) { + TRACE_ALWAYS("using message signaled interrupts\n"); + fIRQ = msiVector; + fUseMSI = true; + } + } + // install the interrupt handler and enable interrupts - install_io_interrupt_handler(fPCIInfo->u.h0.interrupt_line, - InterruptHandler, (void *)this, 0); + install_io_interrupt_handler(fIRQ, InterruptHandler, + (void *)this, 0); } // ensure that interrupts are en-/disabled on the PCI device command = sPCIModule->read_pci_config(fPCIInfo->bus, fPCIInfo->device, fPCIInfo->function, PCI_command, 2); - if (polling == ((command & PCI_command_int_disable) == 0)) { - if (polling) + if ((polling || fUseMSI) == ((command & PCI_command_int_disable) == 0)) { + if (polling || fUseMSI) command &= ~PCI_command_int_disable; else command |= PCI_command_int_disable; @@ -548,6 +567,8 @@ EHCI::~EHCI() if (fInterruptPollThread >= 0) wait_for_thread(fInterruptPollThread, &result); + else + remove_io_interrupt_handler(fIRQ, InterruptHandler, (void *)this); LockIsochronous(); isochronous_transfer_data *isoTransfer = fFirstIsochronousTransfer; @@ -564,7 +585,19 @@ EHCI::~EHCI() delete [] fSitdEntries; delete_area(fPeriodicFrameListArea); delete_area(fRegisterArea); + + if (fUseMSI && sPCIx86Module != NULL) { + sPCIx86Module->disable_msi(fPCIInfo->bus, + fPCIInfo->device, fPCIInfo->function); + sPCIx86Module->unconfigure_msi(fPCIInfo->bus, + fPCIInfo->device, fPCIInfo->function); + } put_module(B_PCI_MODULE_NAME); + + if (sPCIx86Module != NULL) { + sPCIx86Module = NULL; + put_module(B_PCI_X86_MODULE_NAME); + } } @@ -941,6 +974,14 @@ EHCI::AddTo(Stack *stack) return B_NO_MEMORY; } + // Try to get the PCI x86 module as well so we can enable possible MSIs. + if (sPCIx86Module == NULL && get_module(B_PCI_X86_MODULE_NAME, + (module_info **)&sPCIx86Module) != B_OK) { + // If it isn't there, that's not critical though. + TRACE_MODULE_ERROR("failed to get pci x86 module\n"); + sPCIx86Module = NULL; + } + for (int32 i = 0; sPCIModule->get_nth_pci_info(i, item) >= B_OK; i++) { if (item->class_base == PCI_serial_bus && item->class_sub == PCI_usb && item->class_api == PCI_usb_ehci) { @@ -956,6 +997,10 @@ EHCI::AddTo(Stack *stack) delete item; sPCIModule = NULL; put_module(B_PCI_MODULE_NAME); + if (sPCIx86Module != NULL) { + sPCIx86Module = NULL; + put_module(B_PCI_X86_MODULE_NAME); + } return B_NO_MEMORY; } @@ -979,6 +1024,10 @@ EHCI::AddTo(Stack *stack) delete item; sPCIModule = NULL; put_module(B_PCI_MODULE_NAME); + if (sPCIx86Module != NULL) { + sPCIx86Module = NULL; + put_module(B_PCI_X86_MODULE_NAME); + } return ENODEV; } diff --git a/src/add-ons/kernel/busses/usb/ehci.h b/src/add-ons/kernel/busses/usb/ehci.h index 4680e2bc3d..deec069dac 100644 --- a/src/add-ons/kernel/busses/usb/ehci.h +++ b/src/add-ons/kernel/busses/usb/ehci.h @@ -14,6 +14,7 @@ struct pci_info; struct pci_module_info; +struct pci_x86_module_info; class EHCIRootHub; @@ -188,6 +189,7 @@ inline uint16 ReadCapReg16(uint32 reg); inline uint32 ReadCapReg32(uint32 reg); static pci_module_info * sPCIModule; +static pci_x86_module_info * sPCIx86Module; uint8 * fCapabilityRegisters; uint8 * fOperationalRegisters; @@ -243,6 +245,8 @@ static pci_module_info * sPCIModule; // Interrupt polling thread_id fInterruptPollThread; + uint8 fIRQ; + bool fUseMSI; };