Author: oxygene Date: 2009-03-12 18:00:30 +0100 (Thu, 12 Mar 2009) New Revision: 87
Modified: trunk/filo/drivers/ide_new.c trunk/filo/drivers/ide_new.h Log: Use PCI BARs for I/O ports in new IDE driver. Port from old IDE driver.
Modified: trunk/filo/drivers/ide_new.c =================================================================== --- trunk/filo/drivers/ide_new.c 2009-03-11 03:07:08 UTC (rev 86) +++ trunk/filo/drivers/ide_new.c 2009-03-12 17:00:30 UTC (rev 87) @@ -29,6 +29,10 @@ #include "ide_new.h" #include "hdreg.h"
+#ifdef CONFIG_SUPPORT_PCI +#include <pci.h> +#endif + #if 0 #define dprintf printf #else @@ -44,6 +48,7 @@ #define IDE_NUM_CHANNELS CONFIG_IDE_NUM_CHANNELS #endif #define IDE_MAX_CHANNELS 4 +#define IDE_MAX_DRIVES (IDE_MAX_CHANNELS * 2)
static struct ide_channel ob_ide_channels[IDE_MAX_CHANNELS];
@@ -1150,21 +1155,198 @@ return(drive->bs); }
+#ifdef CONFIG_SUPPORT_PCI +static int pci_find_ata_device_on_bus(int bus, pcidev_t * dev, int *index, int sata, int pata) +{ + int slot, func; + u32 val; + unsigned char hdr; + u32 class; + + for (slot = 0; slot < 0x20; slot++) { + for (func = 0; func < 8; func++) { + pcidev_t currdev = PCI_DEV(bus, slot, func); + + val = pci_read_config32(currdev, REG_VENDOR_ID); + + if (val == 0xffffffff || val == 0x00000000 || + val == 0x0000ffff || val == 0xffff0000) + continue; + + class = pci_read_config16(currdev, 0x0a); + debug("%02x:%02x.%02x [%04x:%04x] class %04x\n", + bus, slot, func, val & 0xffff, val >> 16, class); + + if ((sata && class == 0x180) || (pata && class == 0x101)) { + if (*index == 0) { + *dev = currdev; + return 1; + } + (*index)--; + } + + hdr = pci_read_config8(currdev, REG_HEADER_TYPE) & 0x7f; + + if (hdr == HEADER_TYPE_BRIDGE || hdr == HEADER_TYPE_CARDBUS) { + unsigned int new_bus; + new_bus = (pci_read_config32(currdev, REG_PRIMARY_BUS) >> 8) & 0xff; + if (new_bus == 0) { + debug("Misconfigured bridge at %02x:%02x.%02x skipped.\n", + bus, slot, func); + continue; + } + if (pci_find_ata_device_on_bus(new_bus, dev, index, sata, pata)) + return 1; + } + } + } + + return 0; +} + +int pci_find_ata_device(pcidev_t *dev, int *index, int sata, int pata) +{ + debug(" Scanning for:%s%s\n", sata?" SATA":"", pata?" PATA":""); + return pci_find_ata_device_on_bus(0, dev, index, sata, pata); +} +#endif + + +static void fixupregs(struct ide_channel *chan) +{ + int i; + for (i = 1; i < 8; i++) + chan->io_regs[i] = chan->io_regs[0] + i; + chan->io_regs[9] = chan->io_regs[8] + 1; +} + +static int find_ide_controller_compat(struct ide_channel *chan, int index) +{ +#ifdef CONFIG_SUPPORT_PCI + int skip, i, pci_index = index / 2; + pcidev_t dev; +#else + if (index >= IDE_MAX_CHANNELS) + return -1; +#endif +#ifdef CONFIG_PCMCIA_CF + if (index == 2) { + chan->io_regs[0] = 0x1e0; + chan->io_regs[8] = 0x1ec; + fixupregs(chan); + return 0; + } +#endif +#ifdef CONFIG_SUPPORT_PCI + /* skip any SATA and PATA PCI controllers in native mode */ + for (skip = i = 0; i < pci_index && index; i++) { + int devidx = i; + /* look for i:th ata (IDE/other storage really) device */ + if(!pci_find_ata_device(&dev, &devidx, 1, 1)) + break; + /* only IDE can be in compat mode so skip all others */ + if (pci_read_config16(dev, 0xa) != 0x0101) { + /* other storage (SATA) always has two channels */ + skip += 2; + continue; + } + /* primary in native mode? then skip it. */ + if (1 == (pci_read_config8(dev, 0x09) & 1)) + skip++; + /* secondary in native mode? then skip it. */ + if (index && 4 == (pci_read_config8(dev, 0x09) & 4)) + skip++; + } + index = skip <= index ? index - skip : 0; + debug("skipping %d native PCI controllers, new index=%d\n", skip, index); + if (index >= IDE_MAX_CHANNELS) + return -1; +#endif + chan->io_regs[0] = io_ports[index]; + chan->io_regs[8] = ctl_ports[index]; + fixupregs(chan); + return 0; +} + +#ifdef CONFIG_SUPPORT_PCI +static int find_ide_controller(struct ide_channel *chan, int chan_index) +{ + int pci_index; + pcidev_t dev; + unsigned int mask; + u8 prog_if; + u16 vendor, device, devclass; + + /* A PCI IDE controller has two channels (pri, sec) */ + pci_index = chan_index >> 1; + + /* Find a IDE storage class device */ + + if (!pci_find_ata_device(&dev, &pci_index, 1, 0)) { // S-ATA first + pci_index = chan_index >> 1; + if (!pci_find_ata_device(&dev, &pci_index, 0, 1)) { // P-ATA second + debug("PCI IDE #%d not found\n", chan_index >> 1); + return -1; + } + } + + vendor = pci_read_config16(dev, 0); + device = pci_read_config16(dev, 2); + prog_if = pci_read_config8(dev, 9); + devclass = pci_read_config16(dev, 0x0a); + + debug("found PCI IDE controller %04x:%04x prog_if=%#x\n", + vendor, device, prog_if); + + /* See how this controller is configured */ + mask = (chan_index & 1) ? 4 : 1; + debug("%s channel: ", (chan_index & 1) ? "secondary" : "primary"); + if ((prog_if & mask) || (devclass != 0x0101)) { + debug("native PCI mode\n"); + if ((chan_index & 1) == 0) { + /* Primary channel */ + chan->io_regs[0] = pci_read_resource(dev, 0); // io ports + chan->io_regs[8] = pci_read_resource(dev, 1); // ctrl ports + } else { + /* Secondary channel */ + chan->io_regs[0] = pci_read_resource(dev, 2); // io ports + chan->io_regs[8] = pci_read_resource(dev, 3); // ctrl ports + } + chan->io_regs[0] &= ~3; + chan->io_regs[8] &= ~3; + fixupregs(chan); + } else { + debug("compatibility mode\n"); + if (find_ide_controller_compat(chan, chan_index) != 0) + return -1; + } + return 0; +} +#else /* !CONFIG_SUPPORT_PCI */ +# define find_ide_controller find_ide_controller_compat +#endif //int ob_ide_init(int (*func)(struct ide_drive*)) -int ob_ide_init(void) +int ob_ide_init(int drive) { - int i, j; + int j;
- for (i = 0; i < IDE_NUM_CHANNELS; i++) { - struct ide_channel *chan = &ob_ide_channels[i]; + struct ide_channel *chan; + int chan_index;
- chan->mmio = 0; + if (drive >= IDE_MAX_DRIVES) { + printf("Unsupported drive number\n"); + return -1; + }
- for (j = 0; j < 8; j++) - chan->io_regs[j] = io_ports[i] + j; + /* A controller has two drives (master, slave) */ + chan_index = drive >> 1;
- chan->io_regs[8] = ctl_ports[i]; - chan->io_regs[9] = ctl_ports[i] + 1; + chan = &ob_ide_channels[chan_index]; + if (chan->present == 0) { + if (find_ide_controller(chan, chan_index) != 0) { + printf("IDE channel %d not found\n", chan_index); + return -1; + }
chan->obide_inb = ob_ide_inb; chan->obide_insw = ob_ide_insw; @@ -1172,6 +1354,7 @@ chan->obide_outsw = ob_ide_outsw;
chan->selected = -1; + chan->mmio = 0;
/* * assume it's there, if not io port dead check will clear @@ -1185,17 +1368,17 @@ /* init with a decent value */ chan->drives[j].bs = 512;
- chan->drives[j].nr = i * 2 + j; + chan->drives[j].nr = chan_index * 2 + j; }
ob_ide_probe(chan);
if (!chan->present) - continue; + return -1;
ob_ide_identify_drives(chan);
- printf("ata-%d: [io ports 0x%x-0x%x,0x%x]\n", i, + printf("ata-%d: [io ports 0x%x-0x%x,0x%x]\n", chan_index, chan->io_regs[0], chan->io_regs[0] + 7, chan->io_regs[8]);
@@ -1232,10 +1415,7 @@ int ide_probe(int drive) { struct ide_drive *curr_drive = & ob_ide_channels[drive / 2].drives[drive % 2]; - if (!inited) { - ob_ide_init(); - inited = 1; - } + ob_ide_init(drive);
if (!curr_drive->present) return -1; @@ -1249,10 +1429,7 @@ struct ide_drive *curr_drive = & ob_ide_channels[drive / 2].drives[drive % 2]; char *media = "UNKNOWN";
- if (!inited) { - ob_ide_init(); - inited = 1; - } + ob_ide_init(drive);
if (!curr_drive->present) { return -1; @@ -1300,3 +1477,4 @@ } return 0; } +
Modified: trunk/filo/drivers/ide_new.h =================================================================== --- trunk/filo/drivers/ide_new.h 2009-03-11 03:07:08 UTC (rev 86) +++ trunk/filo/drivers/ide_new.h 2009-03-12 17:00:30 UTC (rev 87) @@ -218,7 +218,7 @@ static int ob_ide_atapi_request_sense(struct ide_drive *drive); //int ob_ide_init(int (*func)(struct ide_drive*)); -int ob_ide_init(void); +int ob_ide_init(int drive);
/* FILO compat */