diff options
author | sos <sos@FreeBSD.org> | 2003-07-02 10:50:44 +0000 |
---|---|---|
committer | sos <sos@FreeBSD.org> | 2003-07-02 10:50:44 +0000 |
commit | 50b0b9ea2f2d26323c199bc837b228b8f2c87837 (patch) | |
tree | 95c6e3e670c8a36907b5836fe67f4b0c35f18f4e | |
parent | f7b1b6fb60e6beaabbb08943e9e4530ced84cabd (diff) | |
download | FreeBSD-src-50b0b9ea2f2d26323c199bc837b228b8f2c87837.zip FreeBSD-src-50b0b9ea2f2d26323c199bc837b228b8f2c87837.tar.gz |
Update the SATA support code to work more correctly with
real SATA disks now that I can test it.
Add support for the SiI 3112 SATA chip using memory mapped I/O.
Update the support for the SiI 0680 to use the memio interface as well.
Sponsored by: David Leimbach <leimy2k@mac.com> (3112 based controller)
Sponsored by: FreeBSD Systems (www.FreeBSDsystems.com) (SATA disks)
-rw-r--r-- | sys/dev/ata/ata-chipset.c | 160 | ||||
-rw-r--r-- | sys/dev/ata/ata-pci.c | 11 | ||||
-rw-r--r-- | sys/dev/ata/ata-pci.h | 7 |
3 files changed, 121 insertions, 57 deletions
diff --git a/sys/dev/ata/ata-chipset.c b/sys/dev/ata/ata-chipset.c index e831fce..d731265 100644 --- a/sys/dev/ata/ata-chipset.c +++ b/sys/dev/ata/ata-chipset.c @@ -93,6 +93,8 @@ static int ata_promise_mio_dmastop(struct ata_channel *); static int ata_serverworks_chipinit(device_t); static void ata_serverworks_setmode(struct ata_device *, int); static int ata_sii_chipinit(device_t); +static int ata_sii_mio_allocate(device_t, struct ata_channel *); +static void ata_sii_intr(void *); static void ata_cmd_intr(void *); static void ata_sii_setmode(struct ata_device *, int); static void ata_cmd_setmode(struct ata_device *, int); @@ -838,11 +840,6 @@ ata_intel_new_setmode(struct ata_device *atadev, int mode) mode = ata_limit_mode(atadev, mode, ctlr->chip->max_dma); - if (mode >= ATA_SA150) { - atadev->mode = mode; - return; - } - if (ctlr->chip->max_dma && mode > ATA_UDMA2 && !(reg54 & (0x10 << devno))) { ata_prtdev(atadev,"DMA limited to UDMA33, non-ATA66 cable or device\n"); mode = ATA_UDMA2; @@ -854,7 +851,10 @@ ata_intel_new_setmode(struct ata_device *atadev, int mode) ata_prtdev(atadev, "%s setting %s on %s chip\n", (error) ? "failed" : "success", ata_mode2str(mode), ctlr->chip->text); - if (!error) { + if (error) + return; + + if (ctlr->chip->max_dma < ATA_SA150) { if (mode >= ATA_UDMA0) { pci_write_config(parent, 0x48, reg48 | (0x0001 << devno), 2); pci_write_config(parent, 0x4a, (reg4a & ~(0x3 << (devno<<2))) | @@ -894,8 +894,8 @@ ata_intel_new_setmode(struct ata_device *atadev, int mode) } pci_write_config(parent, 0x40, (reg40 & ~mask40) | new40, 4); pci_write_config(parent, 0x44, (reg44 & ~mask44) | new44, 1); - atadev->mode = mode; } + atadev->mode = mode; } /* @@ -1244,11 +1244,6 @@ ata_promise_setmode(struct ata_device *atadev, int mode) break; } - if (mode >= ATA_SA150) { - atadev->mode = mode; - return; - } - error = ata_command(atadev, ATA_C_SETFEATURES, 0, mode, ATA_C_F_SETXFER, ATA_WAIT_READY); if (bootverbose) @@ -1458,11 +1453,12 @@ ata_sii_ident(device_t dev) struct ata_pci_controller *ctlr = device_get_softc(dev); struct ata_chip_id *idx; static struct ata_chip_id ids[] = - {{ ATA_SII0680, 0x00, 0, SII_SETCLK, ATA_UDMA6, "SiI 0680" }, - { ATA_CMD649, 0x00, 0, SII_INTR|SII_ENINTR, ATA_UDMA5, "CMD 649" }, - { ATA_CMD648, 0x00, 0, SII_INTR|SII_ENINTR, ATA_UDMA4, "CMD 648" }, - { ATA_CMD646, 0x07, 0, SII_ENINTR, ATA_UDMA2, "CMD 646U2" }, - { ATA_CMD646, 0x00, 0, SII_ENINTR, ATA_WDMA2, "CMD 646" }, + {{ ATA_SII3112, 0x00, SIIMEMIO, 0, ATA_SA150, "SiI 3112" }, + { ATA_SII0680, 0x00, SIIMEMIO, SIISETCLK, ATA_UDMA6, "SiI 0680" }, + { ATA_CMD649, 0x00, 0, SIIINTR, ATA_UDMA5, "CMD 649" }, + { ATA_CMD648, 0x00, 0, SIIINTR, ATA_UDMA4, "CMD 648" }, + { ATA_CMD646, 0x07, 0, 0, ATA_UDMA2, "CMD 646U2" }, + { ATA_CMD646, 0x00, 0, 0, ATA_WDMA2, "CMD 646" }, { 0, 0, 0, 0, 0, 0}}; char buffer[64]; @@ -1487,38 +1483,105 @@ ata_sii_chipinit(device_t dev) device_printf(dev, "unable to map interrupt\n"); return ENXIO; } - if ((bus_setup_intr(dev, ctlr->r_irq, INTR_TYPE_BIO | INTR_ENTROPY, - ctlr->chip->cfg2 & SII_INTR ? - ata_cmd_intr : ata_generic_intr, - ctlr, &ctlr->handle))) { - device_printf(dev, "unable to setup interrupt\n"); - return ENXIO; + + if (ctlr->chip->cfg1 == SIIMEMIO) { + if ((bus_setup_intr(dev, ctlr->r_irq, INTR_TYPE_BIO | INTR_ENTROPY, + ata_sii_intr, ctlr, &ctlr->handle))) { + device_printf(dev, "unable to setup interrupt\n"); + return ENXIO; + } + rid = 0x24; + if (!(ctlr->r_io2 = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, + 0, ~0, 1, RF_ACTIVE))) + return ENXIO; + + if (ctlr->chip->cfg2 & SIISETCLK) { + if ((pci_read_config(dev, 0x8a, 1) & 0x30) != 0x10) + pci_write_config(dev, 0x8a, + (pci_read_config(dev, 0x8a, 1) & 0x0F)|0x10,1); + if ((pci_read_config(dev, 0x8a, 1) & 0x30) != 0x10) + device_printf(dev, "%s could not set ATA133 clock\n", + ctlr->chip->text); + } + ctlr->allocate = ata_sii_mio_allocate; + ctlr->setmode = ata_sii_setmode; } + else { + if ((bus_setup_intr(dev, ctlr->r_irq, INTR_TYPE_BIO | INTR_ENTROPY, + ctlr->chip->cfg2 & SIIINTR ? + ata_cmd_intr : ata_generic_intr, + ctlr, &ctlr->handle))) { + device_printf(dev, "unable to setup interrupt\n"); + return ENXIO; + } + + if ((pci_read_config(dev, 0x51, 1) & 0x08) != 0x08) { + device_printf(dev, "HW has secondary channel disabled\n"); + ctlr->channels = 1; + } - if (ctlr->chip->cfg2 & SII_ENINTR) + /* enable interrupt as BIOS might not */ pci_write_config(dev, 0x71, 0x01, 1); - if (ctlr->chip->cfg2 & SII_SETCLK) { - if ((pci_read_config(dev, 0x8a, 1) & 0x30) != 0x10) - pci_write_config(dev, 0x8a, - (pci_read_config(dev, 0x8a, 1) & 0x0F) | 0x10, 1); - if ((pci_read_config(dev, 0x8a, 1) & 0x30) != 0x10) - device_printf(dev, "%s could not set ATA133 clock\n", - ctlr->chip->text); - ctlr->setmode = ata_sii_setmode; + ctlr->setmode = ata_cmd_setmode; } - else - ctlr->setmode = ata_cmd_setmode; + return 0; +} - if ((pci_read_config(dev, 0x51, 1) & 0x08) != 0x08) { - device_printf(dev, "secondary channel disabled\n"); - ctlr->channels = 1; - } +static int +ata_sii_mio_allocate(device_t dev, struct ata_channel *ch) +{ + struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); + int i; + for (i = ATA_DATA; i <= ATA_STATUS; i++) { + ch->r_io[i].res = ctlr->r_io2; + ch->r_io[i].offset = 0x80 + i + (ch->unit << 6); + } + ch->r_io[ATA_ALTSTAT].res = ctlr->r_io2; + ch->r_io[ATA_ALTSTAT].offset = 0x8a + (ch->unit << 6); + ch->r_io[ATA_BMCMD_PORT].res = ctlr->r_io2; + ch->r_io[ATA_BMCMD_PORT].offset = 0x00 + (ch->unit << 3); + ch->r_io[ATA_BMSTAT_PORT].res = ctlr->r_io2; + ch->r_io[ATA_BMSTAT_PORT].offset = 0x02 + (ch->unit << 3); + ch->r_io[ATA_BMDTP_PORT].res = ctlr->r_io2; + ch->r_io[ATA_BMDTP_PORT].offset = 0x04 + (ch->unit << 3); + ch->r_io[ATA_BMDEVSPEC_0].res = ctlr->r_io2; + ch->r_io[ATA_BMDEVSPEC_0].offset = 0xa1 + (ch->unit << 6); + ch->r_io[ATA_IDX_ADDR].res = ctlr->r_io2; + + if (ctlr->chip->max_dma >= ATA_SA150) + ch->flags |= ATA_NO_SLAVE; + ctlr->dmainit(ch); return 0; } static void +ata_sii_intr(void *data) +{ + struct ata_pci_controller *ctlr = data; + struct ata_channel *ch; + u_int8_t dmastat; + int unit; + + /* implement this as a toggle instead to balance load XXX */ + for (unit = 0; unit < 2; unit++) { + if (!(ch = ctlr->interrupt[unit].argument)) + continue; + if (ATA_IDX_INB(ch, ATA_BMDEVSPEC_0) & 0x08) { + if (ch->dma->flags & ATA_DMA_ACTIVE) { + if (!((dmastat = (ATA_IDX_INB(ch, ATA_BMSTAT_PORT) & + ATA_BMSTAT_MASK)) & ATA_BMSTAT_INTERRUPT)) + continue; + ATA_IDX_OUTB(ch, ATA_BMSTAT_PORT, dmastat|ATA_BMSTAT_INTERRUPT); + DELAY(1); + } + ctlr->interrupt[unit].function(ch); + } + } +} + +static void ata_cmd_intr(void *data) { struct ata_pci_controller *ctlr = data; @@ -1551,7 +1614,7 @@ ata_sii_setmode(struct ata_device *atadev, int mode) { device_t parent = device_get_parent(atadev->channel->dev); struct ata_pci_controller *ctlr = device_get_softc(parent); - int devno = (atadev->channel->unit << 4) + (ATA_DEV(atadev->unit) << 1); + int rego = (atadev->channel->unit << 4) + (ATA_DEV(atadev->unit) << 1); int mreg = atadev->channel->unit ? 0x84 : 0x80; int mask = 0x03 << (ATA_DEV(atadev->unit) << 2); int mval = pci_read_config(parent, mreg, 1) & ~mask; @@ -1559,7 +1622,8 @@ ata_sii_setmode(struct ata_device *atadev, int mode) mode = ata_limit_mode(atadev, mode, ctlr->chip->max_dma); - mode = ata_check_80pin(atadev, mode); + if (ctlr->chip->max_dma < ATA_SA150) + mode = ata_check_80pin(atadev, mode); error = ata_command(atadev, ATA_C_SETFEATURES, 0, mode, ATA_C_F_SETXFER, ATA_WAIT_READY); @@ -1567,20 +1631,24 @@ ata_sii_setmode(struct ata_device *atadev, int mode) ata_prtdev(atadev, "%s setting %s on %s chip\n", (error) ? "failed" : "success", ata_mode2str(mode), ctlr->chip->text); - if (!error) { + + if (error) + return; + + if (ctlr->chip->max_dma < ATA_SA150) { if (mode >= ATA_UDMA0) { u_int8_t udmatimings[] = { 0xf, 0xb, 0x7, 0x5, 0x3, 0x2, 0x1 }; - u_int8_t ureg = 0xac + devno; + u_int8_t ureg = 0xac + rego; pci_write_config(parent, mreg, mval | (0x03 << (ATA_DEV(atadev->unit) << 2)), 1); pci_write_config(parent, ureg, - (pci_read_config(parent, ureg, 1) & 0x3f) | + (pci_read_config(parent, ureg, 1) & ~0x3f) | udmatimings[mode & ATA_MODE_MASK], 1); } else if (mode >= ATA_WDMA0) { - u_int8_t dreg = 0xa8 + devno; + u_int8_t dreg = 0xa8 + rego; u_int16_t dmatimings[] = { 0x2208, 0x10c2, 0x10c1 }; pci_write_config(parent, mreg, @@ -1589,15 +1657,15 @@ ata_sii_setmode(struct ata_device *atadev, int mode) } else { - u_int8_t preg = 0xa4 + devno; + u_int8_t preg = 0xa4 + rego; u_int16_t piotimings[] = { 0x328a, 0x2283, 0x1104, 0x10c3, 0x10c1 }; pci_write_config(parent, mreg, mval | (0x01 << (ATA_DEV(atadev->unit) << 2)), 1); pci_write_config(parent, preg, piotimings[mode & ATA_MODE_MASK], 2); } - atadev->mode = mode; } + atadev->mode = mode; } static void diff --git a/sys/dev/ata/ata-pci.c b/sys/dev/ata/ata-pci.c index 2eddd9d..7027da7 100644 --- a/sys/dev/ata/ata-pci.c +++ b/sys/dev/ata/ata-pci.c @@ -152,18 +152,13 @@ ata_pci_attach(device_t dev) cmd = pci_read_config(dev, PCIR_COMMAND, 2); } #endif - /* is busmastering supported and configured ? */ + /* if busmastering configured get the I/O resource */ if ((cmd & PCIM_CMD_BUSMASTEREN) == PCIM_CMD_BUSMASTEREN) { int rid = ATA_BMADDR_RID; - if (!ctlr->r_io2) { - if (!(ctlr->r_io1 = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, - 0, ~0, 1, RF_ACTIVE))) - device_printf(dev, "Busmastering DMA not configured\n"); - } + ctlr->r_io1 = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, + 0, ~0, 1, RF_ACTIVE); } - else - device_printf(dev, "Busmastering DMA not supported\n"); ctlr->chipinit(dev); diff --git a/sys/dev/ata/ata-pci.h b/sys/dev/ata/ata-pci.h index acad8e7..9cb19ca 100644 --- a/sys/dev/ata/ata-pci.h +++ b/sys/dev/ata/ata-pci.h @@ -154,6 +154,7 @@ struct ata_pci_controller { #define ATA_SILICON_IMAGE_ID 0x1095 #define ATA_SII0680 0x06801095 +#define ATA_SII3112 0x31121095 #define ATA_CMD646 0x06461095 #define ATA_CMD648 0x06481095 #define ATA_CMD649 0x06491095 @@ -242,9 +243,9 @@ struct ata_pci_controller { #define SWKS66 1 #define SWKS100 2 -#define SII_INTR 0x01 -#define SII_SETCLK 0x02 -#define SII_ENINTR 0x04 +#define SIIMEMIO 1 +#define SIIINTR 0x01 +#define SIISETCLK 0x02 #define SIS_SOUTH 1 #define SIS133NEW 2 |