From: John Hodge Date: Tue, 18 Jun 2013 14:33:06 +0000 (+0800) Subject: Modules/AHCI - Init almost complete, connection detect works X-Git-Tag: rel0.15~432 X-Git-Url: https://git.ucc.asn.au/?a=commitdiff_plain;h=10b384da656541a3c32e3f86bc5c525737c2de38;p=tpg%2Facess2.git Modules/AHCI - Init almost complete, connection detect works --- diff --git a/KernelLand/Modules/Storage/AHCI/ahci.c b/KernelLand/Modules/Storage/AHCI/ahci.c index fc123776..dfb7deba 100644 --- a/KernelLand/Modules/Storage/AHCI/ahci.c +++ b/KernelLand/Modules/Storage/AHCI/ahci.c @@ -8,6 +8,7 @@ #define DEBUG 1 #define VERSION 0x0001 #include +#include #include #include #include "ahci.h" @@ -18,6 +19,8 @@ // === PROTOTYPES === int AHCI_Install(char **Arguments); int AHCI_Cleanup(void); +// - Hardware init + int AHCI_InitSys(tAHCI_Ctrlr *Ctrlr); // === GLOABLS === MODULE_DEFINE(0, VERSION, AHCI, AHCI_Install, AHCI_Cleanup, "LVM", NULL); @@ -26,7 +29,7 @@ tAHCI_Ctrlr gaAHCI_Controllers[MAX_CONTROLLERS]; // === CODE ==== int AHCI_Install(char **Arguments) { - + int rv; LOG("offsetof(struct sAHCI_MemSpace, Ports) = %x", offsetof(struct sAHCI_MemSpace, Ports)); ASSERT( offsetof(struct sAHCI_MemSpace, Ports) == 0x100 ); @@ -61,7 +64,13 @@ int AHCI_Install(char **Arguments) LOG(" CAP = %x, PI = %x, VS = %x", ctrlr->MMIO->CAP, ctrlr->MMIO->PI, ctrlr->MMIO->VS); - + + if( (rv = AHCI_InitSys(ctrlr)) ) { + // Clean up controller's allocations + // TODO: Should an init error cause module unload? + return rv; + } + i ++; } if( id >= 0 ) { @@ -76,18 +85,36 @@ int AHCI_Cleanup(void) return 0; } +static inline void *AHCI_AllocPage(tAHCI_Ctrlr *Ctrlr, const char *AllocName) +{ + void *ret; + #if PHYS_BITS > 32 + if( Ctrlr->Supports64Bit ) + ret = (void*)MM_AllocDMA(1, 64, NULL); + else + #endif + ret = (void*)MM_AllocDMA(1, 32, NULL); + if( !ret ) { + Log_Error("AHCI", "Unable to allocate page for '%s'", AllocName); + return NULL; + } + return ret; +} + int AHCI_InitSys(tAHCI_Ctrlr *Ctrlr) { // 1. Set GHC.AE Ctrlr->MMIO->GHC |= AHCI_GHC_AE; // 2. Enumerate ports using PI - tTime basetime; + tTime basetime = now(); for( int i = 0; i < 32; i ++ ) { if( !(Ctrlr->MMIO->PI & (1 << i)) ) continue ; + + Ctrlr->PortCount ++; + volatile struct s_port *port = &Ctrlr->MMIO->Ports[i]; - nPorts ++; // 3. (for each port) Ensure that port is not running // - if PxCMD.(ST|CR|FRE|FR) all are clear, port is idle if( (port->PxCMD & (AHCI_PxCMD_ST|AHCI_PxCMD_CR|AHCI_PxCMD_FRE|AHCI_PxCMD_FR)) == 0 ) @@ -98,28 +125,93 @@ int AHCI_InitSys(tAHCI_Ctrlr *Ctrlr) basetime = now(); // > On timeout, port/HBA reset } - for( int i = 0; i < 32; i ++ ) + Ctrlr->Ports = malloc( Ctrlr->PortCount * sizeof(*Ctrlr->Ports) ); + if( !Ctrlr->Ports ) { + return MODULE_ERR_MALLOC; + } + // - Process timeouts after all ports have been poked, saves time + for( int i = 0, idx = 0; i < 32; i ++ ) { if( !(Ctrlr->MMIO->PI & (1 << i)) ) continue ; volatile struct s_port *port = &Ctrlr->MMIO->Ports[i]; + Ctrlr->Ports[idx].Idx = i; + Ctrlr->Ports[idx].MMIO = port; + idx ++; while( (port->PxCMD & (AHCI_PxCMD_CR|AHCI_PxCMD_FR)) && now()-basetime < 500 ) Time_Delay(10); - if( !(port->PxCMD & (AHCI_PxCMD_CR|AHCI_PxCMD_FR)) ) + if( (port->PxCMD & (AHCI_PxCMD_CR|AHCI_PxCMD_FR)) ) { Log_Error("AHCI", "Port %i did not return to idle", i); } } // 4. Read CAP.NCS to get number of command slots + Ctrlr->NCS = (Ctrlr->MMIO->CAP & AHCI_CAP_NCS) >> AHCI_CAP_NCS_ofs; // 5. Allocate PxCLB and PxFB for each port (setting PxCMD.FRE once done) + struct sAHCI_RcvdFIS *fis_vpage = NULL; + struct sAHCI_CmdHdr *cl_vpage = NULL; + for( int i = 0; i < Ctrlr->PortCount; i ++ ) + { + // CLB First (1 KB alignemnt) + if( ((tVAddr)cl_vpage & 0xFFF) == 0 ) { + cl_vpage = AHCI_AllocPage(Ctrlr, "CLB"); + if( !cl_vpage ) + return MODULE_ERR_MALLOC; + } + Ctrlr->Ports[i].CmdList = cl_vpage; + cl_vpage += 1024/sizeof(*cl_vpage); + + tPAddr cl_paddr = MM_GetPhysAddr(Ctrlr->Ports[i].CmdList); + Ctrlr->Ports[i].MMIO->PxCLB = cl_paddr; + #if PHYS_BITS > 32 + Ctrlr->Ports[i].MMIO->PxCLBU = cl_paddr >> 32; + #endif + + // Received FIS Area + // - If there is space for the FIS in the end of the 1K block, use it + if( Ctrlr->NCS <= (1024-256)/32 ) + { + Ctrlr->Ports[i].RcvdFIS = (void*)(cl_vpage - 256/32); + } + else + { + if( ((tVAddr)fis_vpage & 0xFFF) == 0 ) { + fis_vpage = AHCI_AllocPage(Ctrlr, "FIS"); + if( !fis_vpage ) + return MODULE_ERR_MALLOC; + } + Ctrlr->Ports[i].RcvdFIS = fis_vpage; + fis_vpage ++; + } + tPAddr fis_paddr = MM_GetPhysAddr(Ctrlr->Ports[i].RcvdFIS); + Ctrlr->Ports[i].MMIO->PxFB = fis_paddr; + #if PHYS_BITS > 32 + Ctrlr->Ports[i].MMIO->PxFBU = fis_paddr >> 32; + #endif + + LOG("Port #%i: CLB=%p/%P, FB=%p/%P", i, + Ctrlr->Ports[i].CmdList, cl_paddr, + Ctrlr->Ports[i].RcvdFIS, fis_paddr); + } // 6. Clear PxSERR with 1 to each implimented bit // > Clear PxIS then IS.IPS before setting PxIE/GHC.IE // 7. Set PxIE with desired interrupts and set GHC.IE // Detect present ports using: // > PxTFD.STS.BSY = 0, PxTFD.STS.DRQ = 0, and PxSSTS.DET = 3 + for( int i = 0; i < Ctrlr->PortCount; i ++ ) + { + if( Ctrlr->Ports[i].MMIO->PxTFD & (AHCI_PxTFD_STS_BSY|AHCI_PxTFD_STS_DRQ) ) + continue ; + if( (Ctrlr->Ports[i].MMIO->PxSSTS & AHCI_PxSSTS_DET) != 3 << AHCI_PxSSTS_DET_ofs ) + continue ; + + LOG("Port #%i: Connection detected", i); + Ctrlr->Ports[i].bPresent = 1; + // TODO: Query volumes connected + } return 0; } diff --git a/KernelLand/Modules/Storage/AHCI/ahci.h b/KernelLand/Modules/Storage/AHCI/ahci.h index 39652956..bc822d5e 100644 --- a/KernelLand/Modules/Storage/AHCI/ahci.h +++ b/KernelLand/Modules/Storage/AHCI/ahci.h @@ -9,16 +9,38 @@ #define _AHCI__AHCI_H_ #include "ahci_hw.h" +#include +#include +#include typedef struct sAHCI_Ctrlr tAHCI_Ctrlr; +typedef struct sAHCI_Port tAHCI_Port; struct sAHCI_Ctrlr { - int PortCount; - int IRQ; tPAddr PMemBase; - struct sAHCI_MemSpace *MMIO; + tAHCI_MemSpace *MMIO; + + int NCS; + + int PortCount; + tAHCI_Port *Ports; +}; + +struct sAHCI_Port +{ + int Idx; // Hardware index + volatile struct s_port *MMIO; + bool bHotplug; + bool bPresent; + + tSemaphore CommandListSem; + volatile struct sAHCI_CmdHdr *CmdList; + + volatile struct sAHCI_RcvdFIS *RcvdFIS; + + void *LVMHandle; }; #endif diff --git a/KernelLand/Modules/Storage/AHCI/ahci_hw.h b/KernelLand/Modules/Storage/AHCI/ahci_hw.h index bbfcbd13..36cc74f4 100644 --- a/KernelLand/Modules/Storage/AHCI/ahci_hw.h +++ b/KernelLand/Modules/Storage/AHCI/ahci_hw.h @@ -12,6 +12,7 @@ #define AHCI_CAP_SNCQ (1 << 30) // Supports Native Command Queuing #define AHCI_CAP_SXS (1 << 5) // Support External SATA #define AHCI_CAP_NCS (31 << 8) // Number of command slots (mask) +#define AHCI_CAP_NCS_ofs 8 // (offset) #define AHCI_GHC_AE (1 << 31) // AHCI Enable #define AHCI_GHC_MRSM (1 << 2) // MSI Revert to Single Message @@ -59,6 +60,21 @@ #define AHCI_PxCMD_SUD (1 << 1) // Spin-Up Device #define AHCI_PxCMD_ST (1 << 0) // Start +#define AHCI_PxTFD_ERR (255 << 8) +#define AHCI_PxTFD_STS (255 << 0) // Status (latest copy of task file status register) +#define AHCI_PxTFD_STS_BSY (1 << 7) // Interface is busy +#define AHCI_PxTFD_STS_DRQ (1 << 3) // Data transfer requested +#define AHCI_PxTFD_STS_ERR (1 << 0) // Error during transfer + +#define AHCI_PxSSTS_IPM (15 << 8) // Interface Power Management (0=NP,1=Active,2=Partial,6=Slumber) +#define AHCI_PxSSTS_IPM_ofs 8 +#define AHCI_PxSSTS_SPD (15 << 4) // Current Interface Speed (0=NP,Generation n) +#define AHCI_PxSSTS_SPD_ofs 4 +#define AHCI_PxSSTS_DET (15 << 0) // Device Detection (0: None, 1: Present but no PHY yet, 3: Present and PHY, 4: offline) +#define AHCI_PxSSTS_DET_ofs 0 + +typedef volatile struct sAHCI_MemSpace tAHCI_MemSpace; + struct sAHCI_MemSpace { Uint32 CAP; // Host Capabilities @@ -99,6 +115,36 @@ struct sAHCI_MemSpace } Ports[32]; } PACKED; +struct sAHCI_FIS_DMASetup +{ + Uint32 unk[7]; +} PACKED; +struct sAHCI_FIS_PIOSetup +{ + Uint32 unk[5]; +} PACKED; +struct sAHCI_FIS_D2HRegister +{ + Uint32 unk[5]; +} PACKED; +struct sAHCI_FIS_SDB +{ + Uint32 unk[2]; +} PACKED; + +struct sAHCI_RcvdFIS +{ + struct sAHCI_FIS_DMASetup DSFIS; + Uint32 _pad1[1]; + struct sAHCI_FIS_PIOSetup PSFIS; + Uint32 _pad2[3]; + struct sAHCI_FIS_D2HRegister RFIS; + Uint32 _pad3[1]; + struct sAHCI_FIS_SDB SDBFIS; + Uint32 UFIS[64/4]; + Uint32 _redvd[(0x100 - 0xA0) / 4]; +} PACKED; + struct sAHCI_CmdHdr { Uint16 Flags;