Implement time based checks even when looping on an ioport.
[seabios.git] / src / ata.c
index f245e21199cf58f5fd3fdf7b6fb87329572bfb10..53f9196378756f94fdeac15fb25659081be6e084 100644 (file)
--- a/src/ata.c
+++ b/src/ata.c
 #include "ioport.h" // inb
 #include "util.h" // dprintf
 #include "cmos.h" // inb_cmos
-#include "pic.h" // unmask_pic2
+#include "pic.h" // enable_hwirq
 #include "biosvar.h" // GET_EBDA
 #include "pci.h" // pci_find_class
+#include "pci_ids.h" // PCI_CLASS_STORAGE_OTHER
+#include "pci_regs.h" // PCI_INTERRUPT_LINE
 
 #define TIMEOUT 0
 #define BSY 1
 static int
 await_ide(u8 when_done, u16 base, u16 timeout)
 {
-    u32 time=0, last=0;
+    u64 end = calc_future_tsc(timeout);
     for (;;) {
         u8 status = inb(base+ATA_CB_STAT);
-        time++;
         u8 result = 0;
         if (when_done == BSY)
             result = status & ATA_CB_STAT_BSY;
@@ -53,20 +54,13 @@ await_ide(u8 when_done, u16 base, u16 timeout)
 
         if (result)
             return status;
-        // mod 2048 each 16 ms
-        if (time>>16 != last) {
-            last = time >>16;
-            dprintf(6, "await_ide: (TIMEOUT,BSY,!BSY,!BSY_DRQ"
-                    ",!BSY_!DRQ,!BSY_RDY) %d time= %d timeout= %d\n"
-                    , when_done, time>>11, timeout);
-        }
         if (status & ATA_CB_STAT_ERR) {
             dprintf(1, "await_ide: ERROR (TIMEOUT,BSY,!BSY,!BSY_DRQ"
-                    ",!BSY_!DRQ,!BSY_RDY) %d status=%x time= %d timeout= %d\n"
-                    , when_done, status, time>>11, timeout);
+                    ",!BSY_!DRQ,!BSY_RDY) %d status=%x timeout=%d\n"
+                    , when_done, status, timeout);
             return -1;
         }
-        if (timeout == 0 || (time>>11) > timeout)
+        if (rdtscll() >= end)
             break;
     }
     dprintf(1, "IDE time out\n");
@@ -83,30 +77,14 @@ pause_await_ide(u8 when_done, u16 iobase1, u16 iobase2, u16 timeout)
     return await_ide(when_done, iobase1, timeout);
 }
 
-// Delay for x nanoseconds
-static void
-nsleep(u32 delay)
-{
-    // XXX - how to implement ndelay?
-    while (delay--)
-        nop();
-}
-
 // Wait for ide state - pause for 400ns first.
 static __always_inline int
 ndelay_await_ide(u8 when_done, u16 iobase1, u16 timeout)
 {
-    nsleep(400);
+    ndelay(400);
     return await_ide(when_done, iobase1, timeout);
 }
 
-// Delay for x milliseconds
-static void
-msleep(u32 delay)
-{
-    usleep(delay * 1000);
-}
-
 // Reset a drive
 void
 ata_reset(int driveid)
@@ -131,7 +109,7 @@ ata_reset(int driveid)
     // 8.2.1 (g) -- check for sc==sn==0x01
     // select device
     outb(slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0, iobase1+ATA_CB_DH);
-    msleep(50);
+    mdelay(50);
     u8 sc = inb(iobase1+ATA_CB_SC);
     u8 sn = inb(iobase1+ATA_CB_SN);
 
@@ -197,7 +175,7 @@ send_cmd(int driveid, struct ata_pio_command *cmd)
     outb(cmd->device, iobase1 + ATA_CB_DH);
     if ((device ^ cmd->device) & (1 << 4))
         // Wait for device to become active.
