Modules/AHCI - Init almost complete, connection detect works
authorJohn Hodge <[email protected]>
Tue, 18 Jun 2013 14:33:06 +0000 (22:33 +0800)
committerJohn Hodge <[email protected]>
Tue, 18 Jun 2013 14:33:06 +0000 (22:33 +0800)
KernelLand/Modules/Storage/AHCI/ahci.c
KernelLand/Modules/Storage/AHCI/ahci.h
KernelLand/Modules/Storage/AHCI/ahci_hw.h

index fc12377..dfb7deb 100644 (file)
@@ -8,6 +8,7 @@
 #define DEBUG  1
 #define VERSION        0x0001
 #include <acess.h>
+#include <timers.h>
 #include <modules.h>
 #include <drv_pci.h>
 #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;
 }
 
index 3965295..bc822d5 100644 (file)
@@ -9,16 +9,38 @@
 #define _AHCI__AHCI_H_
 
 #include "ahci_hw.h"
+#include <Storage/LVM/include/lvm.h>
+#include <stdbool.h>
+#include <semaphore.h>
 
 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
index bbfcbd1..36cc74f 100644 (file)
@@ -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
 #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;

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