Modules/AHCI - Creeping towards useful
authorJohn Hodge <[email protected]>
Mon, 17 Jun 2013 07:59:42 +0000 (15:59 +0800)
committerJohn Hodge <[email protected]>
Mon, 17 Jun 2013 07:59:42 +0000 (15:59 +0800)
KernelLand/Modules/Storage/AHCI/ahci.c
KernelLand/Modules/Storage/AHCI/ahci_hw.h

index ffd66de..fc12377 100644 (file)
@@ -81,12 +81,38 @@ int AHCI_InitSys(tAHCI_Ctrlr *Ctrlr)
        // 1. Set GHC.AE
        Ctrlr->MMIO->GHC |= AHCI_GHC_AE;
        // 2. Enumerate ports using PI
-       // 3. (for each port) Ensure that port is not running
-       //  - if PxCMD.(ST|CR|FRE|FR) all are clear, port is idle
-       //  - Idle is set by clearing PxCMD.ST and waiting for .CR to clear (timeout 500ms)
-       //  - AND .FRE = 0, checking .FR (timeout 500ms again)
-       //  > On timeout, port/HBA reset
-       // 4. Read CAP.NCS 
+       tTime   basetime;
+       for( int i = 0; i < 32; i ++ )
+       {
+               if( !(Ctrlr->MMIO->PI & (1 << i)) )
+                       continue ;
+               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 )
+                       continue ;
+               //  - Idle is set by clearing PxCMD.ST and waiting for .CR to clear (timeout 500ms)
+               //  - AND .FRE = 0, checking .FR (timeout 500ms again)
+               port->PxCMD = 0;
+               basetime = now();
+               //  > On timeout, port/HBA reset
+       }
+       for( int i = 0; i < 32; i ++ )
+       {
+               if( !(Ctrlr->MMIO->PI & (1 << i)) )
+                       continue ;
+               volatile struct s_port  *port = &Ctrlr->MMIO->Ports[i];
+       
+               while( (port->PxCMD & (AHCI_PxCMD_CR|AHCI_PxCMD_FR)) && now()-basetime < 500 )
+                       Time_Delay(10);
+               
+               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
        // 5. Allocate PxCLB and PxFB for each port (setting PxCMD.FRE once done)
        // 6. Clear PxSERR with 1 to each implimented bit
        // > Clear PxIS then IS.IPS before setting PxIE/GHC.IE
index c4a94f9..bbfcbd1 100644 (file)
 #define AHCI_CAP_S64A  (1 << 31)       // Supports 64-bit addressing
 #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_GHC_AE    (1 << 31)       // AHCI Enable
 #define AHCI_GHC_MRSM  (1 << 2)        // MSI Revert to Single Message
 #define AHCI_GHC_IE    (1 << 1)        // Interrupt Enable
 #define ACHI_GHC_HR    (1 << 0)        // HBA Reset (Clears once complete)
 
+#define AHCI_PxIS_CPDS (1 << 31)       // Cold Port Detect Status
+#define AHCI_PxIS_TFES (1 << 30)       // Task File Error Status
+#define AHCI_PxIS_HBFS (1 << 29)       // Host Bus Fatal error Status
+#define AHCI_PxIS_HBDS (1 << 28)       // Host Bus Data error Status
+#define AHCI_PxIS_IFS  (1 << 27)       // Interface Fatal error Status
+#define AHCI_PxIS_INFS (1 << 26)       // Interface Non-Fatal error status
+#define AHCI_PxIS_OFS  (1 << 24)       // OverFlow Status
+#define AHCI_PxIS_IPMS (1 << 23)       // Incorrect Port Multipier Status
+#define AHCI_PxIS_PRCS (1 << 22)       // PhyRdy Change Status
+#define AHCI_PxIS_DMPS (1 << 7)        // Device Mechanical Presence Status
+#define AHCI_PxIS_PCS  (1 << 6)        // Port Connect change Status
+#define AHCI_PxIS_DPS  (1 << 5)        // Descriptor Processed
+#define AHCI_PxIS_UFI  (1 << 4)        // Unknown FIX Interrupt
+#define AHCI_PxIS_SDBS (1 << 3)        // Set Device Bits Interrupt
+#define AHCI_PxIS_DSS  (1 << 2)        // DMA Setup FIS Interrupt
+#define AHCI_PxIS_PSS  (1 << 1)        // PIO Setup FIX Interrupt
+#define AHCI_PxIS_DHRS (1 << 0)        // Device to Host Register FIS Interrupt
+
+#define AHCI_PxCMD_ICC (15 << 28)      // Interface Communication Control (mask)
+#define AHCI_PxCMD_ASP (1 << 27)       // Agressive Slumber / Partial
+#define AHCI_PxCMD_ALPE        (1 << 26)       // Agressive Link Power Management Enable
+#define AHCI_PxCMD_DLAE        (1 << 25)       // Drive LED on ATAPI Enable
+#define AHCI_PxCMD_ATAPI       (1 << 24)       // Device is ATAPI
+#define AHCI_PxCMD_APSTE       (1 << 23)       // Automatic Partial to Slumber Transitions Enabled
+#define AHCI_PxCMD_FBSCP       (1 << 22)       // FIS-based Switching Capable Port
+#define AHCI_PxCMD_ESP (1 << 21)       // External SATA Port
+#define AHCI_PxCMD_CPD (1 << 20)       // Cold Presence Detection
+#define AHCI_PxCMD_MPSP        (1 << 19)       // Mechanical Presence Switch attached to Port
+#define AHCI_PxCMD_HPCP        (1 << 18)       // Hot Plut Capable Port
+#define AHCI_PxCMD_PMA (1 << 17)       // Port Multiplier Attached
+#define AHCI_PxCMD_CPS (1 << 16)       // Cold Presence State
+#define AHCI_PxCMD_CR  (1 << 15)       // Command List Running
+#define AHCI_PxCMD_FR  (1 << 14)       // FIS Receive Running
+#define AHCI_PxCMD_MPSS        (1 << 13)       // Mechanical Presence Switch State
+#define AHCI_PxCMD_CCS (31 << 8)       // Current Command Slot (mask)
+#define AHCI_PxCMD_FRE (1 << 4)        // FIS Receive Enable
+#define AHCI_PxCMD_CLO (1 << 3)        // Command List Override
+#define AHCI_PxCMD_POD (1 << 2)        // Power On Device
+#define AHCI_PxCMD_SUD (1 << 1)        // Spin-Up Device
+#define AHCI_PxCMD_ST  (1 << 0)        // Start
+
 struct sAHCI_MemSpace
 {
        Uint32  CAP;    // Host Capabilities

UCC git Repository :: git.ucc.asn.au