From cb8be2945773a37f4f569ce08c79d27af1a172df Mon Sep 17 00:00:00 2001 From: Marcus Overhagen Date: Sat, 22 Sep 2007 23:43:25 +0000 Subject: [PATCH] Start and stop DMA engine and FIS receive, enable port interrupts. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@22278 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../kernel/busses/scsi/ahci/ahci_defs.h | 39 +++++++++++++++ .../kernel/busses/scsi/ahci/ahci_port.cpp | 49 ++++++++++++++++++- 2 files changed, 87 insertions(+), 1 deletion(-) 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 66cc17c081..8c8efa1629 100644 --- a/src/add-ons/kernel/busses/scsi/ahci/ahci_defs.h +++ b/src/add-ons/kernel/busses/scsi/ahci/ahci_defs.h @@ -91,6 +91,45 @@ typedef struct { } _PACKED ahci_port; +enum { + PORT_CMD_ICC_ACTIVE = (1 << 28), // Interface Communication control + PORT_CMD_ICC_SLUMBER = (6 << 28), // Interface Communication control + PORT_CMD_CR = (1 << 15), // Command List Running (DMA active) + PORT_CMD_FR = (1 << 14), // FIS Receive Running + PORT_CMD_FER = (1 << 4), // FIS Receive Enable + PORT_CMD_CLO = (1 << 3), // Command List Override + PORT_CMD_POD = (1 << 2), // Power On Device + PORT_CMD_SUD = (1 << 1), // Spin-up Device + PORT_CMD_ST = (1 << 0), // Start DMA +}; + + +enum { + PORT_INT_CPD = (1 << 31), // Cold Presence Detect Status/Enable + PORT_INT_TFE = (1 << 30), // Task File Error Status/Enable + PORT_INT_HBF = (1 << 29), // Host Bus Fatal Error Status/Enable + PORT_INT_HBD = (1 << 28), // Host Bus Data Error Status/Enable + PORT_INT_IF = (1 << 27), // Interface Fatal Error Status/Enable + PORT_INT_INF = (1 << 26), // Interface Non-fatal Error Status/Enable + PORT_INT_OF = (1 << 24), // Overflow Status/Enable + PORT_INT_IPM = (1 << 23), // Incorrect Port Multiplier Status/Enable + PORT_INT_PRCE = (1 << 22), // PhyRdy Change Status/Enable + PORT_INT_DI = (1 << 7), // Device Interlock Status/Enable + PORT_INT_PC = (1 << 6), // Port Change Status/Enable + PORT_INT_DP = (1 << 5), // Descriptor Processed Interrupt + PORT_INT_UF = (1 << 4), // Unknown FIS Interrupt + PORT_INT_SDB = (1 << 3), // Set Device Bits FIS Interrupt + PORT_INT_DS = (1 << 2), // DMA Setup FIS Interrupt + PORT_INT_PS = (1 << 1), // PIO Setup FIS Interrupt + PORT_INT_DHR = (1 << 0), // Device to Host Register FIS Interrupt +}; + +#define PORT_INT_FATAL (PORT_INT_HBF | PORT_INT_IF | PORT_INT_IPM | PORT_INT_UF) +#define PORT_INT_ERROR (PORT_INT_TFE | PORT_INT_HBD) +#define PORT_INT_MASK (PORT_INT_FATAL | PORT_INT_ERROR | PORT_INT_DP |\ + PORT_INT_SDB | PORT_INT_DS | PORT_INT_PS | PORT_INT_DHR) + + typedef struct { uint32 cap; // Host Capabilities uint32 ghc; // Global Host Control 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 2200db89c2..40e71950ae 100644 --- a/src/add-ons/kernel/busses/scsi/ahci/ahci_port.cpp +++ b/src/add-ons/kernel/busses/scsi/ahci/ahci_port.cpp @@ -63,6 +63,21 @@ AHCIPort::Init() fCommandList[0].ctbau = HI32(physAddr); // prdt follows after command table + // clear IRQ status bits + fRegs->is = fRegs->is; + + // clear error bits + fRegs->serr = fRegs->serr; + + // enable FIS receive + fRegs->cmd |= PORT_CMD_FER; + + // start DMA engine + fRegs->cmd |= PORT_CMD_ST; + + // enable interrupts + fRegs->ie = PORT_INT_MASK; + return B_OK; } @@ -72,6 +87,34 @@ AHCIPort::Uninit() { TRACE("AHCIPort::Uninit port %d\n", fIndex); + // disable FIS receive + fRegs->cmd &= ~PORT_CMD_FER; + + // wait for receive completition, up to 500ms + for (int i = 0; i < 15; i++) { + if (!(fRegs->cmd & PORT_CMD_FR)) + break; + snooze(50000); + } + + if (fRegs->cmd & PORT_CMD_FR) { + TRACE("AHCIPort::Uninit port %d error FIS rx still running\n", fIndex); + } + + // stop DMA engine + fRegs->cmd &= ~PORT_CMD_ST; + + // wait for DMA completition + for (int i = 0; i < 15; i++) { + if (!(fRegs->cmd & PORT_CMD_CR)) + break; + snooze(50000); + } + + if (fRegs->cmd & PORT_CMD_CR) { + TRACE("AHCIPort::Uninit port %d error DMA engine still running\n", fIndex); + } + // disable interrupts fRegs->ie = 0; @@ -91,7 +134,11 @@ AHCIPort::Uninit() void AHCIPort::Interrupt() { - TRACE("AHCIPort::Interrupt port %d\n", fIndex); + uint32 is = fRegs->is; + TRACE("AHCIPort::Interrupt port %d, status %#08x\n", fIndex, is); + + // clear interrupts + fRegs->is = is; }