-        msleep(50);
+        mdelay(50);
 
     if (cmd->command & 0x04) {
         outb(0x00, iobase1 + ATA_CB_FR);
@@ -847,7 +825,7 @@ ata_detect()
 
         // Look for device
         outb(slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0, iobase1+ATA_CB_DH);
-        msleep(50);
+        mdelay(50);
         outb(0x55, iobase1+ATA_CB_SC);
         outb(0xaa, iobase1+ATA_CB_SN);
         outb(0xaa, iobase1+ATA_CB_SC);
@@ -868,7 +846,7 @@ ata_detect()
 
         // check for ATA or ATAPI
         outb(slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0, iobase1+ATA_CB_DH);
-        msleep(50);
+        mdelay(50);
         sc = inb(iobase1+ATA_CB_SC);
         sn = inb(iobase1+ATA_CB_SN);
         dprintf(6, "ata_detect(2) drive=%d sc=%x sn=%x\n", driveid, sc, sn);
@@ -907,48 +885,41 @@ ata_init()
     }
 
     // Scan PCI bus for ATA adapters
-    int count=0, index=0;
-    u16 classid = 0x0180; // SATA first
-    while (count<CONFIG_MAX_ATA_INTERFACES-1) {
-        PCIDevice d;
-        int ret = pci_find_class(classid, index, &d);
-        if (ret) {
-            if (classid == 0x0101)
-                // Done
-                break;
-            classid = 0x0101; // PATA controllers
-            index = 0;
+    int count=0;
+    int bdf, max;
+    foreachpci(bdf, max) {
+        if (pci_config_readw(bdf, PCI_CLASS_DEVICE) != PCI_CLASS_STORAGE_IDE)
             continue;
-        }
-        index++;
 
-        u8 irq = pci_config_readb(d, PCI_INTERRUPT_LINE);
+        u8 irq = pci_config_readb(bdf, PCI_INTERRUPT_LINE);
         SET_EBDA(ata.channels[count].irq, irq);
-        SET_EBDA(ata.channels[count].pci_bdf, pci_to_bdf(d));
+        SET_EBDA(ata.channels[count].pci_bdf, bdf);
 
-        u8 prog_if = pci_config_readb(d, PCI_CLASS_PROG);
+        u8 prog_if = pci_config_readb(bdf, PCI_CLASS_PROG);
         u32 port1, port2;
 
-        if (classid != 0x0101 || prog_if & 1) {
-            port1 = pci_config_readl(d, PCI_BASE_ADDR_0) & ~3;
-            port2 = pci_config_readl(d, PCI_BASE_ADDR_1) & ~3;
+        if (prog_if & 1) {
+            port1 = pci_config_readl(bdf, PCI_BASE_ADDRESS_0) & ~3;
+            port2 = pci_config_readl(bdf, PCI_BASE_ADDRESS_1) & ~3;
         } else {
             port1 = 0x1f0;
             port2 = 0x3f0;
         }
         SET_EBDA(ata.channels[count].iobase1, port1);
         SET_EBDA(ata.channels[count].iobase2, port2);
-        dprintf(1, "ATA controller %d at %x/%x\n", count, port1, port2);
+        dprintf(1, "ATA controller %d at %x/%x (dev %x prog_if %x)\n"
+                , count, port1, port2, bdf, prog_if);
         count++;
 
-        if (classid != 0x0101 || prog_if & 4) {
-            port1 = pci_config_readl(d, PCI_BASE_ADDR_2) & ~3;
-            port2 = pci_config_readl(d, PCI_BASE_ADDR_3) & ~3;
+        if (prog_if & 4) {
+            port1 = pci_config_readl(bdf, PCI_BASE_ADDRESS_2) & ~3;
+            port2 = pci_config_readl(bdf, PCI_BASE_ADDRESS_3) & ~3;
         } else {
             port1 = 0x170;
             port2 = 0x370;
         }
-        dprintf(1, "ATA controller %d at %x/%x\n", count, port1, port2);
+        dprintf(1, "ATA controller %d at %x/%x (dev %x prog_if %x)\n"
+                , count, port1, port2, bdf, prog_if);
         SET_EBDA(ata.channels[count].iobase1, port1);
         SET_EBDA(ata.channels[count].iobase2, port2);
         count++;
@@ -970,6 +941,5 @@ hard_drive_setup()
 
     SET_BDA(disk_control_byte, 0xc0);
 
-    // Enable IRQ14 (handle_76)
-    unmask_pic2(PIC2_IRQ14);
+    enable_hwirq(14, entry_76);
 }