[SeaBIOS] non-emulated AHCI hardware

Scott Duplichan scott at notabs.org
Sun Apr 24 08:21:43 CEST 2011


On Friday, April 22, 2011 05:19 AM  Jonathan A. Kollasch wrote:

]> thanks for the tip. Do you have any fixes beyond that one I should try?
]
]Yeah, I just didn't like them well enough to post a patch.
]
]Attached is what I have.  Last I tried it a few months ago it mostly
]worked for ATA disks but not ATAPI devices.  IIRC the key changes are
]in the port probe and reset functions.
]
]	Jonathan Kollasch

Hello Jonathan,

Thanks. I made some progress. Though there are some quirks, the attached
patch gets AHCI working well enough on my AMD Fusion board to install
Windows 7 from DVD. I installed it on both a regular SATA drive and on
a SATA SSD drive. There are at least 2 remaining problems:

1) When booting a DOS drive, a disk read error occurs at some point
after autoexec executes.
2) DOS booting is slower by 100-200 ms. While that isn't much in
absolute terms, it is a big percentage increase from the 642 ms I
can get using the IDE interface.  

Windows 7 setup loads from DVD noticeable faster when AHCI is used.
Windows 7 boot with AHCI and an SSD disk is impressive. Using AHCI
and completely hiding the IDE device keeps Windows from wasting
time with uninstalled drives while booting. Starting from power off
with the Windows 7 SSD drive, the desktop background appears after 15 
seconds and the desktop is complete after around 20 seconds.

Thanks,
Scott


--- seabios-0.6.2-original\src\ahci.c	Mon Feb 28 21:10:57 2011
+++ seabios-0.6.2\src\ahci.c	Sun Apr 24 01:12:20 2011
@@ -105,7 +105,7 @@
 static int ahci_command(struct ahci_port_s *port, int iswrite, int isatapi,
                         void *buffer, u32 bsize)
 {
-    u32 val, status, success, flags;
+    u32 val, status, flags, intbits, error;
     struct ahci_ctrl_s *ctrl = GET_GLOBAL(port->ctrl);
     struct ahci_cmd_s  *cmd  = GET_GLOBAL(port->cmd);
     struct ahci_fis_s  *fis  = GET_GLOBAL(port->fis);
@@ -118,19 +118,24 @@
     SET_FLATPTR(cmd->prdt[0].baseu, 0);
     SET_FLATPTR(cmd->prdt[0].flags, bsize-1);
 
+    // clear interrupt status
+    val = ahci_port_readl(ctrl, pnr, PORT_IRQ_STAT);
+    ahci_port_writel(ctrl, pnr, PORT_IRQ_STAT, val);
+    
+    // toggle the start control
     val = ahci_port_readl(ctrl, pnr, PORT_CMD);
+    ahci_port_writel(ctrl, pnr, PORT_CMD, val & ~(PORT_CMD_START | PORT_CMD_FIS_RX));
     ahci_port_writel(ctrl, pnr, PORT_CMD, val | PORT_CMD_START);
 
     if (ahci_port_readl(ctrl, pnr, PORT_CMD_ISSUE))
         return -1;
 
     flags = ((1 << 16) | /* one prd entry */
-             (1 << 10) | /* clear busy on ok */
              (iswrite ? (1 << 6) : 0) |
              (isatapi ? (1 << 5) : 0) |
-             (4 << 0)); /* fis length (dwords) */
+             (5 << 0)); /* fis length (dwords) */
     SET_FLATPTR(list[0].flags, flags);
-    SET_FLATPTR(list[0].bytes,  bsize);
+    SET_FLATPTR(list[0].bytes,  0);
     SET_FLATPTR(list[0].base,   ((u32)(cmd)));
     SET_FLATPTR(list[0].baseu,  0);
 
@@ -138,19 +143,39 @@
     SET_FLATPTR(fis->rfis[2], 0);
     ahci_port_writel(ctrl, pnr, PORT_SCR_ACT, 1);
     ahci_port_writel(ctrl, pnr, PORT_CMD_ISSUE, 1);
