EHCI USB: add MSI support
* similar to OHCI support by mmlr. * interrupt handler is removed on destruction.
This commit is contained in:
committed by
Jérôme Duval
parent
c01fadcadb
commit
010b06a16e
@@ -11,6 +11,7 @@
|
||||
#include <driver_settings.h>
|
||||
#include <module.h>
|
||||
#include <PCI.h>
|
||||
#include <PCI_x86.h>
|
||||
#include <USB3.h>
|
||||
#include <KernelExport.h>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user