This patch series enables the ATA code to support using select AHCI controllers in legacy ATA mode when SeaBIOS isn't compiled with the AHCI driver. I've only registered the device id of the controller on my e350m1 board, but it's easy to add more device ids.
Kevin O'Connor (2): Convert ATA pci scan to use pci_device_id table. Add support for white-listing AHCI controllers as ATA compatible.
src/ata.c | 120 ++++++++++++++++++++++++++++++++++++------------------------ 1 files changed, 72 insertions(+), 48 deletions(-)
--- src/ata.c | 104 +++++++++++++++++++++++++++++++++---------------------------- 1 files changed, 56 insertions(+), 48 deletions(-)
diff --git a/src/ata.c b/src/ata.c index 397e402..1540565 100644 --- a/src/ata.c +++ b/src/ata.c @@ -941,14 +941,15 @@ 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(int bdf, 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->iobase1 = port1; @@ -962,66 +963,73 @@ init_controller(int chanid, int bdf, int irq, u32 port1, u32 port2, u32 master) #define IRQ_ATA1 14 #define IRQ_ATA2 15
+// Handle controllers on an ATA PCI device. +static void +init_pciata(u16 bdf, void *arg) +{ + 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); + } + } + + 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(bdf, 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(bdf, irq, port1, port2, master ? master + 8 : 0); +} + +static const struct pci_device_id pci_ata_tbl[] = { + PCI_DEVICE_CLASS(PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE, init_pciata), + PCI_DEVICE_END, +}; + // Locate and init ata controllers. static void ata_init(void) { // Scan PCI bus for ATA adapters - int count=0, pcicount=0; + int 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); - } - } - - 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++; + pci_init_device(pci_ata_tbl, bdf, NULL); }
if (!CONFIG_COREBOOT && !pcicount) { // 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(-1, IRQ_ATA1 , PORT_ATA1_CMD_BASE, PORT_ATA1_CTRL_BASE, 0); - init_controller(1, -1, IRQ_ATA2 + init_controller(-1, IRQ_ATA2 , PORT_ATA2_CMD_BASE, PORT_ATA2_CTRL_BASE, 0); } }
To start, register the AMD ATA controller on the A50M chipset as compatible with ATA mode even if it comes up in AHCI mode. --- src/ata.c | 22 +++++++++++++++++++--- 1 files changed, 19 insertions(+), 3 deletions(-)
diff --git a/src/ata.c b/src/ata.c index 1540565..95e1352 100644 --- a/src/ata.c +++ b/src/ata.c @@ -965,10 +965,9 @@ init_controller(int bdf, int irq, u32 port1, u32 port2, u32 master)
// Handle controllers on an ATA PCI device. static void -init_pciata(u16 bdf, void *arg) +init_pciata(u16 bdf, u8 prog_if) { 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. @@ -1007,8 +1006,25 @@ init_pciata(u16 bdf, void *arg) init_controller(bdf, irq, port1, port2, master ? master + 8 : 0); }
+static void +found_genericata(u16 bdf, void *arg) +{ + init_pciata(bdf, pci_config_readb(bdf, PCI_CLASS_PROG)); +} + +static void +found_compatibleahci(u16 bdf, void *arg) +{ + if (CONFIG_AHCI) + // Already handled directly via native ahci interface. + return; + init_pciata(bdf, 0x8f); +} + static const struct pci_device_id pci_ata_tbl[] = { - PCI_DEVICE_CLASS(PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE, init_pciata), + 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, };