diff options
Diffstat (limited to 'sys/dev/pci/pciide.c')
-rw-r--r-- | sys/dev/pci/pciide.c | 1611 |
1 files changed, 1006 insertions, 605 deletions
diff --git a/sys/dev/pci/pciide.c b/sys/dev/pci/pciide.c index a4d86436a8a..db517e42da0 100644 --- a/sys/dev/pci/pciide.c +++ b/sys/dev/pci/pciide.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pciide.c,v 1.9 1999/09/01 04:32:14 csapuntz Exp $ */ +/* $OpenBSD: pciide.c,v 1.10 1999/10/04 22:54:18 deraadt Exp $ */ /* $NetBSD: pciide.c,v 1.40 1999/07/12 13:49:38 bouyer Exp $ */ /* @@ -79,6 +79,7 @@ int wdcdebug_pciide_mask = 0; #include <dev/pci/pciide_cy693_reg.h> #include <dev/pci/pciide_sis_reg.h> #include <dev/pci/pciide_acer_reg.h> +#include <dev/pci/pciide_pdc202xx_reg.h> #include <dev/ata/atavar.h> #include <dev/ic/wdcreg.h> #include <dev/ic/wdcvar.h> @@ -153,170 +154,129 @@ struct pciide_softc { } pciide_channels[PCIIDE_NUM_CHANNELS]; }; -void default_setup_cap __P((struct pciide_softc*)); -void default_setup_chip __P((struct pciide_softc*)); -void default_channel_map __P((struct pci_attach_args *, - struct pciide_channel *)); +void default_chip_map __P((struct pciide_softc*, struct pci_attach_args*)); -void piix_setup_cap __P((struct pciide_softc*)); -void piix_setup_chip __P((struct pciide_softc*)); +void piix_chip_map __P((struct pciide_softc*, struct pci_attach_args*)); void piix_setup_channel __P((struct channel_softc*)); -void piix3_4_setup_chip __P((struct pciide_softc*)); void piix3_4_setup_channel __P((struct channel_softc*)); -void piix_channel_map __P((struct pci_attach_args *, struct pciide_channel *)); + static u_int32_t piix_setup_idetim_timings __P((u_int8_t, u_int8_t, u_int8_t)); static u_int32_t piix_setup_idetim_drvs __P((struct ata_drive_datas*)); static u_int32_t piix_setup_sidetim_timings __P((u_int8_t, u_int8_t, u_int8_t)); -void apollo_setup_cap __P((struct pciide_softc*)); -void apollo_setup_chip __P((struct pciide_softc*)); +void apollo_chip_map __P((struct pciide_softc*, struct pci_attach_args*)); void apollo_setup_channel __P((struct channel_softc*)); -void apollo_channel_map __P((struct pci_attach_args *, - struct pciide_channel *)); -void cmd0643_6_setup_cap __P((struct pciide_softc*)); -void cmd0643_6_setup_chip __P((struct pciide_softc*)); +void cmd_chip_map __P((struct pciide_softc*, struct pci_attach_args*)); +void cmd0643_6_chip_map __P((struct pciide_softc*, struct pci_attach_args*)); void cmd0643_6_setup_channel __P((struct channel_softc*)); -void cmd_channel_map __P((struct pci_attach_args *, struct pciide_channel *)); +void cmd_channel_map __P((struct pci_attach_args *, + struct pciide_softc *, int)); +int cmd_pci_intr __P((void *)); -void cy693_setup_cap __P((struct pciide_softc*)); -void cy693_setup_chip __P((struct pciide_softc*)); +void cy693_chip_map __P((struct pciide_softc*, struct pci_attach_args*)); void cy693_setup_channel __P((struct channel_softc*)); -void cy693_channel_map __P((struct pci_attach_args *, struct pciide_channel *)); -void sis_setup_cap __P((struct pciide_softc*)); -void sis_setup_chip __P((struct pciide_softc*)); +void sis_chip_map __P((struct pciide_softc*, struct pci_attach_args*)); void sis_setup_channel __P((struct channel_softc*)); -void sis_channel_map __P((struct pci_attach_args *, struct pciide_channel *)); -void acer_setup_cap __P((struct pciide_softc*)); -void acer_setup_chip __P((struct pciide_softc*)); +void acer_chip_map __P((struct pciide_softc*, struct pci_attach_args*)); void acer_setup_channel __P((struct channel_softc*)); -void acer_channel_map __P((struct pci_attach_args *, struct pciide_channel *)); +int acer_pci_intr __P((void *)); +void pdc202xx_chip_map __P((struct pciide_softc*, struct pci_attach_args*)); +void pdc202xx_setup_channel __P((struct channel_softc*)); +int pdc202xx_pci_intr __P((void *)); + void pciide_channel_dma_setup __P((struct pciide_channel *)); int pciide_dma_table_setup __P((struct pciide_softc*, int, int)); int pciide_dma_init __P((void*, int, int, void *, size_t, int)); void pciide_dma_start __P((void*, int, int, int)); int pciide_dma_finish __P((void*, int, int, int)); void pciide_print_modes __P((struct pciide_channel *)); +void pciide_print_channels __P((int, pcireg_t));; struct pciide_product_desc { u_int32_t ide_product; u_short ide_flags; - u_short ide_num_channels; - /* init controller's capabilities for drives probe */ - void (*setup_cap) __P((struct pciide_softc*)); - /* init controller after drives probe */ - void (*setup_chip) __P((struct pciide_softc*)); - /* map channel if possible/necessary */ - void (*channel_map) __P((struct pci_attach_args *, - struct pciide_channel *)); + /* map and setup chip, probe drives */ + void (*chip_map) __P((struct pciide_softc*, struct pci_attach_args*)); }; /* Flags for ide_flags */ -#define CMD_PCI064x_IOEN 0x01 /* CMD-style PCI_COMMAND_IO_ENABLE */ -#define ONE_QUEUE 0x02 /* device need serialised access */ +#define IDE_PCI_CLASS_OVERRIDE 0x0001 /* accept even if class != pciide */ /* Default product description for devices not known from this controller */ const struct pciide_product_desc default_product_desc = { 0, /* Generic PCI IDE controller */ 0, - PCIIDE_NUM_CHANNELS, - default_setup_cap, - default_setup_chip, - default_channel_map + default_chip_map }; const struct pciide_product_desc pciide_intel_products[] = { { PCI_PRODUCT_INTEL_82092AA, /* Intel 82092AA IDE */ 0, - PCIIDE_NUM_CHANNELS, - default_setup_cap, - default_setup_chip, - default_channel_map + default_chip_map }, { PCI_PRODUCT_INTEL_82371FB_IDE, /* Intel 82371FB IDE (PIIX) */ 0, - PCIIDE_NUM_CHANNELS, - piix_setup_cap, - piix_setup_chip, - piix_channel_map + piix_chip_map }, { PCI_PRODUCT_INTEL_82371SB_IDE, /* Intel 82371SB IDE (PIIX3) */ 0, - PCIIDE_NUM_CHANNELS, - piix_setup_cap, - piix3_4_setup_chip, - piix_channel_map + piix_chip_map }, { PCI_PRODUCT_INTEL_82371AB_IDE, /* Intel 82371AB IDE (PIIX4) */ 0, - PCIIDE_NUM_CHANNELS, - piix_setup_cap, - piix3_4_setup_chip, - piix_channel_map - } + piix_chip_map + }, + { PCI_PRODUCT_INTEL_82801AA_IDE, + 0, + piix_chip_map, + }, + { PCI_PRODUCT_INTEL_82801AB_IDE, + 0, + piix_chip_map, + }, }; const struct pciide_product_desc pciide_cmd_products[] = { { PCI_PRODUCT_CMDTECH_640, /* CMD Technology PCI0640 */ - ONE_QUEUE | CMD_PCI064x_IOEN, - PCIIDE_NUM_CHANNELS, - default_setup_cap, - default_setup_chip, - cmd_channel_map + 0, + cmd_chip_map }, { PCI_PRODUCT_CMDTECH_643, /* CMD Technology PCI0643 */ - ONE_QUEUE | CMD_PCI064x_IOEN, - PCIIDE_NUM_CHANNELS, - cmd0643_6_setup_cap, - cmd0643_6_setup_chip, - cmd_channel_map + 0, + cmd0643_6_chip_map }, { PCI_PRODUCT_CMDTECH_646, /* CMD Technology PCI0646 */ - ONE_QUEUE | CMD_PCI064x_IOEN, - PCIIDE_NUM_CHANNELS, - cmd0643_6_setup_cap, - cmd0643_6_setup_chip, - cmd_channel_map + 0, + cmd0643_6_chip_map } }; const struct pciide_product_desc pciide_via_products[] = { { PCI_PRODUCT_VIATECH_VT82C586_IDE, /* VIA VT82C586 (Apollo VP) IDE */ 0, - PCIIDE_NUM_CHANNELS, - apollo_setup_cap, - apollo_setup_chip, - apollo_channel_map + apollo_chip_map }, { PCI_PRODUCT_VIATECH_VT82C586A_IDE, /* VIA VT82C586A IDE */ 0, - PCIIDE_NUM_CHANNELS, - apollo_setup_cap, - apollo_setup_chip, - apollo_channel_map + apollo_chip_map } }; const struct pciide_product_desc pciide_cypress_products[] = { { PCI_PRODUCT_CONTAQ_82C693, /* Contaq CY82C693 IDE */ 0, - 1, - cy693_setup_cap, - cy693_setup_chip, - cy693_channel_map + cy693_chip_map } }; const struct pciide_product_desc pciide_sis_products[] = { { PCI_PRODUCT_SIS_5597, /* SIS 5597/5598 IDE */ 0, - PCIIDE_NUM_CHANNELS, - sis_setup_cap, - sis_setup_chip, - sis_channel_map + sis_chip_map } }; @@ -324,14 +284,22 @@ const struct pciide_product_desc pciide_sis_products[] = { const struct pciide_product_desc pciide_acer_products[] = { { PCI_PRODUCT_ALI_M5229, /* Acer Labs M5229 UDMA IDE */ 0, - PCIIDE_NUM_CHANNELS, - acer_setup_cap, - acer_setup_chip, - acer_channel_map + acer_chip_map } }; #endif +const struct pciide_product_desc pciide_promise_products[] = { + { PCI_PRODUCT_PROMISE_ULTRA33, + IDE_PCI_CLASS_OVERRIDE, + pdc202xx_chip_map, + }, + { PCI_PRODUCT_PROMISE_ULTRA66, + IDE_PCI_CLASS_OVERRIDE, + pdc202xx_chip_map, + } +}; + struct pciide_vendor_desc { u_int32_t ide_vendor; const struct pciide_product_desc *ide_products; @@ -351,8 +319,10 @@ const struct pciide_vendor_desc pciide_vendors[] = { sizeof(pciide_sis_products)/sizeof(pciide_sis_products[0]) }, #ifdef notyet { PCI_VENDOR_ALI, pciide_acer_products, - sizeof(pciide_acer_products)/sizeof(pciide_acer_products[0]) } + sizeof(pciide_acer_products)/sizeof(pciide_acer_products[0]) }, #endif + { PCI_VENDOR_PROMISE, pciide_promise_products, + sizeof(pciide_promise_products)/sizeof(pciide_promise_products[0]) } }; #define PCIIDE_CHANNEL_NAME(chan) ((chan) == 0 ? "channel 0" : "channel 1") @@ -376,12 +346,18 @@ struct cfdriver pciide_cd = { NULL, "pciide", DV_DULL }; #endif +int pciide_chipen __P((struct pciide_softc *, struct pci_attach_args *)); int pciide_mapregs_compat __P(( struct pci_attach_args *, struct pciide_channel *, int, bus_size_t *, bus_size_t*)); int pciide_mapregs_native __P((struct pci_attach_args *, - struct pciide_channel *, bus_size_t *, bus_size_t *)); + struct pciide_channel *, bus_size_t *, bus_size_t *, + int (*pci_intr) __P((void *)))); +void pciide_mapreg_dma __P((struct pciide_softc *, + struct pci_attach_args *)); +int pciide_chansetup __P((struct pciide_softc *, int, pcireg_t)); void pciide_mapchan __P((struct pci_attach_args *, - struct pciide_channel *, int, bus_size_t *, bus_size_t *)); + struct pciide_channel *, pcireg_t, bus_size_t *, bus_size_t *, + int (*pci_intr) __P((void *)))); int pciiide_chan_candisable __P((struct pciide_channel *)); void pciide_map_compat_intr __P(( struct pci_attach_args *, struct pciide_channel *, int, int)); @@ -427,6 +403,7 @@ pciide_match(parent, match, aux) void *aux; { struct pci_attach_args *pa = aux; + const struct pciide_product_desc *pp; /* * Check the ID register to see that it's a PCI IDE controller. @@ -438,6 +415,15 @@ pciide_match(parent, match, aux) return (1); } + /* + * Some controllers (e.g. promise Ultra-33) don't claim to be PCI IDE + * controllers. Let see if we can deal with it anyway. + */ + pp = pciide_lookup_product(pa->pa_id); + if (pp && (pp->ide_flags & IDE_PCI_CLASS_OVERRIDE)) { + return (1); + } + return (0); } @@ -451,136 +437,27 @@ pciide_attach(parent, self, aux) pcitag_t tag = pa->pa_tag; struct pciide_softc *sc = (struct pciide_softc *)self; struct pciide_channel *cp; - pcireg_t class, interface, csr; + pcireg_t csr; char devinfo[256]; int i; - sc->sc_pp = pciide_lookup_product(pa->pa_id); + sc->sc_pp = pciide_lookup_product(pa->pa_id); if (sc->sc_pp == NULL) { sc->sc_pp = &default_product_desc; pci_devinfo(pa->pa_id, pa->pa_class, 0, devinfo); } - if ((pa->pa_flags & PCI_FLAGS_IO_ENABLED) == 0) { - csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG); - /* - * For a CMD PCI064x, the use of PCI_COMMAND_IO_ENABLE - * and base adresses registers can be disabled at - * hardware level. In this case, the device is wired - * in compat mode and its first channel is always enabled, - * but we can't rely on PCI_COMMAND_IO_ENABLE. - * In fact, it seems that the first channel of the CMD PCI0640 - * can't be disabled. - */ -#ifndef PCIIDE_CMD064x_DISABLE - if ((sc->sc_pp->ide_flags & CMD_PCI064x_IOEN) == 0) { -#else - if (1) { -#endif - printf(": device disabled (at %s)\n", - sc->sc_wdcdev.sc_dev.dv_xname, - (csr & PCI_COMMAND_IO_ENABLE) == 0 ? - "device" : "bridge"); - return; - } - } - sc->sc_pc = pa->pa_pc; sc->sc_tag = pa->pa_tag; - class = pci_conf_read(pc, tag, PCI_CLASS_REG); - interface = PCI_INTERFACE(class); - /* - * Map DMA registers, if DMA is supported. - * - * Note that sc_dma_ok is the right variable to test to see if - * DMA can be done. If the interface doesn't support DMA, - * sc_dma_ok will never be non-zero. If the DMA regs couldn't - * be mapped, it'll be zero. I.e., sc_dma_ok will only be - * non-zero if the interface supports DMA and the registers - * could be mapped. - * - * XXX Note that despite the fact that the Bus Master IDE specs - * XXX say that "The bus master IDE function uses 16 bytes of IO - * XXX space," some controllers (at least the United - * XXX Microelectronics UM8886BF) place it in memory space. - * XXX eventually, we should probably read the register and check - * XXX which type it is. Either that or 'quirk' certain devices. - */ - if (interface & PCIIDE_INTERFACE_BUS_MASTER_DMA) { - printf(": DMA"); - if (sc->sc_pp == &default_product_desc && - (sc->sc_wdcdev.sc_dev.dv_cfdata->cf_flags & - PCIIDE_OPTIONS_DMA) == 0) { - printf(" (unsupported)"); - sc->sc_dma_ok = 0; - } else { - sc->sc_dma_ok = (pci_mapreg_map(pa, - PCIIDE_REG_BUS_MASTER_DMA, PCI_MAPREG_TYPE_IO, 0, - &sc->sc_dma_iot, &sc->sc_dma_ioh, NULL, NULL) == 0); - sc->sc_dmat = pa->pa_dmat; - if (sc->sc_dma_ok == 0) { - printf(" (unuseable)"); - } else { - if (sc->sc_pp == &default_product_desc) - printf(" (partial support) "); - sc->sc_wdcdev.dma_arg = sc; - sc->sc_wdcdev.dma_init = pciide_dma_init; - sc->sc_wdcdev.dma_start = pciide_dma_start; - sc->sc_wdcdev.dma_finish = pciide_dma_finish; - } - } - } else { - printf(": no DMA"); - } - sc->sc_pp->setup_cap(sc); - sc->sc_wdcdev.channels = sc->wdc_chanarray; - sc->sc_wdcdev.nchannels = sc->sc_pp->ide_num_channels;; - sc->sc_wdcdev.cap |= WDC_CAPABILITY_DATA16; - - for (i = 0; i < sc->sc_wdcdev.nchannels; i++) { - printf(", %s %s to %s", PCIIDE_CHANNEL_NAME(i), - (interface & PCIIDE_INTERFACE_SETTABLE(i)) ? - "configured" : "wired", - (interface & PCIIDE_INTERFACE_PCI(i)) ? "native-PCI" : - "compatibility"); - } - printf("\n"); - - for (i = 0; i < sc->sc_wdcdev.nchannels; i++) { - cp = &sc->pciide_channels[i]; - sc->wdc_chanarray[i] = &cp->wdc_channel; +#ifdef WDCDEBUG + if (wdcdebug_pciide_mask & DEBUG_PROBE) + printf("sc_pc %s, sc_tag %s\n", sc->sc_pc, sc->sc_tag); +#endif - cp->name = PCIIDE_CHANNEL_NAME(i); + sc->sc_pp->chip_map(sc, pa); - cp->wdc_channel.channel = i; - cp->wdc_channel.wdc = &sc->sc_wdcdev; - if (i > 0 && (sc->sc_pp->ide_flags & ONE_QUEUE)) { - cp->wdc_channel.ch_queue = - sc->pciide_channels[0].wdc_channel.ch_queue; - } else { - cp->wdc_channel.ch_queue = - malloc(sizeof(struct channel_queue), M_DEVBUF, - M_NOWAIT); - } - if (cp->wdc_channel.ch_queue == NULL) { - printf("%s: %s cannot allocate memory for " - "command queue", sc->sc_wdcdev.sc_dev.dv_xname, - cp->name); - continue; - } - - /* - * sc->sc_pp->channel_map() will also call wdcattach. - * Eventually the channel will be disabled if there's no - * drive present. cp->hw_ok will be updated accordingly. - */ - sc->sc_pp->channel_map(pa, cp); - - } - /* Now that all drives are know, setup DMA, etc ...*/ - sc->sc_pp->setup_chip(sc); if (sc->sc_dma_ok) { csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG); csr |= PCI_COMMAND_MASTER_ENABLE; @@ -599,6 +476,25 @@ pciide_attach(parent, self, aux) pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG)), DEBUG_PROBE); } +/* tell wether the chip is enabled or not */ +int +pciide_chipen(sc, pa) + struct pciide_softc *sc; + struct pci_attach_args *pa; +{ + pcireg_t csr; + if ((pa->pa_flags & PCI_FLAGS_IO_ENABLED) == 0) { + csr = pci_conf_read(sc->sc_pc, sc->sc_tag, + PCI_COMMAND_STATUS_REG); + printf(": device disabled (at %s)\n", + (csr & PCI_COMMAND_IO_ENABLE) == 0 ? + "device" : "bridge"); + return 0; + } + return 1; +} + + int pciide_mapregs_compat(pa, cp, compatchan, cmdsizep, ctlsizep) struct pci_attach_args *pa; @@ -608,14 +504,12 @@ pciide_mapregs_compat(pa, cp, compatchan, cmdsizep, ctlsizep) { struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc; struct channel_softc *wdc_cp = &cp->wdc_channel; - int rv = 1; cp->compat = 1; *cmdsizep = PCIIDE_COMPAT_CMD_SIZE; *ctlsizep = PCIIDE_COMPAT_CTL_SIZE; wdc_cp->cmd_iot = pa->pa_iot; - wdc_cp->ctl_iot = pa->pa_iot; if (bus_space_map(wdc_cp->cmd_iot, PCIIDE_COMPAT_CMD_BASE(compatchan), PCIIDE_COMPAT_CMD_SIZE, 0, &wdc_cp->cmd_ioh) != 0) { @@ -624,6 +518,8 @@ pciide_mapregs_compat(pa, cp, compatchan, cmdsizep, ctlsizep) return (0); } + wdc_cp->ctl_iot = pa->pa_iot; + if (bus_space_map(wdc_cp->ctl_iot, PCIIDE_COMPAT_CTL_BASE(compatchan), PCIIDE_COMPAT_CTL_SIZE, 0, &wdc_cp->ctl_ioh) != 0) { printf("%s: couldn't map %s ctl regs\n", @@ -633,14 +529,15 @@ pciide_mapregs_compat(pa, cp, compatchan, cmdsizep, ctlsizep) return (0); } - return (rv); + return (1); } int -pciide_mapregs_native(pa, cp, cmdsizep, ctlsizep) +pciide_mapregs_native(pa, cp, cmdsizep, ctlsizep, pci_intr) struct pci_attach_args * pa; struct pciide_channel *cp; bus_size_t *cmdsizep, *ctlsizep; + int (*pci_intr) __P((void *)); { struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc; struct channel_softc *wdc_cp = &cp->wdc_channel; @@ -659,11 +556,11 @@ pciide_mapregs_native(pa, cp, cmdsizep, ctlsizep) intrstr = pci_intr_string(pa->pa_pc, intrhandle); #ifdef __OpenBSD__ sc->sc_pci_ih = pci_intr_establish(pa->pa_pc, - intrhandle, IPL_BIO, pciide_pci_intr, sc, + intrhandle, IPL_BIO, pci_intr, sc, sc->sc_wdcdev.sc_dev.dv_xname); #else sc->sc_pci_ih = pci_intr_establish(pa->pa_pc, - intrhandle, IPL_BIO, pciide_pci_intr, sc); + intrhandle, IPL_BIO, pci_intr, sc); #endif if (sc->sc_pci_ih != NULL) { printf("%s: using %s for native-PCI interrupt\n", @@ -698,6 +595,43 @@ pciide_mapregs_native(pa, cp, cmdsizep, ctlsizep) return (1); } +void +pciide_mapreg_dma(sc, pa) + struct pciide_softc *sc; + struct pci_attach_args *pa; +{ + /* + * Map DMA registers + * + * Note that sc_dma_ok is the right variable to test to see if + * DMA can be done. If the interface doesn't support DMA, + * sc_dma_ok will never be non-zero. If the DMA regs couldn't + * be mapped, it'll be zero. I.e., sc_dma_ok will only be + * non-zero if the interface supports DMA and the registers + * could be mapped. + * + * XXX Note that despite the fact that the Bus Master IDE specs + * XXX say that "The bus master IDE function uses 16 bytes of IO + * XXX space," some controllers (at least the United + * XXX Microelectronics UM8886BF) place it in memory space. + * XXX eventually, we should probably read the register and check + * XXX which type it is. Either that or 'quirk' certain devices. + */ + + sc->sc_dma_ok = (pci_mapreg_map(pa, + PCIIDE_REG_BUS_MASTER_DMA, PCI_MAPREG_TYPE_IO, 0, + &sc->sc_dma_iot, &sc->sc_dma_ioh, NULL, NULL) == 0); + sc->sc_dmat = pa->pa_dmat; + if (sc->sc_dma_ok == 0) { + printf(", (unuseable)"); /* couldn't map registers */ + } else { + sc->sc_wdcdev.dma_arg = sc; + sc->sc_wdcdev.dma_init = pciide_dma_init; + sc->sc_wdcdev.dma_start = pciide_dma_start; + sc->sc_wdcdev.dma_finish = pciide_dma_finish; + } +} + int pciide_compat_intr(arg) void *arg; @@ -1020,18 +954,46 @@ pciide_dma_finish(v, channel, drive, flags) return 0; } +/* some common code used by several chip_map */ +int +pciide_chansetup(sc, channel, interface) + struct pciide_softc *sc; + int channel; + pcireg_t interface; +{ + struct pciide_channel *cp = &sc->pciide_channels[channel]; + sc->wdc_chanarray[channel] = &cp->wdc_channel; + cp->name = PCIIDE_CHANNEL_NAME(channel); + cp->wdc_channel.channel = channel; + cp->wdc_channel.wdc = &sc->sc_wdcdev; + cp->wdc_channel.ch_queue = + malloc(sizeof(struct channel_queue), M_DEVBUF, M_NOWAIT); + if (cp->wdc_channel.ch_queue == NULL) { + printf("%s: %s " + "cannot allocate memory for command queue", + sc->sc_wdcdev.sc_dev.dv_xname, cp->name); + return 0; + } + + return 1; + +} + + /* some common code used by several chip channel_map */ void -pciide_mapchan(pa, cp, interface, cmdsizep, ctlsizep) +pciide_mapchan(pa, cp, interface, cmdsizep, ctlsizep, pci_intr) struct pci_attach_args *pa; - int interface; struct pciide_channel *cp; + pcireg_t interface; bus_size_t *cmdsizep, *ctlsizep; + int (*pci_intr) __P((void *)); { struct channel_softc *wdc_cp = &cp->wdc_channel; if (interface & PCIIDE_INTERFACE_PCI(wdc_cp->channel)) - cp->hw_ok = pciide_mapregs_native(pa, cp, cmdsizep, ctlsizep); + cp->hw_ok = pciide_mapregs_native(pa, cp, cmdsizep, ctlsizep, + pci_intr); else cp->hw_ok = pciide_mapregs_compat(pa, cp, wdc_cp->channel, cmdsizep, ctlsizep); @@ -1088,6 +1050,24 @@ pciide_map_compat_intr(pa, cp, compatchan, interface) } void +pciide_print_channels(nchannels, interface) + int nchannels; + pcireg_t interface; +{ + int i; + + for (i = 0; i < nchannels; i++) { + printf(", %s %s to %s", PCIIDE_CHANNEL_NAME(i), + (interface & PCIIDE_INTERFACE_SETTABLE(i)) ? + "configured" : "wired", + (interface & PCIIDE_INTERFACE_PCI(i)) ? "native-PCI" : + "compatibility"); + } + + printf("\n"); +} + +void pciide_print_modes(cp) struct pciide_channel *cp; { @@ -1116,32 +1096,114 @@ pciide_print_modes(cp) } void -default_setup_cap(sc) +default_chip_map(sc, pa) struct pciide_softc *sc; + struct pci_attach_args *pa; { + struct pciide_channel *cp; + pcireg_t interface = PCI_INTERFACE(pci_conf_read(sc->sc_pc, + sc->sc_tag, PCI_CLASS_REG)); + pcireg_t csr; + int channel, drive; + struct ata_drive_datas *drvp; + u_int8_t idedma_ctl; + bus_size_t cmdsize, ctlsize; + char *failreason; + + if (pciide_chipen(sc, pa) == 0) + return; + + if (interface & PCIIDE_INTERFACE_BUS_MASTER_DMA) { + printf(": DMA"); + if (sc->sc_pp == &default_product_desc && + (sc->sc_wdcdev.sc_dev.dv_cfdata->cf_flags & + PCIIDE_OPTIONS_DMA) == 0) { + printf(" (unsupported)"); + sc->sc_dma_ok = 0; + } else { + pciide_mapreg_dma(sc, pa); + if (sc->sc_dma_ok != 0) + printf(", (partial support) "); + } + } else { + printf(": no DMA"); + sc->sc_dma_ok = 0; + } if (sc->sc_dma_ok) sc->sc_wdcdev.cap |= WDC_CAPABILITY_DMA; sc->sc_wdcdev.PIO_cap = 0; sc->sc_wdcdev.DMA_cap = 0; -} + sc->sc_wdcdev.channels = sc->wdc_chanarray; + sc->sc_wdcdev.nchannels = PCIIDE_NUM_CHANNELS; + sc->sc_wdcdev.cap |= WDC_CAPABILITY_DATA16; -void -default_setup_chip(sc) - struct pciide_softc *sc; -{ - int channel, drive, idedma_ctl; - struct channel_softc *chp; - struct ata_drive_datas *drvp; + pciide_print_channels(sc->sc_wdcdev.nchannels, interface); + + for (channel = 0; channel < sc->sc_wdcdev.nchannels; channel++) { + cp = &sc->pciide_channels[channel]; + if (pciide_chansetup(sc, channel, interface) == 0) + continue; + if (interface & PCIIDE_INTERFACE_PCI(channel)) { + cp->hw_ok = pciide_mapregs_native(pa, cp, &cmdsize, + &ctlsize, pciide_pci_intr); + } else { + cp->hw_ok = pciide_mapregs_compat(pa, cp, + channel, &cmdsize, &ctlsize); + } + if (cp->hw_ok == 0) + continue; + /* + * Check to see if something appears to be there. + */ + failreason = NULL; + if (!wdcprobe(&cp->wdc_channel)) { + failreason = "not responding; disabled or no drives?"; + goto next; + } + /* + * Now, make sure it's actually attributable to this PCI IDE + * channel by trying to access the channel again while the + * PCI IDE controller's I/O space is disabled. (If the + * channel no longer appears to be there, it belongs to + * this controller.) YUCK! + */ + csr = pci_conf_read(sc->sc_pc, sc->sc_tag, + PCI_COMMAND_STATUS_REG); + pci_conf_write(sc->sc_pc, sc->sc_tag, PCI_COMMAND_STATUS_REG, + csr & ~PCI_COMMAND_IO_ENABLE); + if (wdcprobe(&cp->wdc_channel)) + failreason = "other hardware responding at addresses"; + pci_conf_write(sc->sc_pc, sc->sc_tag, + PCI_COMMAND_STATUS_REG, csr); +next: + if (failreason) { + printf("%s: %s ignored (%s)\n", + sc->sc_wdcdev.sc_dev.dv_xname, cp->name, + failreason); + cp->hw_ok = 0; + bus_space_unmap(cp->wdc_channel.cmd_iot, + cp->wdc_channel.cmd_ioh, cmdsize); + bus_space_unmap(cp->wdc_channel.ctl_iot, + cp->wdc_channel.ctl_ioh, ctlsize); + } else { + pciide_map_compat_intr(pa, cp, channel, interface); + } + if (cp->hw_ok) { + cp->wdc_channel.data32iot = cp->wdc_channel.cmd_iot; + cp->wdc_channel.data32ioh = cp->wdc_channel.cmd_ioh; + wdcattach(&cp->wdc_channel); + } + } if (sc->sc_dma_ok == 0) - return; /* nothing to do */ + return; /* Allocate DMA maps */ for (channel = 0; channel < sc->sc_wdcdev.nchannels; channel++) { idedma_ctl = 0; - chp = &sc->pciide_channels[channel].wdc_channel; + cp = &sc->pciide_channels[channel]; for (drive = 0; drive < 2; drive++) { - drvp = &chp->ch_drive[drive]; + drvp = &cp->wdc_channel.ch_drive[drive]; /* If no drive, skip */ if ((drvp->drive_flags & DRIVE) == 0) continue; @@ -1149,7 +1211,7 @@ default_setup_chip(sc) continue; if (pciide_dma_table_setup(sc, channel, drive) != 0) { /* Abort DMA setup */ - printf("%s:%d:%d: can't allocate DMA maps, " + printf("%s:%d:%d: cannot allocate DMA maps, " "using PIO transfers\n", sc->sc_wdcdev.sc_dev.dv_xname, channel, drive); @@ -1171,98 +1233,118 @@ default_setup_chip(sc) } void -default_channel_map(pa, cp) +piix_chip_map(sc, pa) + struct pciide_softc *sc; struct pci_attach_args *pa; +{ struct pciide_channel *cp; -{ - struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc; + int channel; + u_int32_t idetim; bus_size_t cmdsize, ctlsize; - pcireg_t csr; - const char *failreason = NULL; - struct channel_softc *wdc_cp = &cp->wdc_channel; - int interface = - PCI_INTERFACE(pci_conf_read(sc->sc_pc, sc->sc_tag, PCI_CLASS_REG)); - if (interface & PCIIDE_INTERFACE_PCI(wdc_cp->channel)) - cp->hw_ok = pciide_mapregs_native(pa, cp, &cmdsize, &ctlsize); - else - cp->hw_ok = pciide_mapregs_compat(pa, cp, wdc_cp->channel, - &cmdsize, &ctlsize); - if (cp->hw_ok == 0) - return; + pcireg_t interface = PCI_INTERFACE(pci_conf_read(sc->sc_pc, + sc->sc_tag, PCI_CLASS_REG)); - /* - * Check to see if something appears to be there. - */ - if (!wdcprobe(wdc_cp)) { - failreason = "not responding; disabled or no drives?"; - goto out; - } + if (pciide_chipen(sc, pa) == 0) + return; - /* - * Now, make sure it's actually attributable to this PCI IDE - * channel by trying to access the channel again while the - * PCI IDE controller's I/O space is disabled. (If the - * channel no longer appears to be there, it belongs to - * this controller.) YUCK! - */ - csr = pci_conf_read(sc->sc_pc, sc->sc_tag, PCI_COMMAND_STATUS_REG); - pci_conf_write(sc->sc_pc, sc->sc_tag, PCI_COMMAND_STATUS_REG, - csr & ~PCI_COMMAND_IO_ENABLE); - if (wdcprobe(wdc_cp)) - failreason = "other hardware responding at addresses"; - pci_conf_write(sc->sc_pc, sc->sc_tag, PCI_COMMAND_STATUS_REG, csr); - -out: - if (failreason) { - printf("%s: %s ignored (%s)\n", - sc->sc_wdcdev.sc_dev.dv_xname, cp->name, - failreason); - cp->hw_ok = 0; - bus_space_unmap(wdc_cp->cmd_iot, wdc_cp->cmd_ioh, cmdsize); - bus_space_unmap(wdc_cp->ctl_iot, wdc_cp->ctl_ioh, ctlsize); - } - pciide_map_compat_intr(pa, cp, wdc_cp->channel, interface); - if (cp->hw_ok) { - wdc_cp->data32iot = wdc_cp->cmd_iot; - wdc_cp->data32ioh = wdc_cp->cmd_ioh; - wdcattach(wdc_cp); + printf(": DMA"); + pciide_mapreg_dma(sc, pa); + if (sc->sc_dma_ok) { + sc->sc_wdcdev.cap |= WDC_CAPABILITY_DMA; + switch(sc->sc_pp->ide_product) { + case PCI_PRODUCT_INTEL_82371AB_IDE: + case PCI_PRODUCT_INTEL_82801AA_IDE: + case PCI_PRODUCT_INTEL_82801AB_IDE: + sc->sc_wdcdev.cap |= WDC_CAPABILITY_UDMA; + } } -} -void -piix_setup_cap(sc) - struct pciide_softc *sc; -{ - if (sc->sc_pp->ide_product == PCI_PRODUCT_INTEL_82371AB_IDE) - sc->sc_wdcdev.cap |= WDC_CAPABILITY_UDMA; - sc->sc_wdcdev.cap |= WDC_CAPABILITY_DATA32 | WDC_CAPABILITY_MODE | - WDC_CAPABILITY_DMA; + sc->sc_wdcdev.cap |= WDC_CAPABILITY_DATA16 | WDC_CAPABILITY_DATA32 | + WDC_CAPABILITY_MODE; sc->sc_wdcdev.PIO_cap = 4; sc->sc_wdcdev.DMA_cap = 2; - sc->sc_wdcdev.UDMA_cap = 2; - if (sc->sc_pp->ide_product == PCI_PRODUCT_INTEL_82371SB_IDE || - sc->sc_pp->ide_product == PCI_PRODUCT_INTEL_82371AB_IDE) - sc->sc_wdcdev.set_modes = piix3_4_setup_channel; - else + sc->sc_wdcdev.UDMA_cap = + (sc->sc_pp->ide_product == PCI_PRODUCT_INTEL_82801AA_IDE) ? 4 : 2; + if (sc->sc_pp->ide_product == PCI_PRODUCT_INTEL_82371FB_IDE) sc->sc_wdcdev.set_modes = piix_setup_channel; -} + else + sc->sc_wdcdev.set_modes = piix3_4_setup_channel; + sc->sc_wdcdev.channels = sc->wdc_chanarray; + sc->sc_wdcdev.nchannels = PCIIDE_NUM_CHANNELS; -void -piix_setup_chip(sc) - struct pciide_softc *sc; -{ - u_int8_t channel; + pciide_print_channels(sc->sc_wdcdev.nchannels, interface); + WDCDEBUG_PRINT(("piix_setup_chip: old idetim=0x%x", + pci_conf_read(sc->sc_pc, sc->sc_tag, PIIX_IDETIM)), + DEBUG_PROBE); + if (sc->sc_pp->ide_product != PCI_PRODUCT_INTEL_82371FB_IDE) { + WDCDEBUG_PRINT((", sidetim=0x%x", + pci_conf_read(sc->sc_pc, sc->sc_tag, PIIX_SIDETIM)), + DEBUG_PROBE); + if (sc->sc_wdcdev.cap & WDC_CAPABILITY_UDMA) { + WDCDEBUG_PRINT((", udamreg 0x%x", + pci_conf_read(sc->sc_pc, sc->sc_tag, PIIX_UDMAREG)), + DEBUG_PROBE); + } + if (sc->sc_pp->ide_product == PCI_PRODUCT_INTEL_82801AA_IDE || + sc->sc_pp->ide_product == PCI_PRODUCT_INTEL_82801AB_IDE) { + WDCDEBUG_PRINT((", IDE_CONTROL 0x%x", + pci_conf_read(sc->sc_pc, sc->sc_tag, PIIX_CONFIG)), + DEBUG_PROBE); + } - WDCDEBUG_PRINT(("piix_setup_chip: old idetim=0x%x\n", - pci_conf_read(sc->sc_pc, sc->sc_tag, PIIX_IDETIM)), DEBUG_PROBE); + } + WDCDEBUG_PRINT(("\n"), DEBUG_PROBE); for (channel = 0; channel < sc->sc_wdcdev.nchannels; channel++) { - piix_setup_channel(&sc->pciide_channels[channel].wdc_channel); + cp = &sc->pciide_channels[channel]; + /* PIIX is compat-only */ + if (pciide_chansetup(sc, channel, 0) == 0) + continue; + idetim = pci_conf_read(sc->sc_pc, sc->sc_tag, PIIX_IDETIM); + if ((PIIX_IDETIM_READ(idetim, channel) & + PIIX_IDETIM_IDE) == 0) { + printf("%s: %s ignored (disabled)\n", + sc->sc_wdcdev.sc_dev.dv_xname, cp->name); + return; + } + /* PIIX are compat-only pciide devices */ + pciide_mapchan(pa, cp, 0, &cmdsize, &ctlsize, pciide_pci_intr); + if (cp->hw_ok == 0) + continue; + if (pciiide_chan_candisable(cp)) { + idetim = PIIX_IDETIM_CLEAR(idetim, PIIX_IDETIM_IDE, + channel); + pci_conf_write(sc->sc_pc, sc->sc_tag, PIIX_IDETIM, + idetim); + } + pciide_map_compat_intr(pa, cp, channel, 0); + if (cp->hw_ok == 0) + continue; + sc->sc_wdcdev.set_modes(&cp->wdc_channel); + } + + WDCDEBUG_PRINT(("piix_setup_chip: idetim=0x%x", + pci_conf_read(sc->sc_pc, sc->sc_tag, PIIX_IDETIM)), + DEBUG_PROBE); + if (sc->sc_pp->ide_product != PCI_PRODUCT_INTEL_82371FB_IDE) { + WDCDEBUG_PRINT((", sidetim=0x%x", + pci_conf_read(sc->sc_pc, sc->sc_tag, PIIX_SIDETIM)), + DEBUG_PROBE); + if (sc->sc_wdcdev.cap & WDC_CAPABILITY_UDMA) { + WDCDEBUG_PRINT((", udamreg 0x%x", + pci_conf_read(sc->sc_pc, sc->sc_tag, PIIX_UDMAREG)), + DEBUG_PROBE); + } + if (sc->sc_pp->ide_product == PCI_PRODUCT_INTEL_82801AA_IDE || + sc->sc_pp->ide_product == PCI_PRODUCT_INTEL_82801AB_IDE) { + WDCDEBUG_PRINT((", IDE_CONTROL 0x%x", + pci_conf_read(sc->sc_pc, sc->sc_tag, PIIX_CONFIG)), + DEBUG_PROBE); + } } - WDCDEBUG_PRINT(("piix_setup_chip: idetim=0x%x\n", - pci_conf_read(sc->sc_pc, sc->sc_tag, PIIX_IDETIM)), DEBUG_PROBE); + WDCDEBUG_PRINT(("\n"), DEBUG_PROBE); } void @@ -1274,7 +1356,7 @@ piix_setup_channel(chp) struct pciide_channel *cp = (struct pciide_channel*)chp; struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc; struct ata_drive_datas *drvp = cp->wdc_channel.ch_drive; - + oidetim = pci_conf_read(sc->sc_pc, sc->sc_tag, PIIX_IDETIM); idetim = PIIX_IDETIM_CLEAR(oidetim, 0xffff, chp->channel); idedma_ctl = 0; @@ -1375,67 +1457,37 @@ end: /* } void -piix3_4_setup_chip(sc) - struct pciide_softc *sc; -{ - int channel; - - WDCDEBUG_PRINT(("piix3_4_setup_chip: old idetim=0x%x, sidetim=0x%x", - pci_conf_read(sc->sc_pc, sc->sc_tag, PIIX_IDETIM), - pci_conf_read(sc->sc_pc, sc->sc_tag, PIIX_SIDETIM)), DEBUG_PROBE); - if (sc->sc_wdcdev.cap & WDC_CAPABILITY_UDMA) { - WDCDEBUG_PRINT((", udamreg 0x%x", - pci_conf_read(sc->sc_pc, sc->sc_tag, PIIX_UDMAREG)), - DEBUG_PROBE); - } - WDCDEBUG_PRINT(("\n"), DEBUG_PROBE); - - for (channel = 0; channel < sc->sc_wdcdev.nchannels; channel++) { - piix3_4_setup_channel( - &sc->pciide_channels[channel].wdc_channel); - } - - WDCDEBUG_PRINT(("piix3_4_setup_chip: idetim=0x%x, sidetim=0x%x", - pci_conf_read(sc->sc_pc, sc->sc_tag, PIIX_IDETIM), - pci_conf_read(sc->sc_pc, sc->sc_tag, PIIX_SIDETIM)), DEBUG_PROBE); - if (sc->sc_wdcdev.cap & WDC_CAPABILITY_UDMA) { - WDCDEBUG_PRINT((", udmareg=0x%x", - pci_conf_read(sc->sc_pc, sc->sc_tag, PIIX_UDMAREG)), - DEBUG_PROBE); - } - WDCDEBUG_PRINT(("\n"), DEBUG_PROBE); -} - -void piix3_4_setup_channel(chp) struct channel_softc *chp; { struct ata_drive_datas *drvp; - u_int32_t oidetim, idetim, sidetim, udmareg, idedma_ctl; + u_int32_t oidetim, idetim, sidetim, udmareg, ideconf, idedma_ctl; struct pciide_channel *cp = (struct pciide_channel*)chp; struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc; int drive; + int channel = chp->channel; oidetim = pci_conf_read(sc->sc_pc, sc->sc_tag, PIIX_IDETIM); sidetim = pci_conf_read(sc->sc_pc, sc->sc_tag, PIIX_SIDETIM); udmareg = pci_conf_read(sc->sc_pc, sc->sc_tag, PIIX_UDMAREG); - idetim = PIIX_IDETIM_CLEAR(oidetim, 0xffff, chp->channel); - sidetim &= ~(PIIX_SIDETIM_ISP_MASK(chp->channel) | - PIIX_SIDETIM_RTC_MASK(chp->channel)); + ideconf = pci_conf_read(sc->sc_pc, sc->sc_tag, PIIX_CONFIG); + idetim = PIIX_IDETIM_CLEAR(oidetim, 0xffff, channel); + sidetim &= ~(PIIX_SIDETIM_ISP_MASK(channel) | + PIIX_SIDETIM_RTC_MASK(channel)); idedma_ctl = 0; /* If channel disabled, no need to go further */ - if ((PIIX_IDETIM_READ(oidetim, chp->channel) & PIIX_IDETIM_IDE) == 0) + if ((PIIX_IDETIM_READ(oidetim, channel) & PIIX_IDETIM_IDE) == 0) return; /* set up new idetim: Enable IDE registers decode */ - idetim = PIIX_IDETIM_SET(idetim, PIIX_IDETIM_IDE, chp->channel); + idetim = PIIX_IDETIM_SET(idetim, PIIX_IDETIM_IDE, channel); /* setup DMA if needed */ pciide_channel_dma_setup(cp); for (drive = 0; drive < 2; drive++) { - udmareg &= ~(PIIX_UDMACTL_DRV_EN(chp->channel, drive) | - PIIX_UDMATIM_SET(0x3, chp->channel, drive)); + udmareg &= ~(PIIX_UDMACTL_DRV_EN(channel, drive) | + PIIX_UDMATIM_SET(0x3, channel, drive)); drvp = &chp->ch_drive[drive]; /* If no drive, skip */ if ((drvp->drive_flags & DRIVE) == 0) @@ -1444,26 +1496,39 @@ piix3_4_setup_channel(chp) (drvp->drive_flags & DRIVE_UDMA) == 0)) goto pio; + if (sc->sc_pp->ide_product == PCI_PRODUCT_INTEL_82801AA_IDE || + sc->sc_pp->ide_product == PCI_PRODUCT_INTEL_82801AB_IDE) { + ideconf |= PIIX_CONFIG_PINGPONG; + } + if (sc->sc_pp->ide_product == PCI_PRODUCT_INTEL_82801AA_IDE) { + /* setup Ultra/66 */ + if (drvp->UDMA_mode > 2 && + (ideconf & PIIX_CONFIG_CR(channel, drive)) == 0) + drvp->UDMA_mode = 2; + if (drvp->UDMA_mode > 2) + ideconf |= PIIX_CONFIG_UDMA66(channel, drive); + else + ideconf &= ~PIIX_CONFIG_UDMA66(channel, drive); + } + if ((chp->wdc->cap & WDC_CAPABILITY_UDMA) && (drvp->drive_flags & DRIVE_UDMA)) { /* use Ultra/DMA */ drvp->drive_flags &= ~DRIVE_DMA; - udmareg |= PIIX_UDMACTL_DRV_EN( - chp->channel, drive); + udmareg |= PIIX_UDMACTL_DRV_EN( channel,drive); udmareg |= PIIX_UDMATIM_SET( - piix4_sct_udma[drvp->UDMA_mode], - chp->channel, drive); + piix4_sct_udma[drvp->UDMA_mode], channel, drive); } else { /* use Multiword DMA */ drvp->drive_flags &= ~DRIVE_UDMA; if (drive == 0) { idetim |= piix_setup_idetim_timings( - drvp->DMA_mode, 1, chp->channel); + drvp->DMA_mode, 1, channel); } else { sidetim |= piix_setup_sidetim_timings( - drvp->DMA_mode, 1, chp->channel); + drvp->DMA_mode, 1, channel); idetim =PIIX_IDETIM_SET(idetim, - PIIX_IDETIM_SITRE, chp->channel); + PIIX_IDETIM_SITRE, channel); } } idedma_ctl |= IDEDMA_CTL_DRV_DMA(drive); @@ -1472,23 +1537,24 @@ pio: /* use PIO mode */ idetim |= piix_setup_idetim_drvs(drvp); if (drive == 0) { idetim |= piix_setup_idetim_timings( - drvp->PIO_mode, 0, chp->channel); + drvp->PIO_mode, 0, channel); } else { sidetim |= piix_setup_sidetim_timings( - drvp->PIO_mode, 0, chp->channel); + drvp->PIO_mode, 0, channel); idetim =PIIX_IDETIM_SET(idetim, - PIIX_IDETIM_SITRE, chp->channel); + PIIX_IDETIM_SITRE, channel); } } if (idedma_ctl != 0) { /* Add software bits in status register */ bus_space_write_1(sc->sc_dma_iot, sc->sc_dma_ioh, - IDEDMA_CTL + (IDEDMA_SCH_OFFSET * chp->channel), + IDEDMA_CTL + (IDEDMA_SCH_OFFSET * channel), idedma_ctl); } pci_conf_write(sc->sc_pc, sc->sc_tag, PIIX_IDETIM, idetim); pci_conf_write(sc->sc_pc, sc->sc_tag, PIIX_SIDETIM, sidetim); pci_conf_write(sc->sc_pc, sc->sc_tag, PIIX_UDMAREG, udmareg); + pci_conf_write(sc->sc_pc, sc->sc_tag, PIIX_CONFIG, ideconf); pciide_print_modes(cp); } @@ -1585,56 +1651,38 @@ piix_setup_sidetim_timings(mode, dma, channel) } void -piix_channel_map(pa, cp) +apollo_chip_map(sc, pa) + struct pciide_softc *sc; struct pci_attach_args *pa; - struct pciide_channel *cp; { - struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc; + struct pciide_channel *cp; + pcireg_t interface = PCI_INTERFACE(pci_conf_read(sc->sc_pc, + sc->sc_tag, PCI_CLASS_REG)); + int channel; + u_int32_t ideconf; bus_size_t cmdsize, ctlsize; - struct channel_softc *wdc_cp = &cp->wdc_channel; - u_int32_t idetim = pci_conf_read(sc->sc_pc, sc->sc_tag, PIIX_IDETIM); - if ((PIIX_IDETIM_READ(idetim, wdc_cp->channel) & - PIIX_IDETIM_IDE) == 0) { - printf("%s: %s ignored (disabled)\n", - sc->sc_wdcdev.sc_dev.dv_xname, cp->name); - return; - } - - /* PIIX are compat-only pciide devices */ - pciide_mapchan(pa, cp, 0, &cmdsize, &ctlsize); - if (cp->hw_ok == 0) + if (pciide_chipen(sc, pa) == 0) return; - if (pciiide_chan_candisable(cp)) { - idetim = PIIX_IDETIM_CLEAR(idetim, PIIX_IDETIM_IDE, - wdc_cp->channel); - pci_conf_write(sc->sc_pc, sc->sc_tag, PIIX_IDETIM, idetim); + printf(": DMA"); + pciide_mapreg_dma(sc, pa); + if (sc->sc_dma_ok) { + sc->sc_wdcdev.cap |= WDC_CAPABILITY_DMA; + if (sc->sc_pp->ide_product == PCI_PRODUCT_VIATECH_VT82C586A_IDE) + sc->sc_wdcdev.cap |= WDC_CAPABILITY_UDMA; } - pciide_map_compat_intr(pa, cp, wdc_cp->channel, 0); -} - -void -apollo_setup_cap(sc) - struct pciide_softc *sc; -{ - if (sc->sc_pp->ide_product == PCI_PRODUCT_VIATECH_VT82C586A_IDE) - sc->sc_wdcdev.cap |= WDC_CAPABILITY_UDMA; - sc->sc_wdcdev.cap |= WDC_CAPABILITY_DATA32 | WDC_CAPABILITY_MODE | - WDC_CAPABILITY_DMA; + sc->sc_wdcdev.cap |= WDC_CAPABILITY_DATA32 | WDC_CAPABILITY_MODE; sc->sc_wdcdev.PIO_cap = 4; sc->sc_wdcdev.DMA_cap = 2; sc->sc_wdcdev.UDMA_cap = 2; sc->sc_wdcdev.set_modes = apollo_setup_channel; + sc->sc_wdcdev.channels = sc->wdc_chanarray; + sc->sc_wdcdev.nchannels = PCIIDE_NUM_CHANNELS; + sc->sc_wdcdev.cap |= WDC_CAPABILITY_DATA16; -} - -void -apollo_setup_chip(sc) - struct pciide_softc *sc; -{ - int channel; - - WDCDEBUG_PRINT(("apollo_setup_chip: old APO_IDECONF=0x%x, " + pciide_print_channels(sc->sc_wdcdev.nchannels, interface); + + WDCDEBUG_PRINT(("apollo_chip_map: old APO_IDECONF=0x%x, " "APO_CTLMISC=0x%x, APO_DATATIM=0x%x, APO_UDMA=0x%x\n", pci_conf_read(sc->sc_pc, sc->sc_tag, APO_IDECONF), pci_conf_read(sc->sc_pc, sc->sc_tag, APO_CTLMISC), @@ -1643,9 +1691,32 @@ apollo_setup_chip(sc) DEBUG_PROBE); for (channel = 0; channel < sc->sc_wdcdev.nchannels; channel++) { + cp = &sc->pciide_channels[channel]; + if (pciide_chansetup(sc, channel, interface) == 0) + continue; + + ideconf = pci_conf_read(sc->sc_pc, sc->sc_tag, APO_IDECONF); + if ((ideconf & APO_IDECONF_EN(channel)) == 0) { + printf("%s: %s ignored (disabled)\n", + sc->sc_wdcdev.sc_dev.dv_xname, cp->name); + return; + } + pciide_mapchan(pa, cp, interface, &cmdsize, &ctlsize, + pciide_pci_intr); + if (cp->hw_ok == 0) + continue; + if (pciiide_chan_candisable(cp)) { + ideconf &= ~APO_IDECONF_EN(channel); + pci_conf_write(sc->sc_pc, sc->sc_tag, APO_IDECONF, + ideconf); + } + pciide_map_compat_intr(pa, cp, channel, interface); + + if (cp->hw_ok == 0) + continue; apollo_setup_channel(&sc->pciide_channels[channel].wdc_channel); } - WDCDEBUG_PRINT(("apollo_setup_chip: APO_DATATIM=0x%x, APO_UDMA=0x%x\n", + WDCDEBUG_PRINT(("apollo_chip_map: APO_DATATIM=0x%x, APO_UDMA=0x%x\n", pci_conf_read(sc->sc_pc, sc->sc_tag, APO_DATATIM), pci_conf_read(sc->sc_pc, sc->sc_tag, APO_UDMA)), DEBUG_PROBE); } @@ -1729,98 +1800,183 @@ pio: /* setup PIO mode */ } void -apollo_channel_map(pa, cp) +cmd_channel_map(pa, sc, channel) struct pci_attach_args *pa; - struct pciide_channel *cp; + struct pciide_softc *sc; + int channel; { - struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc; + struct pciide_channel *cp = &sc->pciide_channels[channel]; bus_size_t cmdsize, ctlsize; - struct channel_softc *wdc_cp = &cp->wdc_channel; - u_int32_t ideconf = pci_conf_read(sc->sc_pc, sc->sc_tag, APO_IDECONF); - int interface = + u_int8_t ctrl = pciide_pci_read(sc->sc_pc, sc->sc_tag, CMD_CTRL); + pcireg_t interface = PCI_INTERFACE(pci_conf_read(sc->sc_pc, sc->sc_tag, PCI_CLASS_REG)); - if ((ideconf & APO_IDECONF_EN(wdc_cp->channel)) == 0) { - printf("%s: %s ignored (disabled)\n", - sc->sc_wdcdev.sc_dev.dv_xname, cp->name); - return; - } + sc->wdc_chanarray[channel] = &cp->wdc_channel; + cp->name = PCIIDE_CHANNEL_NAME(channel); + cp->wdc_channel.channel = channel; + cp->wdc_channel.wdc = &sc->sc_wdcdev; - pciide_mapchan(pa, cp, interface, &cmdsize, &ctlsize); - if (cp->hw_ok == 0) + if (channel > 0) { + cp->wdc_channel.ch_queue = + sc->pciide_channels[0].wdc_channel.ch_queue; + } else { + cp->wdc_channel.ch_queue = + malloc(sizeof(struct channel_queue), M_DEVBUF, M_NOWAIT); + } + if (cp->wdc_channel.ch_queue == NULL) { + printf( + "%s: %s cannot allocate memory for command queue", + sc->sc_wdcdev.sc_dev.dv_xname, cp->name); return; - if (pciiide_chan_candisable(cp)) { - ideconf &= ~APO_IDECONF_EN(wdc_cp->channel); - pci_conf_write(sc->sc_pc, sc->sc_tag, APO_IDECONF, ideconf); } - pciide_map_compat_intr(pa, cp, wdc_cp->channel, interface); -} - -void -cmd_channel_map(pa, cp) - struct pci_attach_args *pa; - struct pciide_channel *cp; -{ - struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc; - bus_size_t cmdsize, ctlsize; - struct channel_softc *wdc_cp = &cp->wdc_channel; - u_int8_t ctrl = pciide_pci_read(sc->sc_pc, sc->sc_tag, CMD_CTRL); - int interface = - PCI_INTERFACE(pci_conf_read(sc->sc_pc, sc->sc_tag, PCI_CLASS_REG)); /* * with a CMD PCI64x, if we get here, the first channel is enabled: * there's no way to disable the first channel without disabling * the whole device */ - if (wdc_cp->channel != 0 && (ctrl & CMD_CTRL_2PORT) == 0) { + if (channel != 0 && (ctrl & CMD_CTRL_2PORT) == 0) { printf("%s: %s ignored (disabled)\n", sc->sc_wdcdev.sc_dev.dv_xname, cp->name); return; } - pciide_mapchan(pa, cp, interface, &cmdsize, &ctlsize); + pciide_mapchan(pa, cp, interface, &cmdsize, &ctlsize, cmd_pci_intr); if (cp->hw_ok == 0) return; - if (wdc_cp->channel == 1) { + if (channel == 1) { if (pciiide_chan_candisable(cp)) { ctrl &= ~CMD_CTRL_2PORT; pciide_pci_write(pa->pa_pc, pa->pa_tag, CMD_CTRL, ctrl); } } - pciide_map_compat_intr(pa, cp, wdc_cp->channel, interface); + pciide_map_compat_intr(pa, cp, channel, interface); + +} + +int +cmd_pci_intr(arg) + void *arg; +{ + struct pciide_softc *sc = arg; + struct pciide_channel *cp; + struct channel_softc *wdc_cp; + int i, rv, crv; + u_int32_t priirq, secirq; + + rv = 0; + priirq = pciide_pci_read(sc->sc_pc, sc->sc_tag, CMD_CONF); + secirq = pciide_pci_read(sc->sc_pc, sc->sc_tag, CMD_ARTTIM23); + for (i = 0; i < sc->sc_wdcdev.nchannels; i++) { + cp = &sc->pciide_channels[i]; + wdc_cp = &cp->wdc_channel; + /* If a compat channel skip. */ + if (cp->compat) + continue; + if ((i == 0 && (priirq & CMD_CONF_DRV0_INTR)) || + (i == 1 && (secirq & CMD_ARTTIM23_IRQ))) { + crv = wdcintr(wdc_cp); + if (crv == 0) + printf("%s:%d: bogus intr\n", + sc->sc_wdcdev.sc_dev.dv_xname, i); + else + rv = 1; + } + } + return rv; } void -cmd0643_6_setup_cap(sc) +cmd_chip_map(sc, pa) struct pciide_softc *sc; + struct pci_attach_args *pa; { + int channel; + pcireg_t interface = + PCI_INTERFACE(pci_conf_read(sc->sc_pc, sc->sc_tag, PCI_CLASS_REG)); - sc->sc_wdcdev.cap |= WDC_CAPABILITY_DATA32 | WDC_CAPABILITY_MODE | - WDC_CAPABILITY_DMA; - sc->sc_wdcdev.PIO_cap = 4; - sc->sc_wdcdev.DMA_cap = 2; - sc->sc_wdcdev.set_modes = cmd0643_6_setup_channel; + /* + * For a CMD PCI064x, the use of PCI_COMMAND_IO_ENABLE + * and base adresses registers can be disabled at + * hardware level. In this case, the device is wired + * in compat mode and its first channel is always enabled, + * but we can't rely on PCI_COMMAND_IO_ENABLE. + * In fact, it seems that the first channel of the CMD PCI0640 + * can't be disabled. + */ + +#ifdef PCIIDE_CMD064x_DISABLE + if (pciide_chipen(sc, pa) == 0) + return; +#endif + + printf(": no DMA"); + sc->sc_dma_ok = 0; + + sc->sc_wdcdev.channels = sc->wdc_chanarray; + sc->sc_wdcdev.nchannels = PCIIDE_NUM_CHANNELS; + sc->sc_wdcdev.cap |= WDC_CAPABILITY_DATA16; + + pciide_print_channels(sc->sc_wdcdev.nchannels, interface); + + for (channel = 0; channel < sc->sc_wdcdev.nchannels; channel++) { + cmd_channel_map(pa, sc, channel); + } } void -cmd0643_6_setup_chip(sc) +cmd0643_6_chip_map(sc, pa) struct pciide_softc *sc; + struct pci_attach_args *pa; { + struct pciide_channel *cp; int channel; + pcireg_t interface = + PCI_INTERFACE(pci_conf_read(sc->sc_pc, sc->sc_tag, PCI_CLASS_REG)); + + /* + * For a CMD PCI064x, the use of PCI_COMMAND_IO_ENABLE + * and base adresses registers can be disabled at + * hardware level. In this case, the device is wired + * in compat mode and its first channel is always enabled, + * but we can't rely on PCI_COMMAND_IO_ENABLE. + * In fact, it seems that the first channel of the CMD PCI0640 + * can't be disabled. + */ + +#ifdef PCIIDE_CMD064x_DISABLE + if (pciide_chipen(sc, pa) == 0) + return; +#endif + printf(": DMA"); + pciide_mapreg_dma(sc, pa); + if (sc->sc_dma_ok) + sc->sc_wdcdev.cap |= WDC_CAPABILITY_DMA; - WDCDEBUG_PRINT(("cmd0643_6_setup_chip: old timings reg 0x%x 0x%x\n", + sc->sc_wdcdev.channels = sc->wdc_chanarray; + sc->sc_wdcdev.nchannels = PCIIDE_NUM_CHANNELS; + sc->sc_wdcdev.cap |= WDC_CAPABILITY_DATA16 | WDC_CAPABILITY_DATA32 | + WDC_CAPABILITY_MODE; + sc->sc_wdcdev.PIO_cap = 4; + sc->sc_wdcdev.DMA_cap = 2; + sc->sc_wdcdev.set_modes = cmd0643_6_setup_channel; + + pciide_print_channels(sc->sc_wdcdev.nchannels, interface); + + WDCDEBUG_PRINT(("cmd0643_6_chip_map: old timings reg 0x%x 0x%x\n", pci_conf_read(sc->sc_pc, sc->sc_tag, 0x54), pci_conf_read(sc->sc_pc, sc->sc_tag, 0x58)), DEBUG_PROBE); for (channel = 0; channel < sc->sc_wdcdev.nchannels; channel++) { - cmd0643_6_setup_channel( - &sc->pciide_channels[channel].wdc_channel); + cp = &sc->pciide_channels[channel]; + cmd_channel_map(pa, sc, channel); + if (cp->hw_ok == 0) + continue; + cmd0643_6_setup_channel(&cp->wdc_channel); } - /* configure for DMA read multiple */ pciide_pci_write(sc->sc_pc, sc->sc_tag, CMD_DMA_MODE, CMD_DMA_MULTIPLE); - WDCDEBUG_PRINT(("cmd0643_6_setup_chip: timings reg now 0x%x 0x%x\n", + WDCDEBUG_PRINT(("cmd0643_6_chip_map: timings reg now 0x%x 0x%x\n", pci_conf_read(sc->sc_pc, sc->sc_tag, 0x54), pci_conf_read(sc->sc_pc, sc->sc_tag, 0x58)), DEBUG_PROBE); @@ -1874,27 +2030,82 @@ cmd0643_6_setup_channel(chp) } void -cy693_setup_cap(sc) +cy693_chip_map(sc, pa) struct pciide_softc *sc; -{ + struct pci_attach_args *pa; +{ + struct pciide_channel *cp; + pcireg_t interface = PCI_INTERFACE(pci_conf_read(sc->sc_pc, + sc->sc_tag, PCI_CLASS_REG)); + int compatchan; + + if (pciide_chipen(sc, pa) == 0) + return; + /* + * this chip has 2 PCI IDE functions, one for primary and one for + * secondary. So we need to call pciide_mapregs_compat() with + * the real channel + */ + if (pa->pa_function == 1) { + compatchan = 0; + } else if (pa->pa_function == 2) { + compatchan = 1; + } else { + printf("%s: unexpected PCI function %d\n", + sc->sc_wdcdev.sc_dev.dv_xname, pa->pa_function); + cp->hw_ok = 0; + return; + } + if (interface & PCIIDE_INTERFACE_BUS_MASTER_DMA) { + printf(": DMA"); + pciide_mapreg_dma(sc, pa); + } else { + printf(": no DMA"); + sc->sc_dma_ok = 0; + } - sc->sc_wdcdev.cap |= WDC_CAPABILITY_DATA32 | WDC_CAPABILITY_MODE | - WDC_CAPABILITY_DMA; + pciide_print_channels(sc->sc_wdcdev.nchannels, interface); + + if (sc->sc_dma_ok) + sc->sc_wdcdev.cap |= WDC_CAPABILITY_DMA; + sc->sc_wdcdev.cap |= WDC_CAPABILITY_DATA16 | WDC_CAPABILITY_DATA32 | + WDC_CAPABILITY_MODE; sc->sc_wdcdev.PIO_cap = 4; sc->sc_wdcdev.DMA_cap = 2; sc->sc_wdcdev.set_modes = cy693_setup_channel; -} -void -cy693_setup_chip(sc) - struct pciide_softc *sc; -{ + sc->sc_wdcdev.channels = sc->wdc_chanarray; + sc->sc_wdcdev.nchannels = 1; - WDCDEBUG_PRINT(("cy693_setup_chip: old timings reg 0x%x\n", - pci_conf_read(sc->sc_pc, sc->sc_tag, CY_CMD_CTRL)), - DEBUG_PROBE); - cy693_setup_channel(&sc->pciide_channels[0].wdc_channel); - WDCDEBUG_PRINT(("cy693_setup_chip: new timings reg 0x%x\n", + /* Only one channel for this chip; if we are here it's enabled */ + cp = &sc->pciide_channels[0]; + sc->wdc_chanarray[0] = &cp->wdc_channel; + cp->name = PCIIDE_CHANNEL_NAME(0); + cp->wdc_channel.channel = 0; + cp->wdc_channel.wdc = &sc->sc_wdcdev; + cp->wdc_channel.ch_queue = + malloc(sizeof(struct channel_queue), M_DEVBUF, M_NOWAIT); + if (cp->wdc_channel.ch_queue == NULL) { + printf("%s: %s" + "cannot allocate memory for command queue", + sc->sc_wdcdev.sc_dev.dv_xname, cp->name); + return; + } + + cp->wdc_channel.data32iot = cp->wdc_channel.cmd_iot; + cp->wdc_channel.data32ioh = cp->wdc_channel.cmd_ioh; + wdcattach(&cp->wdc_channel); + if (pciiide_chan_candisable(cp)) { + pci_conf_write(sc->sc_pc, sc->sc_tag, + PCI_COMMAND_STATUS_REG, 0); + } + pciide_map_compat_intr(pa, cp, compatchan, interface); + if (cp->hw_ok == 0) + return; + WDCDEBUG_PRINT(("cy693_chip_map: old timings reg 0x%x\n", + pci_conf_read(sc->sc_pc, sc->sc_tag, CY_CMD_CTRL)),DEBUG_PROBE); + cy693_setup_channel(&cp->wdc_channel); + WDCDEBUG_PRINT(("cy693_chip_map: new timings reg 0x%x\n", pci_conf_read(sc->sc_pc, sc->sc_tag, CY_CMD_CTRL)), DEBUG_PROBE); } @@ -1908,6 +2119,7 @@ cy693_setup_channel(chp) u_int32_t idedma_ctl; struct pciide_channel *cp = (struct pciide_channel*)chp; struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc; + int dma_mode = -1; cy_cmd_ctrl = idedma_ctl = 0; @@ -1922,15 +2134,9 @@ cy693_setup_channel(chp) /* add timing values, setup DMA if needed */ if (drvp->drive_flags & DRIVE_DMA) { idedma_ctl |= IDEDMA_CTL_DRV_DMA(drive); - /* - * use Multiword DMA - * Timings will be used for both PIO and DMA, so adjust - * DMA mode if needed - */ - if (drvp->PIO_mode > (drvp->DMA_mode + 2)) - drvp->PIO_mode = drvp->DMA_mode + 2; - if (drvp->DMA_mode == 0) - drvp->PIO_mode = 0; + /* use Multiword DMA */ + if (dma_mode == -1 || dma_mode > drvp->DMA_mode) + dma_mode = drvp->DMA_mode; } cy_cmd_ctrl |= (cy_pio_pulse[drvp->PIO_mode] << CY_CMD_CTRL_IOW_PULSE_OFF(drive)); @@ -1942,6 +2148,8 @@ cy693_setup_channel(chp) CY_CMD_CTRL_IOR_REC_OFF(drive)); } pci_conf_write(sc->sc_pc, sc->sc_tag, CY_CMD_CTRL, cy_cmd_ctrl); + chp->ch_drive[0].DMA_mode = dma_mode; + chp->ch_drive[1].DMA_mode = dma_mode; pciide_print_modes(cp); if (idedma_ctl != 0) { /* Add software bits in status register */ @@ -1951,81 +2159,68 @@ cy693_setup_channel(chp) } void -cy693_channel_map(pa, cp) +sis_chip_map(sc, pa) + struct pciide_softc *sc; struct pci_attach_args *pa; - struct pciide_channel *cp; { - struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc; + struct pciide_channel *cp; + int channel; + u_int8_t sis_ctr0 = pciide_pci_read(sc->sc_pc, sc->sc_tag, SIS_CTRL0); + pcireg_t interface = PCI_INTERFACE(pci_conf_read(sc->sc_pc, + sc->sc_tag, PCI_CLASS_REG)); bus_size_t cmdsize, ctlsize; - struct channel_softc *wdc_cp = &cp->wdc_channel; - int interface = - PCI_INTERFACE(pci_conf_read(sc->sc_pc, sc->sc_tag, PCI_CLASS_REG)); - int compatchan; - -#ifdef DIAGNOSTIC - if (wdc_cp->channel != 0) - panic("cy693_channel_map: channel %d", wdc_cp->channel); -#endif - /* - * this chip has 2 PCI IDE functions, one for primary and one for - * secondary. So we need to call pciide_mapregs_compat() with - * the real channel - */ - if (pa->pa_function == 1) { - compatchan = 0; - } else if (pa->pa_function == 2) { - compatchan = 1; - } else { - printf("%s: unexpected PCI function %d\n", - sc->sc_wdcdev.sc_dev.dv_xname, pa->pa_function); - cp->hw_ok = 0; + if (pciide_chipen(sc, pa) == 0) return; - } - - /* Only one channel for this chip; if we are here it's enabled */ - if (interface & PCIIDE_INTERFACE_PCI(0)) - cp->hw_ok = pciide_mapregs_native(pa, cp, &cmdsize, &ctlsize); - else - cp->hw_ok = pciide_mapregs_compat(pa, cp, compatchan, - &cmdsize, &ctlsize); - if (cp->hw_ok == 0) - return; - wdc_cp->data32iot = wdc_cp->cmd_iot; - wdc_cp->data32ioh = wdc_cp->cmd_ioh; - wdcattach(wdc_cp); - if (pciiide_chan_candisable(cp)) { - pci_conf_write(sc->sc_pc, sc->sc_tag, - PCI_COMMAND_STATUS_REG, 0); - } - pciide_map_compat_intr(pa, cp, compatchan, interface); -} -void -sis_setup_cap(sc) - struct pciide_softc *sc; -{ + printf(": DMA"); + pciide_mapreg_dma(sc, pa); + + if (sc->sc_dma_ok) + sc->sc_wdcdev.cap |= WDC_CAPABILITY_DMA | WDC_CAPABILITY_UDMA; - sc->sc_wdcdev.cap |= WDC_CAPABILITY_DATA32 | WDC_CAPABILITY_MODE | - WDC_CAPABILITY_DMA | WDC_CAPABILITY_UDMA; + sc->sc_wdcdev.cap |= WDC_CAPABILITY_DATA16 | WDC_CAPABILITY_DATA32 | + WDC_CAPABILITY_MODE; sc->sc_wdcdev.PIO_cap = 4; sc->sc_wdcdev.DMA_cap = 2; sc->sc_wdcdev.UDMA_cap = 2; sc->sc_wdcdev.set_modes = sis_setup_channel; -} + sc->sc_wdcdev.channels = sc->wdc_chanarray; + sc->sc_wdcdev.nchannels = PCIIDE_NUM_CHANNELS; -void -sis_setup_chip(sc) - struct pciide_softc *sc; -{ - int channel; + pciide_print_channels(sc->sc_wdcdev.nchannels, interface); - for (channel = 0; channel < sc->sc_wdcdev.nchannels; channel++) { - sis_setup_channel(&sc->pciide_channels[channel].wdc_channel); - } pciide_pci_write(sc->sc_pc, sc->sc_tag, SIS_MISC, pciide_pci_read(sc->sc_pc, sc->sc_tag, SIS_MISC) | SIS_MISC_TIM_SEL | SIS_MISC_FIFO_SIZE); + + for (channel = 0; channel < sc->sc_wdcdev.nchannels; channel++) { + cp = &sc->pciide_channels[channel]; + if (pciide_chansetup(sc, channel, interface) == 0) + continue; + if ((channel == 0 && (sis_ctr0 & SIS_CTRL0_CHAN0_EN) == 0) || + (channel == 1 && (sis_ctr0 & SIS_CTRL0_CHAN1_EN) == 0)) { + printf("%s: %s ignored (disabled)\n", + sc->sc_wdcdev.sc_dev.dv_xname, cp->name); + return; + } + pciide_mapchan(pa, cp, interface, &cmdsize, &ctlsize, + pciide_pci_intr); + if (cp->hw_ok == 0) + continue; + if (pciiide_chan_candisable(cp)) { + if (channel == 0) + sis_ctr0 &= ~SIS_CTRL0_CHAN0_EN; + else + sis_ctr0 &= ~SIS_CTRL0_CHAN1_EN; + pciide_pci_write(sc->sc_pc, sc->sc_tag, SIS_CTRL0, + sis_ctr0); + } + pciide_map_compat_intr(pa, cp, channel, interface); + if (cp->hw_ok == 0) + continue; + sis_setup_channel(&cp->wdc_channel); + } } void @@ -2039,7 +2234,7 @@ sis_setup_channel(chp) struct pciide_channel *cp = (struct pciide_channel*)chp; struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc; - WDCDEBUG_PRINT(("sis_setup_chip: old timings reg for " + WDCDEBUG_PRINT(("sis_setup_channel: old timings reg for " "channel %d 0x%x\n", chp->channel, pci_conf_read(sc->sc_pc, sc->sc_tag, SIS_TIM(chp->channel))), DEBUG_PROBE); @@ -2084,7 +2279,7 @@ pio: sis_tim |= sis_pio_act[drvp->PIO_mode] << sis_tim |= sis_pio_rec[drvp->PIO_mode] << SIS_TIM_REC_OFF(drive); } - WDCDEBUG_PRINT(("sis_setup_chip: new timings reg for " + WDCDEBUG_PRINT(("sis_setup_channel: new timings reg for " "channel %d 0x%x\n", chp->channel, sis_tim), DEBUG_PROBE); pci_conf_write(sc->sc_pc, sc->sc_tag, SIS_TIM(chp->channel), sis_tim); if (idedma_ctl != 0) { @@ -2096,62 +2291,76 @@ pio: sis_tim |= sis_pio_act[drvp->PIO_mode] << } void -sis_channel_map(pa, cp) +acer_chip_map(sc, pa) + struct pciide_softc *sc; struct pci_attach_args *pa; - struct pciide_channel *cp; { - struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc; + struct pciide_channel *cp; + int channel; + pcireg_t cr, interface; bus_size_t cmdsize, ctlsize; - struct channel_softc *wdc_cp = &cp->wdc_channel; - u_int8_t sis_ctr0 = pciide_pci_read(sc->sc_pc, sc->sc_tag, SIS_CTRL0); - int interface = - PCI_INTERFACE(pci_conf_read(sc->sc_pc, sc->sc_tag, PCI_CLASS_REG)); - if ((wdc_cp->channel == 0 && (sis_ctr0 & SIS_CTRL0_CHAN0_EN) == 0) || - (wdc_cp->channel == 1 && (sis_ctr0 & SIS_CTRL0_CHAN1_EN) == 0)) { - printf("%s: %s ignored (disabled)\n", - sc->sc_wdcdev.sc_dev.dv_xname, cp->name); + if (pciide_chipen(sc, pa) == 0) return; - } - pciide_mapchan(pa, cp, interface, &cmdsize, &ctlsize); - if (cp->hw_ok == 0) - return; - if (pciiide_chan_candisable(cp)) { - if (wdc_cp->channel == 0) - sis_ctr0 &= ~SIS_CTRL0_CHAN0_EN; - else - sis_ctr0 &= ~SIS_CTRL0_CHAN1_EN; - pciide_pci_write(sc->sc_pc, sc->sc_tag, SIS_CTRL0, sis_ctr0); - } - pciide_map_compat_intr(pa, cp, wdc_cp->channel, interface); -} + printf(": DMA"); + pciide_mapreg_dma(sc, pa); -void -acer_setup_cap(sc) - struct pciide_softc *sc; -{ + if (sc->sc_dma_ok) + sc->sc_wdcdev.cap |= WDC_CAPABILITY_DMA | WDC_CAPABILITY_UDMA; - sc->sc_wdcdev.cap |= WDC_CAPABILITY_DATA32 | WDC_CAPABILITY_MODE | - WDC_CAPABILITY_DMA | WDC_CAPABILITY_UDMA; + sc->sc_wdcdev.cap |= WDC_CAPABILITY_DATA16 | WDC_CAPABILITY_DATA32 | + WDC_CAPABILITY_MODE; sc->sc_wdcdev.PIO_cap = 4; sc->sc_wdcdev.DMA_cap = 2; sc->sc_wdcdev.UDMA_cap = 2; sc->sc_wdcdev.set_modes = acer_setup_channel; -} - -void -acer_setup_chip(sc) - struct pciide_softc *sc; -{ - int channel; + sc->sc_wdcdev.channels = sc->wdc_chanarray; + sc->sc_wdcdev.nchannels = PCIIDE_NUM_CHANNELS; pciide_pci_write(sc->sc_pc, sc->sc_tag, ACER_CDRC, (pciide_pci_read(sc->sc_pc, sc->sc_tag, ACER_CDRC) | ACER_CDRC_DMA_EN) & ~ACER_CDRC_FIFO_DISABLE); + + /* Enable "microsoft register bits" R/W. */ + pciide_pci_write(sc->sc_pc, sc->sc_tag, ACER_CCAR3, + pciide_pci_read(sc->sc_pc, sc->sc_tag, ACER_CCAR3) | ACER_CCAR3_PI); + pciide_pci_write(sc->sc_pc, sc->sc_tag, ACER_CCAR1, + pciide_pci_read(sc->sc_pc, sc->sc_tag, ACER_CCAR1) & + ~(ACER_CHANSTATUS_RO|PCIIDE_CHAN_RO(0)|PCIIDE_CHAN_RO(1))); + pciide_pci_write(sc->sc_pc, sc->sc_tag, ACER_CCAR2, + pciide_pci_read(sc->sc_pc, sc->sc_tag, ACER_CCAR2) & + ~ACER_CHANSTATUSREGS_RO); + cr = pci_conf_read(sc->sc_pc, sc->sc_tag, PCI_CLASS_REG); + cr |= (PCIIDE_CHANSTATUS_EN << PCI_INTERFACE_SHIFT); + pci_conf_write(sc->sc_pc, sc->sc_tag, PCI_CLASS_REG, cr); + /* Don't use cr, re-read the real register content instead */ + interface = PCI_INTERFACE(pci_conf_read(sc->sc_pc, sc->sc_tag, + PCI_CLASS_REG)); + + pciide_print_channels(sc->sc_wdcdev.nchannels, interface); + for (channel = 0; channel < sc->sc_wdcdev.nchannels; channel++) { - acer_setup_channel(&sc->pciide_channels[channel].wdc_channel); + cp = &sc->pciide_channels[channel]; + if (pciide_chansetup(sc, channel, interface) == 0) + continue; + if ((interface & PCIIDE_CHAN_EN(channel)) == 0) { + printf("%s: %s ignored (disabled)\n", + sc->sc_wdcdev.sc_dev.dv_xname, cp->name); + continue; + } + pciide_mapchan(pa, cp, interface, &cmdsize, &ctlsize, + acer_pci_intr); + if (cp->hw_ok == 0) + continue; + if (pciiide_chan_candisable(cp)) { + cr &= ~(PCIIDE_CHAN_EN(channel) << PCI_INTERFACE_SHIFT); + pci_conf_write(sc->sc_pc, sc->sc_tag, + PCI_CLASS_REG, cr); + } + pciide_map_compat_intr(pa, cp, channel, interface); + acer_setup_channel(&cp->wdc_channel); } } @@ -2168,7 +2377,7 @@ acer_setup_channel(chp) idedma_ctl = 0; acer_fifo_udma = pci_conf_read(sc->sc_pc, sc->sc_tag, ACER_FTH_UDMA); - WDCDEBUG_PRINT(("acer_setup_chip: old fifo/udma reg 0x%x\n", + WDCDEBUG_PRINT(("acer_setup_channel: old fifo/udma reg 0x%x\n", acer_fifo_udma), DEBUG_PROBE); /* setup DMA if needed */ pciide_channel_dma_setup(cp); @@ -2178,7 +2387,7 @@ acer_setup_channel(chp) /* If no drive, skip */ if ((drvp->drive_flags & DRIVE) == 0) continue; - WDCDEBUG_PRINT(("acer_setup_chip: old timings reg for " + WDCDEBUG_PRINT(("acer_setup_channel: old timings reg for " "channel %d drive %d 0x%x\n", chp->channel, drive, pciide_pci_read(sc->sc_pc, sc->sc_tag, ACER_IDETIM(chp->channel, drive))), DEBUG_PROBE); @@ -2222,7 +2431,7 @@ pio: pciide_pci_write(sc->sc_pc, sc->sc_tag, ACER_IDETIM(chp->channel, drive), acer_pio[drvp->PIO_mode]); } - WDCDEBUG_PRINT(("acer_setup_chip: new fifo/udma reg 0x%x\n", + WDCDEBUG_PRINT(("acer_setup_channel: new fifo/udma reg 0x%x\n", acer_fifo_udma), DEBUG_PROBE); pci_conf_write(sc->sc_pc, sc->sc_tag, ACER_FTH_UDMA, acer_fifo_udma); if (idedma_ctl != 0) { @@ -2233,49 +2442,241 @@ pio: pciide_pci_write(sc->sc_pc, sc->sc_tag, pciide_print_modes(cp); } +int +acer_pci_intr(arg) + void *arg; +{ + struct pciide_softc *sc = arg; + struct pciide_channel *cp; + struct channel_softc *wdc_cp; + int i, rv, crv; + u_int32_t chids; + + rv = 0; + chids = pciide_pci_read(sc->sc_pc, sc->sc_tag, ACER_CHIDS); + for (i = 0; i < sc->sc_wdcdev.nchannels; i++) { + cp = &sc->pciide_channels[i]; + wdc_cp = &cp->wdc_channel; + /* If a compat channel skip. */ + if (cp->compat) + continue; + if (chids & ACER_CHIDS_INT(i)) { + crv = wdcintr(wdc_cp); + if (crv == 0) + printf("%s:%d: bogus intr\n", + sc->sc_wdcdev.sc_dev.dv_xname, i); + else + rv = 1; + } + } + return rv; +} + + void -acer_channel_map(pa, cp) +pdc202xx_chip_map(sc, pa) + struct pciide_softc *sc; struct pci_attach_args *pa; - struct pciide_channel *cp; { - struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc; + struct pciide_channel *cp; + int channel; + pcireg_t interface, st, mode; bus_size_t cmdsize, ctlsize; - struct channel_softc *wdc_cp = &cp->wdc_channel; - u_int32_t cr; - int interface; + + st = pci_conf_read(sc->sc_pc, sc->sc_tag, PDC2xx_STATE); + WDCDEBUG_PRINT(("pdc202xx_setup_chip: controller state 0x%x\n", st), + DEBUG_PROBE); + if (pciide_chipen(sc, pa) == 0) + return; + + /* turn off RAID mode */ + st &= ~PDC2xx_STATE_IDERAID; /* - * Enable "microsoft register bits" R/W. Will be done 2 times - * (one for each channel) but should'nt be a problem. There's no - * better place where to put this. + * can't rely on the PCI_CLASS_REG content if the chip was in raid + * mode. We have to fake interface */ - pciide_pci_write(sc->sc_pc, sc->sc_tag, ACER_CCAR3, - pciide_pci_read(sc->sc_pc, sc->sc_tag, ACER_CCAR3) | ACER_CCAR3_PI); - pciide_pci_write(sc->sc_pc, sc->sc_tag, ACER_CCAR1, - pciide_pci_read(sc->sc_pc, sc->sc_tag, ACER_CCAR1) & - ~(ACER_CHANSTATUS_RO|PCIIDE_CHAN_RO(0)|PCIIDE_CHAN_RO(1))); - pciide_pci_write(sc->sc_pc, sc->sc_tag, ACER_CCAR2, - pciide_pci_read(sc->sc_pc, sc->sc_tag, ACER_CCAR2) & - ~ACER_CHANSTATUSREGS_RO); - cr = pci_conf_read(sc->sc_pc, sc->sc_tag, PCI_CLASS_REG); - cr |= (PCIIDE_CHANSTATUS_EN << PCI_INTERFACE_SHIFT); - pci_conf_write(sc->sc_pc, sc->sc_tag, PCI_CLASS_REG, cr); - /* Don't use cr, re-read the real register content instead */ - interface = PCI_INTERFACE(pci_conf_read(sc->sc_pc, sc->sc_tag, - PCI_CLASS_REG)); + interface = PCIIDE_INTERFACE_SETTABLE(0) | PCIIDE_INTERFACE_SETTABLE(1); + if (st & PDC2xx_STATE_NATIVE) + interface |= PCIIDE_INTERFACE_PCI(0) | PCIIDE_INTERFACE_PCI(1); - if ((interface & PCIIDE_CHAN_EN(wdc_cp->channel)) == 0) { - printf("%s: %s ignored (disabled)\n", - sc->sc_wdcdev.sc_dev.dv_xname, cp->name); - return; - } + printf(": DMA"); + pciide_mapreg_dma(sc, pa); - pciide_mapchan(pa, cp, interface, &cmdsize, &ctlsize); - if (cp->hw_ok == 0) - return; - if (pciiide_chan_candisable(cp)) { - cr &= ~(PCIIDE_CHAN_EN(wdc_cp->channel) << PCI_INTERFACE_SHIFT); - pci_conf_write(sc->sc_pc, sc->sc_tag, PCI_CLASS_REG, cr); + sc->sc_wdcdev.cap = WDC_CAPABILITY_DATA16 | WDC_CAPABILITY_DATA32 | + WDC_CAPABILITY_MODE; + if (sc->sc_dma_ok) + sc->sc_wdcdev.cap |= WDC_CAPABILITY_DMA | WDC_CAPABILITY_UDMA; + sc->sc_wdcdev.PIO_cap = 4; + sc->sc_wdcdev.DMA_cap = 2; + if (sc->sc_pp->ide_product == PCI_PRODUCT_PROMISE_ULTRA66) + sc->sc_wdcdev.UDMA_cap = 4; + else + sc->sc_wdcdev.UDMA_cap = 2; + sc->sc_wdcdev.set_modes = pdc202xx_setup_channel; + sc->sc_wdcdev.channels = sc->wdc_chanarray; + sc->sc_wdcdev.nchannels = PCIIDE_NUM_CHANNELS; + + pciide_print_channels(sc->sc_wdcdev.nchannels, interface); + + /* setup failsafe defaults */ + mode = 0; + mode = PDC2xx_TIM_SET_PA(mode, pdc2xx_pa[0]); + mode = PDC2xx_TIM_SET_PB(mode, pdc2xx_pb[0]); + mode = PDC2xx_TIM_SET_MB(mode, pdc2xx_dma_mb[0]); + mode = PDC2xx_TIM_SET_MC(mode, pdc2xx_dma_mc[0]); + + for (channel = 0; channel < sc->sc_wdcdev.nchannels; channel++) { + WDCDEBUG_PRINT(("pdc202xx_setup_chip: channel %d drive 0 " + "initial timings 0x%x, now 0x%x\n", channel, + pci_conf_read(sc->sc_pc, sc->sc_tag, + PDC2xx_TIM(channel, 0)), mode | PDC2xx_TIM_IORDYp), + DEBUG_PROBE); + pci_conf_write(sc->sc_pc, sc->sc_tag, PDC2xx_TIM(channel, 0), + mode | PDC2xx_TIM_IORDYp); + WDCDEBUG_PRINT(("pdc202xx_setup_chip: channel %d drive 1 " + "initial timings 0x%x, now 0x%x\n", channel, + pci_conf_read(sc->sc_pc, sc->sc_tag, + PDC2xx_TIM(channel, 1)), mode), DEBUG_PROBE); + pci_conf_write(sc->sc_pc, sc->sc_tag, PDC2xx_TIM(channel, 1), + mode); + } + + mode = PDC2xx_SCR_DMA; + mode = PDC2xx_SCR_SET_GEN(mode, 0x1); /* the BIOS set it up this way */ + mode = PDC2xx_SCR_SET_I2C(mode, 0x3); /* ditto */ + mode = PDC2xx_SCR_SET_POLL(mode, 0x1); /* ditto */ + WDCDEBUG_PRINT(("pdc202xx_setup_chip: initial SCR 0x%x, now 0x%x\n", + bus_space_read_4(sc->sc_dma_iot, sc->sc_dma_ioh, PDC2xx_SCR), mode), + DEBUG_PROBE); + bus_space_write_4(sc->sc_dma_iot, sc->sc_dma_ioh, PDC2xx_SCR, mode); + + /* controller initial state register is OK even without BIOS */ + /* The Linux driver does this */ + mode = bus_space_read_1(sc->sc_dma_iot, sc->sc_dma_ioh, PDC2xx_PM); + WDCDEBUG_PRINT(("pdc202xx_setup_chip: primary mode 0x%x", mode ), + DEBUG_PROBE); + bus_space_write_1(sc->sc_dma_iot, sc->sc_dma_ioh, PDC2xx_PM, + mode | 0x1); + mode = bus_space_read_1(sc->sc_dma_iot, sc->sc_dma_ioh, PDC2xx_SM); + WDCDEBUG_PRINT((", secondary mode 0x%x\n", mode ), DEBUG_PROBE); + bus_space_write_1(sc->sc_dma_iot, sc->sc_dma_ioh, PDC2xx_SM, + mode | 0x1); + + for (channel = 0; channel < sc->sc_wdcdev.nchannels; channel++) { + cp = &sc->pciide_channels[channel]; + if (pciide_chansetup(sc, channel, interface) == 0) + continue; + if ((st & PDC2xx_STATE_EN(channel)) == 0) { + printf("%s: %s ignored (disabled)\n", + sc->sc_wdcdev.sc_dev.dv_xname, cp->name); + continue; + } + pciide_mapchan(pa, cp, interface, &cmdsize, &ctlsize, + pdc202xx_pci_intr); + if (cp->hw_ok == 0) + continue; + if (pciiide_chan_candisable(cp)) + st &= ~PDC2xx_STATE_EN(channel); + pciide_map_compat_intr(pa, cp, channel, interface); + pdc202xx_setup_channel(&cp->wdc_channel); + } + WDCDEBUG_PRINT(("pdc202xx_setup_chip: new controller state 0x%x\n", st), + DEBUG_PROBE); + pci_conf_write(sc->sc_pc, sc->sc_tag, PDC2xx_STATE, st); +return; +} + +void +pdc202xx_setup_channel(chp) + struct channel_softc *chp; +{ + struct ata_drive_datas *drvp; + int drive; + pcireg_t mode; + u_int32_t idedma_ctl; + struct pciide_channel *cp = (struct pciide_channel*)chp; + struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc; + + /* setup DMA if needed */ + pciide_channel_dma_setup(cp); + + idedma_ctl = 0; + for (drive = 0; drive < 2; drive++) { + drvp = &chp->ch_drive[drive]; + /* If no drive, skip */ + if ((drvp->drive_flags & DRIVE) == 0) + continue; + mode = PDC2xx_TIM_IORDY; + if (drvp->drive_flags & DRIVE_ATA) + mode |= PDC2xx_TIM_PRE; + if (drvp->drive_flags & DRIVE_UDMA) { + mode = PDC2xx_TIM_SET_MB(mode, + pdc2xx_udma_mb[drvp->UDMA_mode]); + mode = PDC2xx_TIM_SET_MC(mode, + pdc2xx_udma_mc[drvp->UDMA_mode]); + drvp->drive_flags &= ~DRIVE_DMA; + idedma_ctl |= IDEDMA_CTL_DRV_DMA(drive); + } else if (drvp->drive_flags & DRIVE_DMA) { + mode = PDC2xx_TIM_SET_MB(mode, + pdc2xx_dma_mb[drvp->DMA_mode]); + mode = PDC2xx_TIM_SET_MC(mode, + pdc2xx_dma_mc[drvp->DMA_mode]); + idedma_ctl |= IDEDMA_CTL_DRV_DMA(drive); + } else { + mode = PDC2xx_TIM_SET_MB(mode, + pdc2xx_dma_mb[0]); + mode = PDC2xx_TIM_SET_MC(mode, + pdc2xx_dma_mc[0]); + } + mode = PDC2xx_TIM_SET_PA(mode, pdc2xx_pa[drvp->PIO_mode]); + mode = PDC2xx_TIM_SET_PB(mode, pdc2xx_pb[drvp->PIO_mode]); + mode |= PDC2xx_TIM_SYNC; + if (drvp->PIO_mode >= 3 &&(drvp->drive_flags & DRIVE_ATA)) + mode |= PDC2xx_TIM_ERRDY; + if (drive == 0) + mode |= PDC2xx_TIM_IORDYp; + WDCDEBUG_PRINT(("pdc202xx_setup_channel: %s:%d:%d " + "timings 0x%x\n", + sc->sc_wdcdev.sc_dev.dv_xname, + chp->channel, drive, mode), DEBUG_PROBE); + pci_conf_write(sc->sc_pc, sc->sc_tag, + PDC2xx_TIM(chp->channel, drive), mode); + } + if (idedma_ctl != 0) { + /* Add software bits in status register */ + bus_space_write_1(sc->sc_dma_iot, sc->sc_dma_ioh, + IDEDMA_CTL, idedma_ctl); } - pciide_map_compat_intr(pa, cp, wdc_cp->channel, interface); + pciide_print_modes(cp); +} + +int +pdc202xx_pci_intr(arg) + void *arg; +{ + struct pciide_softc *sc = arg; + struct pciide_channel *cp; + struct channel_softc *wdc_cp; + int i, rv, crv; + u_int32_t scr; + + rv = 0; + scr = bus_space_read_4(sc->sc_dma_iot, sc->sc_dma_ioh, PDC2xx_SCR); + for (i = 0; i < sc->sc_wdcdev.nchannels; i++) { + cp = &sc->pciide_channels[i]; + wdc_cp = &cp->wdc_channel; + /* If a compat channel skip. */ + if (cp->compat) + continue; + if (scr & PDC2xx_SCR_INT(i)) { + crv = wdcintr(wdc_cp); + if (crv == 0) + printf("%s:%d: bogus intr\n", + sc->sc_wdcdev.sc_dev.dv_xname, i); + else + rv = 1; + } + } + return rv; } |