grml...
[seabios.git] / src / ata.c
index 397e4022a7990e5fb1d78e0c24193d80428833e9..76e4f20d2f9cd6b35a078d9e2200a8ef21969c7d 100644 (file)
--- a/src/ata.c
+++ b/src/ata.c
@@ -776,7 +776,7 @@ init_drive_atapi(struct atadrive_s *dummy, u16 *buffer)
 
     // fill cdidmap
     if (iscd) {
-        int prio = bootprio_find_ata_device(adrive_g->chan_gf->pci_bdf,
+        int prio = bootprio_find_ata_device(adrive_g->chan_gf->pci_tmp,
                                             adrive_g->chan_gf->chanid,
                                             adrive_g->slave);
         boot_add_cd(&adrive_g->drive, desc, prio);
@@ -826,7 +826,7 @@ init_drive_ata(struct atadrive_s *dummy, u16 *buffer)
                           , (u32)adjsize, adjprefix);
     dprintf(1, "%s\n", desc);
 
-    int prio = bootprio_find_ata_device(adrive_g->chan_gf->pci_bdf,
+    int prio = bootprio_find_ata_device(adrive_g->chan_gf->pci_tmp,
                                         adrive_g->chan_gf->chanid,
                                         adrive_g->slave);
     // Register with bcv system.
@@ -941,88 +941,115 @@ ata_detect(void *data)
 
 // Initialize an ata controller and detect its drives.
 static void
-init_controller(int chanid, int bdf, int irq, u32 port1, u32 port2, u32 master)
+init_controller(struct pci_device *pci, int irq
+                , u32 port1, u32 port2, u32 master)
 {
+    static int chanid = 0;
     struct ata_channel_s *chan_gf = malloc_fseg(sizeof(*chan_gf));
     if (!chan_gf) {
         warn_noalloc();
         return;
     }
-    chan_gf->chanid = chanid;
+    chan_gf->chanid = chanid++;
     chan_gf->irq = irq;
-    chan_gf->pci_bdf = bdf;
+    chan_gf->pci_bdf = pci ? pci->bdf : -1;
+    chan_gf->pci_tmp = pci;
     chan_gf->iobase1 = port1;
     chan_gf->iobase2 = port2;
     chan_gf->iomaster = master;
     dprintf(1, "ATA controller %d at %x/%x/%x (irq %d dev %x)\n"
-            , chanid, port1, port2, master, irq, bdf);
+            , chanid, port1, port2, master, irq, chan_gf->pci_bdf);
     run_thread(ata_detect, chan_gf);
 }
 
 #define IRQ_ATA1 14
 #define IRQ_ATA2 15
 
-// Locate and init ata controllers.
+// Handle controllers on an ATA PCI device.
 static void
-ata_init(void)
+init_pciata(struct pci_device *pci, u8 prog_if)
 {
-    // Scan PCI bus for ATA adapters
-    int count=0, pcicount=0;
-    int bdf, max;
-    foreachpci(bdf, max) {
-        pcicount++;
-        if (pci_config_readw(bdf, PCI_CLASS_DEVICE) != PCI_CLASS_STORAGE_IDE)
-            continue;
-
-        u8 pciirq = pci_config_readb(bdf, PCI_INTERRUPT_LINE);
-        u8 prog_if = pci_config_readb(bdf, PCI_CLASS_PROG);
-        int master = 0;
-        if (CONFIG_ATA_DMA && prog_if & 0x80) {
-            // Check for bus-mastering.
-            u32 bar = pci_config_readl(bdf, PCI_BASE_ADDRESS_4);
-            if (bar & PCI_BASE_ADDRESS_SPACE_IO) {
-                master = bar & PCI_BASE_ADDRESS_IO_MASK;
-                pci_config_maskw(bdf, PCI_COMMAND, 0, PCI_COMMAND_MASTER);
-            }
+    pci->have_driver = 1;
+    u16 bdf = pci->bdf;
+    u8 pciirq = pci_config_readb(bdf, PCI_INTERRUPT_LINE);
+    int master = 0;
+    if (CONFIG_ATA_DMA && prog_if & 0x80) {
+        // Check for bus-mastering.
+        u32 bar = pci_config_readl(bdf, PCI_BASE_ADDRESS_4);
+        if (bar & PCI_BASE_ADDRESS_SPACE_IO) {
+            master = bar & PCI_BASE_ADDRESS_IO_MASK;
+            pci_config_maskw(bdf, PCI_COMMAND, 0, PCI_COMMAND_MASTER);
         }
+    }
 
-        u32 port1, port2, irq;
-        if (prog_if & 1) {
-            port1 = (pci_config_readl(bdf, PCI_BASE_ADDRESS_0)
-                     & PCI_BASE_ADDRESS_IO_MASK);
-            port2 = (pci_config_readl(bdf, PCI_BASE_ADDRESS_1)
-                     & PCI_BASE_ADDRESS_IO_MASK);
-            irq = pciirq;
-        } else {
-            port1 = PORT_ATA1_CMD_BASE;
-            port2 = PORT_ATA1_CTRL_BASE;
-            irq = IRQ_ATA1;
-        }
-        init_controller(count, bdf, irq, port1, port2, master);
-        count++;
-
-        if (prog_if & 4) {
-            port1 = (pci_config_readl(bdf, PCI_BASE_ADDRESS_2)
-                     & PCI_BASE_ADDRESS_IO_MASK);
-            port2 = (pci_config_readl(bdf, PCI_BASE_ADDRESS_3)
-                     & PCI_BASE_ADDRESS_IO_MASK);
-            irq = pciirq;
-        } else {
-            port1 = PORT_ATA2_CMD_BASE;
-            port2 = PORT_ATA2_CTRL_BASE;
-            irq = IRQ_ATA2;
-        }
-        init_controller(count, bdf, irq, port1, port2, master ? master + 8 : 0);
-        count++;
+    u32 port1, port2, irq;
+    if (prog_if & 1) {
+        port1 = (pci_config_readl(bdf, PCI_BASE_ADDRESS_0)
+                 & PCI_BASE_ADDRESS_IO_MASK);
+        port2 = (pci_config_readl(bdf, PCI_BASE_ADDRESS_1)
+                 & PCI_BASE_ADDRESS_IO_MASK);
+        irq = pciirq;
+    } else {
+        port1 = PORT_ATA1_CMD_BASE;
+        port2 = PORT_ATA1_CTRL_BASE;
+        irq = IRQ_ATA1;
+    }
+    init_controller(pci, irq, port1, port2, master);
+
+    if (prog_if & 4) {
+        port1 = (pci_config_readl(bdf, PCI_BASE_ADDRESS_2)
+                 & PCI_BASE_ADDRESS_IO_MASK);
+        port2 = (pci_config_readl(bdf, PCI_BASE_ADDRESS_3)
+                 & PCI_BASE_ADDRESS_IO_MASK);
+        irq = pciirq;
+    } else {
+        port1 = PORT_ATA2_CMD_BASE;
+        port2 = PORT_ATA2_CTRL_BASE;
+        irq = IRQ_ATA2;
     }
+    init_controller(pci, irq, port1, port2, master ? master + 8 : 0);
+}
+
+static void
+found_genericata(struct pci_device *pci, void *arg)
+{
+    init_pciata(pci, pci->prog_if);
+}
+
+static void
+found_compatibleahci(struct pci_device *pci, void *arg)
+{
+    if (CONFIG_AHCI)
+        // Already handled directly via native ahci interface.
+        return;
+    init_pciata(pci, 0x8f);
+}
+
+static const struct pci_device_id pci_ata_tbl[] = {
+    PCI_DEVICE_CLASS(PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE
+                     , found_genericata),
+    PCI_DEVICE(PCI_VENDOR_ID_ATI, 0x4391, found_compatibleahci),
+    PCI_DEVICE_END,
+};
 
-    if (!CONFIG_COREBOOT && !pcicount) {
+// Locate and init ata controllers.
+static void
+ata_init(void)
+{
+    if (!CONFIG_COREBOOT && !PCIDevices) {
         // No PCI devices found - probably a QEMU "-M isapc" machine.
         // Try using ISA ports for ATA controllers.
-        init_controller(0, -1, IRQ_ATA1
+        init_controller(NULL, IRQ_ATA1
                         , PORT_ATA1_CMD_BASE, PORT_ATA1_CTRL_BASE, 0);
-        init_controller(1, -1, IRQ_ATA2
+        init_controller(NULL, IRQ_ATA2
                         , PORT_ATA2_CMD_BASE, PORT_ATA2_CTRL_BASE, 0);
+        return;
+    }
+
+    // Scan PCI bus for ATA adapters
+    struct pci_device *pci;
+    foreachpci(pci) {
+        pci_init_device(pci_ata_tbl, pci, NULL);
     }
 }