From 4f733fe93bda89631a901a417e0cbca1b00b97c0 Mon Sep 17 00:00:00 2001 From: Marcus Overhagen Date: Sat, 1 Sep 2007 19:54:45 +0000 Subject: [PATCH] added Interrupt handling framework git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@22145 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../busses/scsi/ahci/ahci_controller.cpp | 48 ++++++++++++++++--- .../kernel/busses/scsi/ahci/ahci_controller.h | 3 ++ .../kernel/busses/scsi/ahci/ahci_port.cpp | 7 +++ .../kernel/busses/scsi/ahci/ahci_port.h | 2 + 4 files changed, 54 insertions(+), 6 deletions(-) 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 3420406daf..f2e5ec7228 100644 --- a/src/add-ons/kernel/busses/scsi/ahci/ahci_controller.cpp +++ b/src/add-ons/kernel/busses/scsi/ahci/ahci_controller.cpp @@ -24,6 +24,7 @@ AHCIController::AHCIController(device_node_handle node, pci_device_info *device) , fCommandSlotCount(0) , fPortCount(0) , fPortMax(0) + , fIRQ(0) , fInstanceCheck(-1) { memset(fPorts, 0, sizeof(fPorts)); @@ -100,6 +101,12 @@ AHCIController::Init() while ((fRegs->pi & (1 << fPortMax)) == 0) fPortMax--; + fIRQ = gPCI->read_pci_config(fPCIDevice, PCI_interrupt_line, 1); + if (fIRQ == 0 || fIRQ == 0xff) { + TRACE("no IRQ assigned\n"); + goto err; + } + TRACE("cap: Interface Speed Support: generation %lu\n", (fRegs->cap >> CAP_ISS_SHIFT) & CAP_ISS_MASK); TRACE("cap: Number of Command Slots: %d (raw %#lx)\n", fCommandSlotCount, (fRegs->cap >> CAP_NCS_SHIFT) & CAP_NCS_MASK); TRACE("cap: Number of Ports: %d (raw %#lx)\n", fPortCount, (fRegs->cap >> CAP_NCS_SHIFT) & CAP_NCS_MASK); @@ -118,7 +125,13 @@ AHCIController::Init() TRACE("Ports Implemented: %08lx\n", fRegs->pi); TRACE("Highest port Number: %d\n", fPortMax); TRACE("AHCI Version %lu.%lu\n", fRegs->vs >> 16, fRegs->vs & 0xff); + TRACE("Interrupt %u\n", fIRQ); + // setup interrupt handler + if (install_io_interrupt_handler(fIRQ, Interrupt, this, 0) < B_OK) { + TRACE("can't install interrupt handler\n"); + goto err; + } for (int i = 0; i <= fPortMax; i++) { if (fRegs->pi & (1 << i)) { @@ -137,12 +150,6 @@ AHCIController::Init() } } - // disable interrupts - fRegs->ghc &= ~GHC_IE; - // clear pending interrupts - fRegs->is = 0xffffffff; - - return B_OK; err: @@ -168,6 +175,10 @@ AHCIController::Uninit() // clear pending interrupts fRegs->is = 0xffffffff; + // well... + remove_io_interrupt_handler(fIRQ, Interrupt, this); + + delete_area(fRegsArea); // --- Instance check workaround begin @@ -208,6 +219,31 @@ AHCIController::ResetController() } +int32 +AHCIController::Interrupt(void *data) +{ + AHCIController *self = (AHCIController *)data; + uint32 int_stat = self->fRegs->is & self->fRegs->pi; + if (int_stat == 0) + return B_UNHANDLED_INTERRUPT; + + for (int i = 0; i < self->fPortMax; i++) { + if (int_stat & (1 << i)) { + if (self->fPorts[i]) { + self->fPorts[i]->Interrupt(); + } else { + FLOW("interrupt on non-existent port %d\n", i); + } + } + } + + // clear interrupts + self->fRegs->is = int_stat; + + return B_INVOKE_SCHEDULER; +} + + void AHCIController::ExecuteRequest(scsi_ccb *request) { 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 d9e3cbdbad..92d30c86f4 100644 --- a/src/add-ons/kernel/busses/scsi/ahci/ahci_controller.h +++ b/src/add-ons/kernel/busses/scsi/ahci/ahci_controller.h @@ -31,6 +31,8 @@ private: status_t ResetController(); void RegsFlush(); +static int32 Interrupt(void *data); + private: device_node_handle fNode; pci_device_info* fPCIDevice; @@ -43,6 +45,7 @@ private: int fCommandSlotCount; int fPortCount; int fPortMax; + uint8 fIRQ; AHCIPort * fPorts[32]; diff --git a/src/add-ons/kernel/busses/scsi/ahci/ahci_port.cpp b/src/add-ons/kernel/busses/scsi/ahci/ahci_port.cpp index 0504413195..2cc60d8a70 100644 --- a/src/add-ons/kernel/busses/scsi/ahci/ahci_port.cpp +++ b/src/add-ons/kernel/busses/scsi/ahci/ahci_port.cpp @@ -36,3 +36,10 @@ AHCIPort::Uninit() { TRACE("AHCIPort::Uninit port %d\n", fIndex); } + + +void +AHCIPort::Interrupt() +{ + TRACE("AHCIPort::Interrupt port %d\n", fIndex); +} diff --git a/src/add-ons/kernel/busses/scsi/ahci/ahci_port.h b/src/add-ons/kernel/busses/scsi/ahci/ahci_port.h index ca81f42dc2..8da68672ad 100644 --- a/src/add-ons/kernel/busses/scsi/ahci/ahci_port.h +++ b/src/add-ons/kernel/busses/scsi/ahci/ahci_port.h @@ -17,6 +17,8 @@ public: status_t Init(); void Uninit(); + void Interrupt(); + private: int fIndex; };