-    while (ahci_port_readl(ctrl, pnr, PORT_CMD_ISSUE)) {
-        yield();
-    }
-    while ((status = GET_FLATPTR(fis->rfis[2])) == 0) {
+    while (1) {
+        intbits = ahci_port_readl(ctrl, pnr, PORT_IRQ_STAT) & 0x3f;
+        if (intbits) break;
         yield();
     }
-
-    success = (0x00 == (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_DF |
-                                  ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR)) &&
-               ATA_CB_STAT_RDY == (status & (ATA_CB_STAT_RDY)));
-    dprintf(2, "AHCI/%d: ... finished, status 0x%x, %s\n", pnr,
-            status, success ? "OK" : "ERROR");
-    return success ? 0 : -1;
+    status = 0xFFFF;
+    error = -2;
+    if (intbits == 0x01) { // Device to Host Register FIS Interrupt (DHRS)
+        status = GET_FLATPTR(fis->rfis[2]);
+        error = GET_FLATPTR(fis->rfis[3]);
+    }
+    if (intbits == 0x02) { // PIO Setup FIS Interrupt (PSS)
+        status = GET_FLATPTR(fis->psfis[2]);
+        error = GET_FLATPTR(fis->psfis[3]);
+    }
+    if (intbits == 0x04) { // DMA Setup FIS Interrupt (DSS)
+        status = GET_FLATPTR(fis->dsfis[2]);
+        error = GET_FLATPTR(fis->dsfis[3]);
+    }
+    if (intbits == 0x08) { // Set Device Bits Interrupt (SDBS)
+        status = GET_FLATPTR(fis->sdbfis[2]);
+        error = GET_FLATPTR(fis->sdbfis[3]);
+    }
+    if (intbits == 0x10) { // Unknown FIS Interrupt (UFS)
+        status = GET_FLATPTR(fis->ufis[2]);
+        error = GET_FLATPTR(fis->ufis[3]);
+    }
+
+    if (!error)
+        dprintf(2, "AHCI/%d: ... finished, status 0x%02x OK\n", pnr, status);
+    else
+        dprintf(2, "AHCI/%d: ... finished, status 0x%02x ERROR %02x\n", pnr, status, error);
+    return error;
 }
 
 #define CDROM_CDB_SIZE 12
@@ -172,7 +197,7 @@
     }
     rc = ahci_command(port, 0, 1, op->buf_fl,
                       op->count * blocksize);
-    if (rc < 0)
+    if (rc)
         return DISK_RET_EBADTRACK;
     return DISK_RET_SUCCESS;
 }
@@ -191,7 +216,7 @@
                       op->count * DISK_SECTOR_SIZE);
     dprintf(2, "ahci disk %s, lba %6x, count %3x, buf %p, rc %d\n",
             iswrite ? "write" : "read", (u32)op->lba, op->count, op->buf_fl, rc);
-    if (rc < 0)
+    if (rc)
         return DISK_RET_EBADTRACK;
     return DISK_RET_SUCCESS;
 }
@@ -281,22 +306,10 @@
 static int
 ahci_port_probe(struct ahci_ctrl_s *ctrl, u32 pnr)
 {
-    u32 val, count = 0;
-
-    val = ahci_port_readl(ctrl, pnr, PORT_TFDATA);
-    while (val & ((1 << 7) /* BSY */ |
-                  (1 << 3) /* DRQ */)) {
-        ndelay(500);
-        val = ahci_port_readl(ctrl, pnr, PORT_TFDATA);
-        count++;
-        if (count >= AHCI_MAX_RETRIES)
-            return -1;
-    }
-
-    val = ahci_port_readl(ctrl, pnr, PORT_SCR_STAT);
-    if ((val & 0x07) != 0x03)
-        return -1;
-    return 0;
+    u32 val = ahci_port_readl(ctrl, pnr, PORT_SCR_STAT) & 7;
+    if (val == 3) // Device presence detected and Phy communication established
+        return 0;
+    return -1;
 }
 
 #define MAXMODEL 40
@@ -340,7 +353,7 @@
         port->atapi = 0;
         sata_prep_simple(&port->cmd->fis, ATA_CMD_IDENTIFY_DEVICE);
         rc = ahci_command(port, 0, 0, buffer, sizeof(buffer));
-        if (rc < 0)
+        if (rc)
             goto err;
     }

-------------- next part --------------
A non-text attachment was scrubbed...
Name: ahci-001.patch
Type: application/octet-stream
Size: 5003 bytes
Desc: not available
URL: <http://www.seabios.org/pipermail/seabios/attachments/20110424/6de86a19/attachment.obj>


More information about the SeaBIOS mailing list