summaryrefslogtreecommitdiff
path: root/sys/dev/pci/pciide.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/pci/pciide.c')
-rw-r--r--sys/dev/pci/pciide.c579
1 files changed, 280 insertions, 299 deletions
diff --git a/sys/dev/pci/pciide.c b/sys/dev/pci/pciide.c
index b860c856db8..ae181f83d73 100644
--- a/sys/dev/pci/pciide.c
+++ b/sys/dev/pci/pciide.c
@@ -1,5 +1,5 @@
-/* $OpenBSD: pciide.c,v 1.48 2001/03/26 22:17:05 chris Exp $ */
-/* $NetBSD: pciide.c,v 1.48 1999/11/28 20:05:18 bouyer Exp $ */
+/* $OpenBSD: pciide.c,v 1.49 2001/04/04 07:02:51 csapuntz Exp $ */
+/* $NetBSD: pciide.c,v 1.110 2001/03/20 17:56:46 bouyer Exp $ */
/*
* Copyright (c) 1999 Manuel Bouyer.
@@ -14,23 +14,22 @@
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
@@ -97,6 +96,8 @@ int wdcdebug_pciide_mask = 0;
#include <vm/vm_param.h>
#include <vm/vm_kern.h>
+#include <machine/endian.h>
+
#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
#include <dev/pci/pcidevs.h>
@@ -119,15 +120,6 @@ int wdcdebug_pciide_mask = 0;
#include <dev/ic/wdcreg.h>
#include <dev/ic/wdcvar.h>
-#if BYTE_ORDER == BIG_ENDIAN
-#include <machine/bswap.h>
-#define htopci(x) bswap32(x)
-#define pcitoh(x) bswap32(x)
-#else
-#define htopci(x) (x)
-#define pcitoh(x) (x)
-#endif
-
/* inlines for reading/writing 8-bit PCI registers */
static __inline u_int8_t pciide_pci_read __P((pci_chipset_tag_t, pcitag_t,
int));
@@ -449,8 +441,6 @@ const struct pciide_vendor_desc pciide_vendors[] = {
sizeof(pciide_promise_products)/sizeof(pciide_promise_products[0]) }
};
-#define PCIIDE_CHANNEL_NAME(chan) ((chan) == 0 ? "channel 0" : "channel 1")
-
/* options passed via the 'flags' config keyword */
#define PCIIDE_OPTIONS_DMA 0x01
@@ -606,16 +596,16 @@ pciide_chipen(sc, 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");
+ PCI_COMMAND_STATUS_REG);
+ printf("%s: device disabled (at %s)\n",
+ sc->sc_wdcdev.sc_dev.dv_xname,
+ (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;
@@ -994,17 +984,17 @@ pciide_dma_init(v, channel, drive, databuf, datalen, flags)
}
#endif
dma_maps->dma_table[seg].base_addr =
- htopci(dma_maps->dmamap_xfer->dm_segs[seg].ds_addr);
+ htole32(dma_maps->dmamap_xfer->dm_segs[seg].ds_addr);
dma_maps->dma_table[seg].byte_count =
- htopci(dma_maps->dmamap_xfer->dm_segs[seg].ds_len &
+ htole32(dma_maps->dmamap_xfer->dm_segs[seg].ds_len &
IDEDMA_BYTE_COUNT_MASK);
WDCDEBUG_PRINT(("\t seg %d len %d addr 0x%x\n",
- seg, pcitoh(dma_maps->dma_table[seg].byte_count),
- pcitoh(dma_maps->dma_table[seg].base_addr)), DEBUG_DMA);
+ seg, le32toh(dma_maps->dma_table[seg].byte_count),
+ le32toh(dma_maps->dma_table[seg].base_addr)), DEBUG_DMA);
}
dma_maps->dma_table[dma_maps->dmamap_xfer->dm_nsegs -1].byte_count |=
- htopci(IDEDMA_BYTE_COUNT_EOT);
+ htole32(IDEDMA_BYTE_COUNT_EOT);
#ifndef __OpenBSD__
bus_dmamap_sync(sc->sc_dmat, dma_maps->dmamap_table,
@@ -1099,13 +1089,13 @@ pciide_dma_finish(v, channel, drive)
status);
if ((status & IDEDMA_CTL_ERR) != 0) {
- printf("%s:%d:%d: Bus-Master DMA error: status=0x%x\n",
+ printf("%s:%d:%d: bus-master DMA error: status=0x%x\n",
sc->sc_wdcdev.sc_dev.dv_xname, channel, drive, status);
error |= WDC_DMAST_ERR;
}
if ((status & IDEDMA_CTL_INTR) == 0) {
- printf("%s:%d:%d: Bus-Master DMA error: missing interrupt, "
+ printf("%s:%d:%d: bus-master DMA error: missing interrupt, "
"status=0x%x\n", sc->sc_wdcdev.sc_dev.dv_xname, channel,
drive, status);
error |= WDC_DMAST_NOIRQ;
@@ -1150,14 +1140,12 @@ pciide_chansetup(sc, channel, interface)
printf("%s: %s "
"cannot allocate memory for command queue",
sc->sc_wdcdev.sc_dev.dv_xname, cp->name);
- return 0;
+ return 0;
}
return 1;
-
}
-
/* some common code used by several chip channel_map */
void
pciide_mapchan(pa, cp, interface, cmdsizep, ctlsizep, pci_intr)
@@ -1258,8 +1246,7 @@ default_chip_map(sc, pa)
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 interface = PCI_INTERFACE(pa->pa_class);
pcireg_t csr;
int channel, drive;
struct ata_drive_datas *drvp;
@@ -1388,7 +1375,6 @@ next:
idedma_ctl);
}
}
-
}
void
@@ -1401,14 +1387,15 @@ piix_chip_map(sc, pa)
u_int32_t idetim;
bus_size_t cmdsize, ctlsize;
- pcireg_t interface = PCI_INTERFACE(pci_conf_read(sc->sc_pc,
- sc->sc_tag, PCI_CLASS_REG));
+ pcireg_t interface = PCI_INTERFACE(pa->pa_class);
if (pciide_chipen(sc, pa) == 0)
return;
printf(": DMA");
pciide_mapreg_dma(sc, pa);
+ 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_IRQACK;
sc->sc_wdcdev.irqack = pciide_irqack;
@@ -1423,9 +1410,6 @@ piix_chip_map(sc, pa)
break;
}
}
-
- 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;
switch (sc->sc_pp->ide_product) {
@@ -1534,7 +1518,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;
@@ -1683,7 +1667,7 @@ piix3_4_setup_channel(chp)
if (sc->sc_pp->ide_product == PCI_PRODUCT_INTEL_82801BAM_IDE ||
sc->sc_pp->ide_product == PCI_PRODUCT_INTEL_82801BA_IDE) {
/* setup Ultra/100 */
- if (drvp->UDMA_mode > 2 &&
+ if (drvp->UDMA_mode > 2 &&
(ideconf & PIIX_CONFIG_CR(channel, drive)) == 0)
drvp->UDMA_mode = 2;
if (drvp->UDMA_mode > 4) {
@@ -1698,8 +1682,8 @@ piix3_4_setup_channel(chp)
drive);
}
}
- }
- if (sc->sc_pp->ide_product == PCI_PRODUCT_INTEL_82801AA_IDE ) {
+ }
+ 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)
@@ -1855,8 +1839,7 @@ amd756_chip_map(sc, pa)
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 interface = PCI_INTERFACE(pa->pa_class);
int channel;
pcireg_t chanenable;
bus_size_t cmdsize, ctlsize;
@@ -1866,14 +1849,13 @@ amd756_chip_map(sc, pa)
printf(": DMA");
pciide_mapreg_dma(sc, pa);
-
+ 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.cap |= WDC_CAPABILITY_IRQACK;
sc->sc_wdcdev.irqack = pciide_irqack;
}
- 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 = 4;
@@ -2025,6 +2007,8 @@ apollo_chip_map(sc, pa)
return;
printf(": DMA");
pciide_mapreg_dma(sc, pa);
+ 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_IRQACK;
sc->sc_wdcdev.irqack = pciide_irqack;
@@ -2032,14 +2016,12 @@ apollo_chip_map(sc, pa)
&& rev >= 6)
sc->sc_wdcdev.cap |= WDC_CAPABILITY_UDMA;
}
- 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;
pciide_print_channels(sc->sc_wdcdev.nchannels, interface);
@@ -2122,7 +2104,7 @@ apollo_setup_channel(chp)
datatim_reg = pci_conf_read(sc->sc_pc, sc->sc_tag, APO_DATATIM);
udmatim_reg = pci_conf_read(sc->sc_pc, sc->sc_tag, APO_UDMA);
datatim_reg &= ~APO_DATATIM_MASK(chp->channel);
- udmatim_reg &= ~AP0_UDMA_MASK(chp->channel);
+ udmatim_reg &= ~APO_UDMA_MASK(chp->channel);
/* setup DMA if needed */
pciide_channel_dma_setup(cp);
@@ -2273,7 +2255,6 @@ cmd_channel_map(pa, sc, channel)
}
}
pciide_map_compat_intr(pa, cp, channel, interface);
-
}
int
@@ -2315,7 +2296,6 @@ cmd_chip_map(sc, pa)
{
int channel;
pcireg_t interface = PCI_INTERFACE(pa->pa_class);
-
/*
* For a CMD PCI064x, the use of PCI_COMMAND_IO_ENABLE
* and base adresses registers can be disabled at
@@ -2336,7 +2316,7 @@ cmd_chip_map(sc, pa)
sc->sc_wdcdev.channels = sc->wdc_chanarray;
sc->sc_wdcdev.nchannels = PCIIDE_NUM_CHANNELS;
- sc->sc_wdcdev.cap |= WDC_CAPABILITY_DATA16;
+ sc->sc_wdcdev.cap = WDC_CAPABILITY_DATA16;
pciide_print_channels(sc->sc_wdcdev.nchannels, interface);
@@ -2444,6 +2424,10 @@ cmd0643_9_chip_map(sc, pa)
continue;
cmd0643_9_setup_channel(&cp->wdc_channel);
}
+ /*
+ * note - this also makes sure we clear the irq disable and reset
+ * bits
+ */
pciide_pci_write(sc->sc_pc, sc->sc_tag, CMD_DMA_MODE, CMD_DMA_MULTIPLE);
WDCDEBUG_PRINT(("cmd0643_9_chip_map: timings reg now 0x%x 0x%x\n",
pci_conf_read(sc->sc_pc, sc->sc_tag, 0x54),
@@ -2475,7 +2459,8 @@ cmd0643_9_setup_channel(chp)
tim = cmd0643_9_data_tim_pio[drvp->PIO_mode];
if (drvp->drive_flags & (DRIVE_DMA | DRIVE_UDMA)) {
if (drvp->drive_flags & DRIVE_UDMA) {
- /* UltraDMA on a 0648 or 0649 */
+ /* UltraDMA on a 646U2, 0648 or 0649 */
+ drvp->drive_flags &= ~DRIVE_DMA;
udma_reg = pciide_pci_read(sc->sc_pc,
sc->sc_tag, CMD_UDMATIM(chp->channel));
if (drvp->UDMA_mode > 2 &&
@@ -2485,13 +2470,13 @@ cmd0643_9_setup_channel(chp)
drvp->UDMA_mode = 2;
if (drvp->UDMA_mode > 2)
udma_reg &= ~CMD_UDMATIM_UDMA33(drive);
- else
+ else if (sc->sc_wdcdev.UDMA_cap > 2)
udma_reg |= CMD_UDMATIM_UDMA33(drive);
udma_reg |= CMD_UDMATIM_UDMA(drive);
udma_reg &= ~(CMD_UDMATIM_TIM_MASK <<
CMD_UDMATIM_TIM_OFF(drive));
udma_reg |=
- (cmd0648_9_tim_udma[drvp->UDMA_mode] <<
+ (cmd0646_9_tim_udma[drvp->UDMA_mode] <<
CMD_UDMATIM_TIM_OFF(drive));
pciide_pci_write(sc->sc_pc, sc->sc_tag,
CMD_UDMATIM(chp->channel), udma_reg);
@@ -2500,7 +2485,7 @@ cmd0643_9_setup_channel(chp)
* use Multiword DMA.
* Timings will be used for both PIO and DMA,
* so adjust DMA mode if needed
- * if we have a 0648/9, turn off UDMA
+ * if we have a 0646U2/8/9, turn off UDMA
*/
if (sc->sc_wdcdev.cap & WDC_CAPABILITY_UDMA) {
udma_reg = pciide_pci_read(sc->sc_pc,
@@ -2555,8 +2540,7 @@ cy693_chip_map(sc, pa)
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 interface = PCI_INTERFACE(pa->pa_class);
bus_size_t cmdsize, ctlsize;
if (pciide_chipen(sc, pa) == 0)
@@ -2589,12 +2573,12 @@ cy693_chip_map(sc, pa)
sc->sc_dma_ok = 0;
}
+ 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_IRQACK;
sc->sc_wdcdev.irqack = pciide_irqack;
}
- 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;
@@ -2713,10 +2697,8 @@ sis_chip_map(sc, pa)
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));
- pcireg_t rev = PCI_REVISION(pci_conf_read(sc->sc_pc, sc->sc_tag,
- PCI_CLASS_REG));
+ pcireg_t interface = PCI_INTERFACE(pa->pa_class);
+ pcireg_t rev = PCI_REVISION(pa->pa_class);
bus_size_t cmdsize, ctlsize;
if (pciide_chipen(sc, pa) == 0)
@@ -2724,21 +2706,21 @@ sis_chip_map(sc, pa)
printf(": DMA");
pciide_mapreg_dma(sc, pa);
-
+ 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_IRQACK;
sc->sc_wdcdev.irqack = pciide_irqack;
- if (rev >= 0xd0)
+ if (rev > 0xd0)
sc->sc_wdcdev.cap |= 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;
if (sc->sc_wdcdev.cap & WDC_CAPABILITY_UDMA)
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;
@@ -2860,7 +2842,8 @@ acer_chip_map(sc, pa)
printf(": DMA");
pciide_mapreg_dma(sc, pa);
-
+ 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;
if (rev >= 0x20)
@@ -2869,8 +2852,6 @@ acer_chip_map(sc, pa)
sc->sc_wdcdev.irqack = pciide_irqack;
}
- 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;
if (sc->sc_wdcdev.cap & WDC_CAPABILITY_UDMA)
@@ -3061,7 +3042,6 @@ hpt_chip_map(sc, pa)
printf(": DMA");
pciide_mapreg_dma(sc, pa);
- printf("\n");
sc->sc_wdcdev.cap = WDC_CAPABILITY_DATA16 | WDC_CAPABILITY_DATA32 |
WDC_CAPABILITY_MODE;
if (sc->sc_dma_ok) {
@@ -3236,218 +3216,8 @@ hpt_pci_intr(arg)
return rv;
}
-/*
- * Inline functions for accessing the timing registers of the
- * OPTi controller.
- *
- * These *MUST* disable interrupts as they need atomic access to
- * certain magic registers. Failure to adhere to this *will*
- * break things in subtle ways if the wdc registers are accessed
- * by an interrupt routine while this magic sequence is executing.
- */
-static __inline__ u_int8_t
-opti_read_config(struct channel_softc *chp, int reg)
-{
- u_int8_t rv;
- int s = splhigh();
-
- /* Two consecutive 16-bit reads from register #1 (0x1f1/0x171) */
- (void) bus_space_read_2(chp->cmd_iot, chp->cmd_ioh, wdr_features);
- (void) bus_space_read_2(chp->cmd_iot, chp->cmd_ioh, wdr_features);
-
- /* Followed by an 8-bit write of 0x3 to register #2 */
- bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wdr_seccnt, 0x03u);
-
- /* Now we can read the required register */
- rv = bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, reg);
-
- /* Restore the real registers */
- bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wdr_seccnt, 0x83u);
-
- splx(s);
-
- return rv;
-}
-
-static __inline__ void
-opti_write_config(struct channel_softc *chp, int reg, u_int8_t val)
-{
- int s = splhigh();
-
- /* Two consecutive 16-bit reads from register #1 (0x1f1/0x171) */
- (void) bus_space_read_2(chp->cmd_iot, chp->cmd_ioh, wdr_features);
- (void) bus_space_read_2(chp->cmd_iot, chp->cmd_ioh, wdr_features);
-
- /* Followed by an 8-bit write of 0x3 to register #2 */
- bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wdr_seccnt, 0x03u);
-
- /* Now we can write the required register */
- bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, reg, val);
-
- /* Restore the real registers */
- bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wdr_seccnt, 0x83u);
-
- splx(s);
-}
-
-void
-opti_chip_map(sc, pa)
- struct pciide_softc *sc;
- struct pci_attach_args *pa;
-{
- struct pciide_channel *cp;
- bus_size_t cmdsize, ctlsize;
- pcireg_t interface;
- u_int8_t init_ctrl;
- int channel;
-
- if (pciide_chipen(sc, pa) == 0)
- return;
- printf(": DMA");
- pciide_mapreg_dma(sc, pa);
-
- sc->sc_wdcdev.cap |= WDC_CAPABILITY_DATA16 | WDC_CAPABILITY_MODE;
- sc->sc_wdcdev.PIO_cap = 4;
- if (sc->sc_dma_ok) {
- sc->sc_wdcdev.cap |= WDC_CAPABILITY_DMA | WDC_CAPABILITY_IRQACK;
- sc->sc_wdcdev.DMA_cap = 2;
- sc->sc_wdcdev.irqack = pciide_irqack;
- }
- sc->sc_wdcdev.set_modes = opti_setup_channel;
-
- sc->sc_wdcdev.channels = sc->wdc_chanarray;
- sc->sc_wdcdev.nchannels = PCIIDE_NUM_CHANNELS;
-
- init_ctrl = pciide_pci_read(sc->sc_pc, sc->sc_tag,
- OPTI_REG_INIT_CONTROL);
-
- 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++) {
- cp = &sc->pciide_channels[channel];
- if (pciide_chansetup(sc, channel, interface) == 0)
- continue;
- if (channel == 1 &&
- (init_ctrl & OPTI_INIT_CONTROL_CH2_DISABLE) != 0) {
- printf("%s: %s channel ignored (disabled)\n",
- sc->sc_wdcdev.sc_dev.dv_xname, cp->name);
- continue;
- }
- pciide_mapchan(pa, cp, interface, &cmdsize, &ctlsize,
- pciide_pci_intr);
- if (cp->hw_ok == 0)
- continue;
- pciide_map_compat_intr(pa, cp, channel, interface);
- if (cp->hw_ok == 0)
- continue;
- opti_setup_channel(&cp->wdc_channel);
- }
-}
-
-void
-opti_setup_channel(chp)
- struct channel_softc *chp;
-{
- struct ata_drive_datas *drvp;
- struct pciide_channel *cp = (struct pciide_channel*)chp;
- struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc;
- int drive,spd;
- int mode[2];
- u_int8_t rv, mr;
-
- /*
- * The `Delay' and `Address Setup Time' fields of the
- * Miscellaneous Register are always zero initially.
- */
- mr = opti_read_config(chp, OPTI_REG_MISC) & ~OPTI_MISC_INDEX_MASK;
- mr &= ~(OPTI_MISC_DELAY_MASK |
- OPTI_MISC_ADDR_SETUP_MASK |
- OPTI_MISC_INDEX_MASK);
-
- /* Prime the control register before setting timing values */
- opti_write_config(chp, OPTI_REG_CONTROL, OPTI_CONTROL_DISABLE);
-
- /* Determine the clockrate of the PCIbus the chip is attached to */
- spd = 2;
-
- /* setup DMA if needed */
- pciide_channel_dma_setup(cp);
-
- for (drive = 0; drive < 2; drive++) {
- drvp = &chp->ch_drive[drive];
- /* If no drive, skip */
- if ((drvp->drive_flags & DRIVE) == 0) {
- mode[drive] = -1;
- continue;
- }
-
- if ((drvp->drive_flags & DRIVE_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 + 2 > (drvp->PIO_mode))
- drvp->DMA_mode = (drvp->PIO_mode > 2) ?
- drvp->PIO_mode - 2 : 0;
- if (drvp->DMA_mode == 0)
- drvp->PIO_mode = 0;
-
- mode[drive] = drvp->DMA_mode + 5;
- } else
- mode[drive] = drvp->PIO_mode;
-
- if (drive && mode[0] >= 0 &&
- (opti_tim_as[spd][mode[0]] != opti_tim_as[spd][mode[1]])) {
- /*
- * Can't have two drives using different values
- * for `Address Setup Time'.
- * Slow down the faster drive to compensate.
- */
- int d = (opti_tim_as[spd][mode[0]] >
- opti_tim_as[spd][mode[1]]) ? 0 : 1;
-
- mode[d] = mode[1-d];
- chp->ch_drive[d].PIO_mode = chp->ch_drive[1-d].PIO_mode;
- chp->ch_drive[d].DMA_mode = 0;
- chp->ch_drive[d].drive_flags &= DRIVE_DMA;
- }
- }
-
- for (drive = 0; drive < 2; drive++) {
- int m;
- if ((m = mode[drive]) < 0)
- continue;
-
- /* Set the Address Setup Time and select appropriate index */
- rv = opti_tim_as[spd][m] << OPTI_MISC_ADDR_SETUP_SHIFT;
- rv |= OPTI_MISC_INDEX(drive);
- opti_write_config(chp, OPTI_REG_MISC, mr | rv);
-
- /* Set the pulse width and recovery timing parameters */
- rv = opti_tim_cp[spd][m] << OPTI_PULSE_WIDTH_SHIFT;
- rv |= opti_tim_rt[spd][m] << OPTI_RECOVERY_TIME_SHIFT;
- opti_write_config(chp, OPTI_REG_READ_CYCLE_TIMING, rv);
- opti_write_config(chp, OPTI_REG_WRITE_CYCLE_TIMING, rv);
-
- /* Set the Enhanced Mode register appropriately */
- rv = pciide_pci_read(sc->sc_pc, sc->sc_tag, OPTI_REG_ENH_MODE);
- rv &= ~OPTI_ENH_MODE_MASK(chp->channel, drive);
- rv |= OPTI_ENH_MODE(chp->channel, drive, opti_tim_em[m]);
- pciide_pci_write(sc->sc_pc, sc->sc_tag, OPTI_REG_ENH_MODE, rv);
- }
-
- /* Finally, enable the timings */
- opti_write_config(chp, OPTI_REG_CONTROL, OPTI_CONTROL_ENABLE);
- pciide_print_modes(cp);
-}
-
-/* A macro to test product */
+/* Macros to test product */
#define PDC_IS_262(sc) \
((sc)->sc_pp->ide_product == PCI_PRODUCT_PROMISE_PDC20262 || \
(sc)->sc_pp->ide_product == PCI_PRODUCT_PROMISE_PDC20265 || \
@@ -3661,6 +3431,8 @@ pdc202xx_setup_channel(chp)
continue;
mode = 0;
if (drvp->drive_flags & DRIVE_UDMA) {
+ /* use Ultra/DMA */
+ drvp->drive_flags &= ~DRIVE_DMA;
mode = PDC2xx_TIM_SET_MB(mode,
pdc2xx_udma_mb[drvp->UDMA_mode]);
mode = PDC2xx_TIM_SET_MC(mode,
@@ -3748,10 +3520,7 @@ pdc20265_pci_intr(arg)
for (i = 0; i < sc->sc_wdcdev.nchannels; i++) {
cp = &sc->pciide_channels[i];
wdc_cp = &cp->wdc_channel;
- /*
- * If a compat channel, skip. This may
- * never be the case on a PDC2026x ??
- */
+ /* If a compat channel skip. */
if (cp->compat)
continue;
/*
@@ -3773,3 +3542,215 @@ pdc20265_pci_intr(arg)
}
return rv;
}
+
+/*
+ * Inline functions for accessing the timing registers of the
+ * OPTi controller.
+ *
+ * These *MUST* disable interrupts as they need atomic access to
+ * certain magic registers. Failure to adhere to this *will*
+ * break things in subtle ways if the wdc registers are accessed
+ * by an interrupt routine while this magic sequence is executing.
+ */
+static __inline__ u_int8_t
+opti_read_config(struct channel_softc *chp, int reg)
+{
+ u_int8_t rv;
+ int s = splhigh();
+
+ /* Two consecutive 16-bit reads from register #1 (0x1f1/0x171) */
+ (void) bus_space_read_2(chp->cmd_iot, chp->cmd_ioh, wdr_features);
+ (void) bus_space_read_2(chp->cmd_iot, chp->cmd_ioh, wdr_features);
+
+ /* Followed by an 8-bit write of 0x3 to register #2 */
+ bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wdr_seccnt, 0x03u);
+
+ /* Now we can read the required register */
+ rv = bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, reg);
+
+ /* Restore the real registers */
+ bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wdr_seccnt, 0x83u);
+
+ splx(s);
+
+ return rv;
+}
+
+static __inline__ void
+opti_write_config(struct channel_softc *chp, int reg, u_int8_t val)
+{
+ int s = splhigh();
+
+ /* Two consecutive 16-bit reads from register #1 (0x1f1/0x171) */
+ (void) bus_space_read_2(chp->cmd_iot, chp->cmd_ioh, wdr_features);
+ (void) bus_space_read_2(chp->cmd_iot, chp->cmd_ioh, wdr_features);
+
+ /* Followed by an 8-bit write of 0x3 to register #2 */
+ bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wdr_seccnt, 0x03u);
+
+ /* Now we can write the required register */
+ bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, reg, val);
+
+ /* Restore the real registers */
+ bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wdr_seccnt, 0x83u);
+
+ splx(s);
+}
+
+void
+opti_chip_map(sc, pa)
+ struct pciide_softc *sc;
+ struct pci_attach_args *pa;
+{
+ struct pciide_channel *cp;
+ bus_size_t cmdsize, ctlsize;
+ pcireg_t interface;
+ u_int8_t init_ctrl;
+ int channel;
+
+ if (pciide_chipen(sc, pa) == 0)
+ return;
+ printf(": DMA");
+ pciide_mapreg_dma(sc, pa);
+
+ sc->sc_wdcdev.cap = WDC_CAPABILITY_DATA16 | WDC_CAPABILITY_DATA32 |
+ WDC_CAPABILITY_MODE;
+ sc->sc_wdcdev.PIO_cap = 4;
+ if (sc->sc_dma_ok) {
+ sc->sc_wdcdev.cap |= WDC_CAPABILITY_DMA | WDC_CAPABILITY_IRQACK;
+ sc->sc_wdcdev.irqack = pciide_irqack;
+ sc->sc_wdcdev.DMA_cap = 2;
+ }
+ sc->sc_wdcdev.set_modes = opti_setup_channel;
+
+ sc->sc_wdcdev.channels = sc->wdc_chanarray;
+ sc->sc_wdcdev.nchannels = PCIIDE_NUM_CHANNELS;
+
+ init_ctrl = pciide_pci_read(sc->sc_pc, sc->sc_tag,
+ OPTI_REG_INIT_CONTROL);
+
+ interface = PCI_INTERFACE(pa->pa_class);
+
+ 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 (channel == 1 &&
+ (init_ctrl & OPTI_INIT_CONTROL_CH2_DISABLE) != 0) {
+ printf("%s: %s channel ignored (disabled)\n",
+ sc->sc_wdcdev.sc_dev.dv_xname, cp->name);
+ continue;
+ }
+ pciide_mapchan(pa, cp, interface, &cmdsize, &ctlsize,
+ pciide_pci_intr);
+ if (cp->hw_ok == 0)
+ continue;
+ pciide_map_compat_intr(pa, cp, channel, interface);
+ if (cp->hw_ok == 0)
+ continue;
+ opti_setup_channel(&cp->wdc_channel);
+ }
+}
+
+void
+opti_setup_channel(chp)
+ struct channel_softc *chp;
+{
+ struct ata_drive_datas *drvp;
+ struct pciide_channel *cp = (struct pciide_channel*)chp;
+ struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc;
+ int drive,spd;
+ int mode[2];
+ u_int8_t rv, mr;
+
+ /*
+ * The `Delay' and `Address Setup Time' fields of the
+ * Miscellaneous Register are always zero initially.
+ */
+ mr = opti_read_config(chp, OPTI_REG_MISC) & ~OPTI_MISC_INDEX_MASK;
+ mr &= ~(OPTI_MISC_DELAY_MASK |
+ OPTI_MISC_ADDR_SETUP_MASK |
+ OPTI_MISC_INDEX_MASK);
+
+ /* Prime the control register before setting timing values */
+ opti_write_config(chp, OPTI_REG_CONTROL, OPTI_CONTROL_DISABLE);
+
+ /* Determine the clockrate of the PCIbus the chip is attached to */
+ spd = (int) opti_read_config(chp, OPTI_REG_STRAP);
+ spd &= OPTI_STRAP_PCI_SPEED_MASK;
+
+ /* setup DMA if needed */
+ pciide_channel_dma_setup(cp);
+
+ for (drive = 0; drive < 2; drive++) {
+ drvp = &chp->ch_drive[drive];
+ /* If no drive, skip */
+ if ((drvp->drive_flags & DRIVE) == 0) {
+ mode[drive] = -1;
+ continue;
+ }
+
+ if ((drvp->drive_flags & DRIVE_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 + 2 > (drvp->PIO_mode))
+ drvp->DMA_mode = (drvp->PIO_mode > 2) ?
+ drvp->PIO_mode - 2 : 0;
+ if (drvp->DMA_mode == 0)
+ drvp->PIO_mode = 0;
+
+ mode[drive] = drvp->DMA_mode + 5;
+ } else
+ mode[drive] = drvp->PIO_mode;
+
+ if (drive && mode[0] >= 0 &&
+ (opti_tim_as[spd][mode[0]] != opti_tim_as[spd][mode[1]])) {
+ /*
+ * Can't have two drives using different values
+ * for `Address Setup Time'.
+ * Slow down the faster drive to compensate.
+ */
+ int d = (opti_tim_as[spd][mode[0]] >
+ opti_tim_as[spd][mode[1]]) ? 0 : 1;
+
+ mode[d] = mode[1-d];
+ chp->ch_drive[d].PIO_mode = chp->ch_drive[1-d].PIO_mode;
+ chp->ch_drive[d].DMA_mode = 0;
+ chp->ch_drive[d].drive_flags &= DRIVE_DMA;
+ }
+ }
+
+ for (drive = 0; drive < 2; drive++) {
+ int m;
+ if ((m = mode[drive]) < 0)
+ continue;
+
+ /* Set the Address Setup Time and select appropriate index */
+ rv = opti_tim_as[spd][m] << OPTI_MISC_ADDR_SETUP_SHIFT;
+ rv |= OPTI_MISC_INDEX(drive);
+ opti_write_config(chp, OPTI_REG_MISC, mr | rv);
+
+ /* Set the pulse width and recovery timing parameters */
+ rv = opti_tim_cp[spd][m] << OPTI_PULSE_WIDTH_SHIFT;
+ rv |= opti_tim_rt[spd][m] << OPTI_RECOVERY_TIME_SHIFT;
+ opti_write_config(chp, OPTI_REG_READ_CYCLE_TIMING, rv);
+ opti_write_config(chp, OPTI_REG_WRITE_CYCLE_TIMING, rv);
+
+ /* Set the Enhanced Mode register appropriately */
+ rv = pciide_pci_read(sc->sc_pc, sc->sc_tag, OPTI_REG_ENH_MODE);
+ rv &= ~OPTI_ENH_MODE_MASK(chp->channel, drive);
+ rv |= OPTI_ENH_MODE(chp->channel, drive, opti_tim_em[m]);
+ pciide_pci_write(sc->sc_pc, sc->sc_tag, OPTI_REG_ENH_MODE, rv);
+ }
+
+ /* Finally, enable the timings */
+ opti_write_config(chp, OPTI_REG_CONTROL, OPTI_CONTROL_ENABLE);
+
+ pciide_print_modes(cp);
+}