diff options
author | Jason Wright <jason@cvs.openbsd.org> | 2002-11-20 19:39:03 +0000 |
---|---|---|
committer | Jason Wright <jason@cvs.openbsd.org> | 2002-11-20 19:39:03 +0000 |
commit | 565f4050db9b7fe2f602d71ee35c8f99778caabb (patch) | |
tree | 813945c4ae213d3b6eacb66c73f154388820323a /sys/dev/pci | |
parent | daa6ecbb5037969970ccdff19fe3bb48ef5df504 (diff) |
Overhaul natsemi driver:
- setup the DMA bits on the second channel correctly (missing channel offset)
- setup timing for PIO/DMA modes
- workaround the fact that the INTR/ERR clear bits are in the wrong register
- only read the interrupt mask register once in the interrupt path
Many thanks to grange@ for assistance and debugging!
Diffstat (limited to 'sys/dev/pci')
-rw-r--r-- | sys/dev/pci/pciide.c | 70 | ||||
-rw-r--r-- | sys/dev/pci/pciide_natsemi_reg.h | 9 |
2 files changed, 57 insertions, 22 deletions
diff --git a/sys/dev/pci/pciide.c b/sys/dev/pci/pciide.c index eea7ccc180b..3f68291403b 100644 --- a/sys/dev/pci/pciide.c +++ b/sys/dev/pci/pciide.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pciide.c,v 1.97 2002/11/18 11:06:40 grange Exp $ */ +/* $OpenBSD: pciide.c,v 1.98 2002/11/20 19:39:02 jason Exp $ */ /* $NetBSD: pciide.c,v 1.127 2001/08/03 01:31:08 tsutsui Exp $ */ /* @@ -224,6 +224,7 @@ void sis_setup_channel(struct channel_softc*); void natsemi_chip_map(struct pciide_softc*, struct pci_attach_args*); void natsemi_setup_channel(struct channel_softc*); int natsemi_pci_intr(void *); +void natsemi_irqack(struct channel_softc *); void acer_chip_map(struct pciide_softc*, struct pci_attach_args*); void acer_setup_channel(struct channel_softc*); @@ -3309,7 +3310,7 @@ natsemi_chip_map(sc, pa) if (sc->sc_dma_ok) { sc->sc_wdcdev.cap |= WDC_CAPABILITY_DMA | WDC_CAPABILITY_IRQACK; - sc->sc_wdcdev.irqack = pciide_irqack; + sc->sc_wdcdev.irqack = natsemi_irqack; } pciide_pci_write(sc->sc_pc, sc->sc_tag, NATSEMI_CCBT, 0xb7); @@ -3358,7 +3359,6 @@ natsemi_chip_map(sc, pa) } natsemi_setup_channel(&cp->wdc_channel); } - } void @@ -3370,6 +3370,7 @@ natsemi_setup_channel(chp) u_int32_t idedma_ctl = 0; struct pciide_channel *cp = (struct pciide_channel*)chp; struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc; + u_int8_t tim; /* setup DMA if needed */ pciide_channel_dma_setup(cp); @@ -3382,29 +3383,34 @@ natsemi_setup_channel(chp) ndrives++; /* add timing values, setup DMA if needed */ - if ((drvp->drive_flags & DRIVE_DMA) == 0) - goto pio; - - /* - * use Multiword DMA - * Timings will be used for both PIO and DMA, - * so adjust DMA mode if needed - */ - if (drvp->PIO_mode >= 3 && - (drvp->DMA_mode + 2) > drvp->PIO_mode) { - drvp->DMA_mode = drvp->PIO_mode - 2; + if ((drvp->drive_flags & DRIVE_DMA) == 0) { + tim = natsemi_pio_pulse[drvp->PIO_mode] | + (natsemi_pio_recover[drvp->PIO_mode] << 4); + } else { + /* + * use Multiword DMA + * Timings will be used for both PIO and DMA, + * so adjust DMA mode if needed + */ + if (drvp->PIO_mode >= 3 && + (drvp->DMA_mode + 2) > drvp->PIO_mode) { + drvp->DMA_mode = drvp->PIO_mode - 2; + } + idedma_ctl |= IDEDMA_CTL_DRV_DMA(drive); + tim = natsemi_dma_pulse[drvp->DMA_mode] | + (natsemi_dma_recover[drvp->DMA_mode] << 4); } - idedma_ctl |= IDEDMA_CTL_DRV_DMA(drive); -pio: + pciide_pci_write(sc->sc_pc, sc->sc_tag, - NATSEMI_RTREG(chp->channel, drive), 0x85); + NATSEMI_RTREG(chp->channel, drive), tim); pciide_pci_write(sc->sc_pc, sc->sc_tag, - NATSEMI_WTREG(chp->channel, drive), 0x85); + NATSEMI_WTREG(chp->channel, drive), tim); } 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); + (chp->channel * IDEDMA_SCH_OFFSET) + IDEDMA_CTL, + idedma_ctl); } if (ndrives > 0) { /* Unmask the channel if at least one drive is found */ @@ -3412,6 +3418,7 @@ pio: pciide_pci_read(sc->sc_pc, sc->sc_tag, NATSEMI_CTRL2) & ~(NATSEMI_CHMASK(chp->channel))); } + pciide_print_modes(cp); /* Go ahead and ack interrupts generated during probe. */ @@ -3421,6 +3428,24 @@ pio: (chp->channel * IDEDMA_SCH_OFFSET) + IDEDMA_CTL)); } +void +natsemi_irqack(chp) + struct channel_softc *chp; +{ + struct pciide_channel *cp = (struct pciide_channel*)chp; + struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc; + u_int8_t clr; + + /* The "clear" bits are in the wrong register *sigh* */ + clr = bus_space_read_1(sc->sc_dma_iot, sc->sc_dma_ioh, + IDEDMA_CMD + IDEDMA_SCH_OFFSET * chp->channel); + clr |= bus_space_read_1(sc->sc_dma_iot, sc->sc_dma_ioh, + IDEDMA_CTL + IDEDMA_SCH_OFFSET * chp->channel) & + (IDEDMA_CTL_ERR | IDEDMA_CTL_INTR); + bus_space_write_1(sc->sc_dma_iot, sc->sc_dma_ioh, + IDEDMA_CMD + IDEDMA_SCH_OFFSET * chp->channel, clr); +} + int natsemi_pci_intr(arg) void *arg; @@ -3432,24 +3457,27 @@ natsemi_pci_intr(arg) u_int8_t ide_dmactl, msk; rv = 0; + msk = pciide_pci_read(sc->sc_pc, sc->sc_tag, NATSEMI_CTRL2); 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 this channel is masked, skip it. */ - msk = pciide_pci_read(sc->sc_pc, sc->sc_tag, NATSEMI_CTRL2); if (msk & NATSEMI_CHMASK(i)) continue; /* Get intr status */ ide_dmactl = bus_space_read_1(sc->sc_dma_iot, sc->sc_dma_ioh, (i * IDEDMA_SCH_OFFSET) + IDEDMA_CTL); + if (ide_dmactl & IDEDMA_CTL_ERR) printf("%s:%d: error intr\n", sc->sc_wdcdev.sc_dev.dv_xname, i); + if (ide_dmactl & IDEDMA_CTL_INTR) { crv = wdcintr(wdc_cp); if (crv == 0) @@ -3459,7 +3487,7 @@ natsemi_pci_intr(arg) rv = 1; } } - return rv; + return (rv); } void diff --git a/sys/dev/pci/pciide_natsemi_reg.h b/sys/dev/pci/pciide_natsemi_reg.h index daa3ce5c76d..370b4e0297f 100644 --- a/sys/dev/pci/pciide_natsemi_reg.h +++ b/sys/dev/pci/pciide_natsemi_reg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pciide_natsemi_reg.h,v 1.1 2001/09/29 02:41:31 jason Exp $ */ +/* $OpenBSD: pciide_natsemi_reg.h,v 1.2 2002/11/20 19:39:02 jason Exp $ */ /* * Copyright (c) 2001 Jason L. Wright (jason@thought.net) @@ -95,3 +95,10 @@ #define NATSEMI_RTREG(c,d) (0x44 + (c * 8) + (d * 4) + 0) #define NATSEMI_WTREG(c,d) (0x44 + (c * 8) + (d * 4) + 1) + +/* 17 - N = number of clocks */ +static u_int8_t natsemi_pio_pulse[] = { 7, 12, 13, 14, 14 }; +static u_int8_t natsemi_dma_pulse[] = { 7, 10, 10 }; +/* 16 - N = number of clocks */ +static u_int8_t natsemi_pio_recover[] = { 6, 8, 11, 13, 15 }; +static u_int8_t natsemi_dma_recover[] = { 6, 8, 9 }; |