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 */