diff --git a/src/add-ons/kernel/busses/scsi/ahci/ahci.c b/src/add-ons/kernel/busses/scsi/ahci/ahci.c index 761355b1d6..89327a373d 100644 --- a/src/add-ons/kernel/busses/scsi/ahci/ahci.c +++ b/src/add-ons/kernel/busses/scsi/ahci/ahci.c @@ -142,6 +142,7 @@ const device_info kSupportedDevices[] = { device_manager_info *gDeviceManager; scsi_for_sim_interface *gSCSI; +pci_x86_module_info* gPCIx86Module; status_t @@ -328,7 +329,17 @@ std_ops(int32 op, ...) { switch (op) { case B_MODULE_INIT: + if (get_module(B_PCI_X86_MODULE_NAME, + (module_info**)&gPCIx86Module) != B_OK) { + TRACE("failed to get pci x86 module\n"); + gPCIx86Module = NULL; + } + return B_OK; case B_MODULE_UNINIT: + if (gPCIx86Module != NULL) { + put_module(B_PCI_X86_MODULE_NAME); + gPCIx86Module = NULL; + } return B_OK; default: diff --git a/src/add-ons/kernel/busses/scsi/ahci/ahci_controller.cpp b/src/add-ons/kernel/busses/scsi/ahci/ahci_controller.cpp index b5ed575812..c7295f909c 100644 --- a/src/add-ons/kernel/busses/scsi/ahci/ahci_controller.cpp +++ b/src/add-ons/kernel/busses/scsi/ahci/ahci_controller.cpp @@ -29,6 +29,7 @@ AHCIController::AHCIController(device_node *node, fPortCount(0), fPortImplementedMask(0), fIRQ(0), + fUseMSI(false), fInstanceCheck(-1) { memset(fPort, 0, sizeof(fPort)); @@ -101,6 +102,20 @@ AHCIController::Init() } fIRQ = pciInfo.u.h0.interrupt_line; + if (gPCIx86Module != NULL && gPCIx86Module->get_msi_count( + pciInfo.bus, pciInfo.device, pciInfo.function) >= 1) { + uint8 vector; + if (gPCIx86Module->configure_msi(pciInfo.bus, pciInfo.device, + pciInfo.function, 1, &vector) == B_OK + && gPCIx86Module->enable_msi(pciInfo.bus, pciInfo.device, + pciInfo.function) == B_OK) { + TRACE("using MSI vector %u\n", vector); + fIRQ = vector; + fUseMSI = true; + } else { + TRACE("couldn't use MSI\n"); + } + } if (fIRQ == 0 || fIRQ == 0xff) { TRACE("Error: PCI IRQ not assigned\n"); return B_ERROR; @@ -250,6 +265,15 @@ AHCIController::Uninit() // well... remove_io_interrupt_handler(fIRQ, Interrupt, this); + if (fUseMSI && gPCIx86Module != NULL) { + pci_info pciInfo; + fPCI->get_pci_info(fPCIDevice, &pciInfo); + gPCIx86Module->disable_msi(pciInfo.bus, + pciInfo.device, pciInfo.function); + gPCIx86Module->unconfigure_msi(pciInfo.bus, + pciInfo.device, pciInfo.function); + } + delete_area(fRegsArea); // --- Instance check workaround begin diff --git a/src/add-ons/kernel/busses/scsi/ahci/ahci_controller.h b/src/add-ons/kernel/busses/scsi/ahci/ahci_controller.h index c973d41cb6..ccbba641f5 100644 --- a/src/add-ons/kernel/busses/scsi/ahci/ahci_controller.h +++ b/src/add-ons/kernel/busses/scsi/ahci/ahci_controller.h @@ -52,6 +52,7 @@ private: int fPortCount; uint32 fPortImplementedMask; uint8 fIRQ; + bool fUseMSI; AHCIPort * fPort[32]; // --- Instance check workaround begin diff --git a/src/add-ons/kernel/busses/scsi/ahci/ahci_defs.h b/src/add-ons/kernel/busses/scsi/ahci/ahci_defs.h index ebe1757f9d..7599abdf4d 100644 --- a/src/add-ons/kernel/busses/scsi/ahci/ahci_defs.h +++ b/src/add-ons/kernel/busses/scsi/ahci/ahci_defs.h @@ -7,6 +7,7 @@ #include #include +#include #ifdef __cplusplus extern "C" { @@ -259,6 +260,7 @@ status_t get_device_info(uint16 vendorID, uint16 deviceID, const char **name, extern scsi_sim_interface gAHCISimInterface; extern device_manager_info *gDeviceManager; extern scsi_for_sim_interface *gSCSI; +extern pci_x86_module_info* gPCIx86Module; #define MAX_SECTOR_LBA_28 ((1ull << 28) - 1)