diff --git a/src/add-ons/kernel/busses/usb/uhci.cpp b/src/add-ons/kernel/busses/usb/uhci.cpp index 7463fb5d5b..42b898a3fa 100644 --- a/src/add-ons/kernel/busses/usb/uhci.cpp +++ b/src/add-ons/kernel/busses/usb/uhci.cpp @@ -10,6 +10,7 @@ #include #include +#include #include #include @@ -18,6 +19,7 @@ #define USB_MODULE_NAME "uhci" pci_module_info *UHCI::sPCIModule = NULL; +pci_x86_module_info *UHCI::sPCIx86Module = NULL; static int32 sDebuggerCommandAdded = 0; @@ -404,7 +406,9 @@ UHCI::UHCI(pci_info *info, Stack *stack) fFinishIsochronousThread(-1), fRootHub(NULL), fRootHubAddress(0), - fPortResetChange(0) + fPortResetChange(0), + fIRQ(0), + fUseMSI(false) { // Create a lock for the isochronous transfer list mutex_init(&fIsochronousLock, "UHCI isochronous lock"); @@ -557,10 +561,24 @@ UHCI::UHCI(pci_info *info, Stack *stack) (void *)this); resume_thread(fFinishIsochronousThread); + // 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 TRACE("installing interrupt handler\n"); - install_io_interrupt_handler(fPCIInfo->u.h0.interrupt_line, - InterruptHandler, (void *)this, 0); + install_io_interrupt_handler(fIRQ, InterruptHandler, (void *)this, 0); // Enable interrupts fEnabledInterrupts = UHCI_USBSTS_USBINT | UHCI_USBSTS_ERRINT @@ -599,6 +617,8 @@ UHCI::~UHCI() wait_for_thread(fCleanupThread, &result); wait_for_thread(fFinishIsochronousThread, &result); + remove_io_interrupt_handler(fIRQ, InterruptHandler, (void *)this); + LockIsochronous(); isochronous_transfer_data *isoTransfer = fFirstIsochronousTransfer; while (isoTransfer) { @@ -629,7 +649,17 @@ UHCI::~UHCI() delete fRootHub; delete_area(fFrameArea); + 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); + } Unlock(); } diff --git a/src/add-ons/kernel/busses/usb/uhci.h b/src/add-ons/kernel/busses/usb/uhci.h index a0c2b892de..f5fbb78d8d 100644 --- a/src/add-ons/kernel/busses/usb/uhci.h +++ b/src/add-ons/kernel/busses/usb/uhci.h @@ -23,6 +23,7 @@ struct pci_info; struct pci_module_info; +struct pci_x86_module_info; class UHCIRootHub; class DebugTransfer; @@ -208,6 +209,7 @@ inline uint16 ReadReg16(uint32 reg); inline uint32 ReadReg32(uint32 reg); static pci_module_info * sPCIModule; +static pci_x86_module_info * sPCIx86Module; uint32 fRegisterBase; pci_info * fPCIInfo; @@ -256,6 +258,9 @@ static pci_module_info * sPCIModule; UHCIRootHub * fRootHub; uint8 fRootHubAddress; uint8 fPortResetChange; + + uint8 fIRQ; + bool fUseMSI; };