summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorJason Wright <jason@cvs.openbsd.org>2002-11-20 19:39:03 +0000
committerJason Wright <jason@cvs.openbsd.org>2002-11-20 19:39:03 +0000
commit565f4050db9b7fe2f602d71ee35c8f99778caabb (patch)
tree813945c4ae213d3b6eacb66c73f154388820323a /sys/dev
parentdaa6ecbb5037969970ccdff19fe3bb48ef5df504 (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')
-rw-r--r--sys/dev/pci/pciide.c70
-rw-r--r--sys/dev/pci/pciide_natsemi_reg.h9
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 };