correct port number handling

allocate memory for command list and fis


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@22221 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Marcus Overhagen
2007-09-11 22:09:13 +00:00
parent 72c9d31ec4
commit 9382f57691
5 changed files with 100 additions and 16 deletions
@@ -21,8 +21,8 @@ AHCIController::AHCIController(device_node_handle node, pci_device_info *device)
, fPCIVendorID(0xffff)
, fPCIDeviceID(0xffff)
, fCommandSlotCount(0)
, fPortCount(0)
, fPortMax(0)
, fPortCountMax(0)
, fPortCountAvail(0)
, fIRQ(0)
, fInstanceCheck(-1)
{
@@ -90,15 +90,13 @@ AHCIController::Init()
}
fCommandSlotCount = 1 + ((fRegs->cap >> CAP_NCS_SHIFT) & CAP_NCS_MASK);
fPortCount = 1 + ((fRegs->cap >> CAP_NP_SHIFT) & CAP_NP_MASK);
fPortCountMax = 1 + ((fRegs->cap >> CAP_NP_SHIFT) & CAP_NP_MASK);
fPortCountAvail = count_bits_set(fRegs->pi);
if (fRegs->pi == 0) {
TRACE("controller doesn't implement any ports\n");
goto err;
}
fPortMax = 31;
while ((fRegs->pi & (1 << fPortMax)) == 0)
fPortMax--;
fIRQ = gPCI->read_pci_config(fPCIDevice, PCI_interrupt_line, 1);
if (fIRQ == 0 || fIRQ == 0xff) {
@@ -108,7 +106,7 @@ AHCIController::Init()
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);
TRACE("cap: Number of Ports: %d (raw %#lx)\n", fPortCountMax, (fRegs->cap >> CAP_NP_SHIFT) & CAP_NP_MASK);
TRACE("cap: Supports Port Multiplier: %s\n", (fRegs->cap & CAP_SPM) ? "yes" : "no");
TRACE("cap: Supports External SATA: %s\n", (fRegs->cap & CAP_SXS) ? "yes" : "no");
TRACE("cap: Enclosure Management Supported: %s\n", (fRegs->cap & CAP_EMS) ? "yes" : "no");
@@ -121,8 +119,8 @@ AHCIController::Init()
TRACE("cap: Supports AHCI mode only: %s\n", (fRegs->cap & CAP_SAM) ? "yes" : "no");
TRACE("ghc: AHCI Enable: %s\n", (fRegs->ghc & GHC_AE) ? "yes" : "no");
TRACE("Ports Implemented: %08lx\n", fRegs->pi);
TRACE("Highest port Number: %d\n", fPortMax);
TRACE("Ports Implemented Mask: %#08lx\n", fRegs->pi);
TRACE("Number of Available Ports: %d\n", fPortCountAvail);
TRACE("AHCI Version %lu.%lu\n", fRegs->vs >> 16, fRegs->vs & 0xff);
TRACE("Interrupt %u\n", fIRQ);
@@ -132,7 +130,7 @@ AHCIController::Init()
goto err;
}
for (int i = 0; i <= fPortMax; i++) {
for (int i = 0; i <= fPortCountMax; i++) {
if (fRegs->pi & (1 << i)) {
fPort[i] = new (std::nothrow)AHCIPort(this, i);
if (!fPort[i]) {
@@ -166,7 +164,7 @@ AHCIController::Uninit()
{
TRACE("AHCIController::Uninit\n");
for (int i = 0; i <= fPortMax; i++) {
for (int i = 0; i <= fPortCountMax; i++) {
if (fPort[i]) {
fPort[i]->Uninit();
delete fPort[i];
@@ -233,7 +231,7 @@ AHCIController::Interrupt(void *data)
if (int_stat == 0)
return B_UNHANDLED_INTERRUPT;
for (int i = 0; i < self->fPortMax; i++) {
for (int i = 0; i < self->fPortCountMax; i++) {
if (int_stat & (1 << i)) {
if (self->fPort[i]) {
self->fPort[i]->Interrupt();
@@ -44,8 +44,8 @@ private:
volatile ahci_hba * fRegs;
area_id fRegsArea;
int fCommandSlotCount;
int fPortCount;
int fPortMax;
int fPortCountMax;
int fPortCountAvail;
uint8 fIRQ;
AHCIPort * fPort[32];
@@ -47,10 +47,37 @@ enum {
};
enum {
INT_CPD = (1 << 31), // Cold Port Detect Status/Enable
INT_TFE = (1 << 30), // Task File Error Status/Enable
INT_HBF = (1 << 29), // Host Bus Fatal Error Status/Enable
INT_HBD = (1 << 28), // Host Bus Data Error Status/Enable
INT_IF = (1 << 27), // Interface Fatal Error Status/Enable
INT_INF = (1 << 26), // Interface Non-fatal Error Status/Enable
INT_OF = (1 << 24), // Overflow Status/Enable
INT_IPM = (1 << 23), // Incorrect Port Multiplier Status/Enable
INT_PRC = (1 << 22), // PhyRdy Change Status/Enable
INT_DMP = (1 << 7), // Device Mechanical Presence Status/Enable
INT_PC = (1 << 6), // Port Change Interrupt Status/Enable
INT_DP = (1 << 5), // Descriptor Processed Interrupt/Enable
INT_UF = (1 << 4), // Unknown FIS Interrupt/Enable
INT_SDB = (1 << 3), // Set Device Bits Interrupt/Enable
INT_DS = (1 << 2), // DMA Setup FIS Interrupt/Enable
INT_PS = (1 << 1), // PIO Setup FIS Interrupt/Enable
INT_DHR = (1 << 0), // Device to Host Register FIS Interrupt/Enable
};
enum {
AHCI_CLB_SIZE = 1024,
AHCI_FIS_SIZE = 256,
};
typedef struct {
uint32 clb; // Command List Base Address
uint32 clb; // Command List Base Address (alignment 1024 byte)
uint32 clbu; // Command List Base Address Upper 32-Bits
uint32 fb; // FIS Base Address
uint32 fb; // FIS Base Address (alignment 256 byte)
uint32 fbu; // FIS Base Address Upper 32-Bits
uint32 is; // Interrupt Status
uint32 ie; // Interrupt Enable
@@ -91,4 +118,22 @@ extern device_manager_info *gDeviceManager;
extern pci_device_module_info *gPCI;
extern scsi_for_sim_interface *gSCSI;
#define LO32(val) ((uint32)(val))
#define HI32(val) (((uint64)(val)) >> 32)
#ifdef __cplusplus
template <class T>
int count_bits_set(T value)
{
int count = 0;
for (T mask = 1; mask; mask <<= 1)
if (value & mask)
count++;
return count;
}
#endif /* __cplusplus */
#endif /* _AHCI_DEFS_H */
@@ -5,6 +5,7 @@
#include "ahci_port.h"
#include "ahci_controller.h"
#include "util.h"
#include <KernelExport.h>
#include <stdio.h>
@@ -16,6 +17,7 @@
AHCIPort::AHCIPort(AHCIController *controller, int index)
: fIndex(index)
, fRegs(&controller->fRegs->port[index])
, fArea(-1)
{
}
@@ -29,6 +31,29 @@ status_t
AHCIPort::Init()
{
TRACE("AHCIPort::Init port %d\n", fIndex);
size_t size = 999;
void *virtAddr;
void *physAddr;
fArea = alloc_mem(&virtAddr, &physAddr, size, 0, "some AHCI port");
if (fArea < B_OK) {
TRACE("failed allocating memory for port %d\n", fIndex);
return fArea;
}
void *virtClbAddr;
void *physClbAddr = physAddr;
void *virtFisAddr;
void *physFisAddr = (char *)physAddr + 1024;
fRegs->clb = LO32(physClbAddr);
fRegs->clbu = HI32(physClbAddr);
fRegs->fb = LO32(physFisAddr);
fRegs->fbu = HI32(physFisAddr);
return B_OK;
}
@@ -37,6 +62,20 @@ void
AHCIPort::Uninit()
{
TRACE("AHCIPort::Uninit port %d\n", fIndex);
// disable interrupts
fRegs->ie = 0;
// clear pending interrupts
fRegs->is = fRegs->is;
// invalidate DMA addresses
fRegs->clb = 0;
fRegs->clbu = 0;
fRegs->fb = 0;
fRegs->fbu = 0;
delete_area(fArea);
}
@@ -25,10 +25,12 @@ public:
uchar TerminateRequest(scsi_ccb *request);
uchar ResetDevice();
private:
private:
int fIndex;
volatile ahci_port * fRegs;
area_id fArea;
};
#endif // _AHCI_PORT_H