Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/dev Add an optionnal controller callback for channel res...
details: https://anonhg.NetBSD.org/src/rev/0bca2edd899f
branches: trunk
changeset: 583434:0bca2edd899f
user: bouyer <bouyer%NetBSD.org@localhost>
date: Sat Aug 06 22:07:24 2005 +0000
description:
Add an optionnal controller callback for channel reset. If the callback
is set to NULL, use the generic reset code.
Use this to work around a bug in some Acer IDE controllers (like the
one found in some sparc systems) where a controller disable/enable
is required after a reset to avoid data corruption when Ultra-DMA is
used. Workaround from opensolaris, thanks to Hiroki Sato for testing.
diffstat:
sys/dev/ic/wdc.c | 72 +++++++++++++++++++++---------------------
sys/dev/ic/wdcvar.h | 6 ++-
sys/dev/pci/aceride.c | 61 ++++++++++++++++++++++++++++++++++-
sys/dev/pci/pciide_acer_reg.h | 6 ++-
4 files changed, 104 insertions(+), 41 deletions(-)
diffs (282 lines):
diff -r 7ebb1ef33f1c -r 0bca2edd899f sys/dev/ic/wdc.c
--- a/sys/dev/ic/wdc.c Sat Aug 06 17:58:13 2005 +0000
+++ b/sys/dev/ic/wdc.c Sat Aug 06 22:07:24 2005 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: wdc.c,v 1.224 2005/06/19 18:14:27 bouyer Exp $ */
+/* $NetBSD: wdc.c,v 1.225 2005/08/06 22:07:24 bouyer Exp $ */
/*
* Copyright (c) 1998, 2001, 2003 Manuel Bouyer. All rights reserved.
@@ -70,7 +70,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: wdc.c,v 1.224 2005/06/19 18:14:27 bouyer Exp $");
+__KERNEL_RCSID(0, "$NetBSD: wdc.c,v 1.225 2005/08/06 22:07:24 bouyer Exp $");
#ifndef ATADEBUG
#define ATADEBUG
@@ -613,23 +613,10 @@
delay(5000);
#endif
- if (wdc->select)
- wdc->select(chp,0);
- bus_space_write_1(wdr->cmd_iot, wdr->cmd_iohs[wd_sdh], 0, WDSD_IBM);
- delay(10); /* 400ns delay */
- /* assert SRST, wait for reset to complete */
- bus_space_write_1(wdr->ctl_iot, wdr->ctl_ioh, wd_aux_ctlr,
- WDCTL_RST | WDCTL_IDS | WDCTL_4BIT);
- DELAY(1000);
- bus_space_write_1(wdr->ctl_iot, wdr->ctl_ioh, wd_aux_ctlr,
- WDCTL_IDS | WDCTL_4BIT);
+ wdc->reset(chp, RESET_POLL);
DELAY(2000);
(void) bus_space_read_1(wdr->cmd_iot, wdr->cmd_iohs[wd_error], 0);
bus_space_write_1(wdr->ctl_iot, wdr->ctl_ioh, wd_aux_ctlr, WDCTL_4BIT);
- delay(10); /* 400ns delay */
- /* ACK interrupt in case there is one pending left (Promise ATA100) */
- if (wdc->irqack != NULL)
- wdc->irqack(chp);
splx(s);
ret_value = __wdcwait_reset(chp, ret_value, poll);
@@ -703,6 +690,9 @@
wdc->datain_pio = wdc_datain_pio;
if (wdc->dataout_pio == NULL)
wdc->dataout_pio = wdc_dataout_pio;
+ /* default reset method */
+ if (wdc->reset == NULL)
+ wdc->reset = wdc_do_reset;
/* initialise global data */
if (atac->atac_bustype_ata == NULL)
@@ -948,27 +938,8 @@
struct wdc_softc *wdc = CHAN_TO_WDC(chp);
struct wdc_regs *wdr = &wdc->regs[chp->ch_channel];
int drv_mask1, drv_mask2;
- int s = 0;
- if (wdc->select)
- wdc->select(chp,0);
- if (poll != RESET_SLEEP)
- s = splbio();
- /* master */
- bus_space_write_1(wdr->cmd_iot, wdr->cmd_iohs[wd_sdh], 0, WDSD_IBM);
- delay(10); /* 400ns delay */
- bus_space_write_1(wdr->ctl_iot, wdr->ctl_ioh, wd_aux_ctlr,
- WDCTL_RST | WDCTL_IDS | WDCTL_4BIT);
- delay(2000);
- (void) bus_space_read_1(wdr->cmd_iot, wdr->cmd_iohs[wd_error], 0);
- bus_space_write_1(wdr->ctl_iot, wdr->ctl_ioh, wd_aux_ctlr,
- WDCTL_4BIT | WDCTL_IDS);
- delay(10); /* 400ns delay */
- if (poll != RESET_SLEEP) {
- if (wdc->irqack)
- wdc->irqack(chp);
- splx(s);
- }
+ wdc->reset(chp, poll);
drv_mask1 = (chp->ch_drive[0].drive_flags & DRIVE) ? 0x01:0x00;
drv_mask1 |= (chp->ch_drive[1].drive_flags & DRIVE) ? 0x02:0x00;
@@ -987,6 +958,35 @@
return (drv_mask1 != drv_mask2) ? 1 : 0;
}
+void
+wdc_do_reset(struct ata_channel *chp, int poll)
+{
+ struct wdc_softc *wdc = CHAN_TO_WDC(chp);
+ struct wdc_regs *wdr = &wdc->regs[chp->ch_channel];
+ int s = 0;
+
+ if (poll != RESET_SLEEP)
+ s = splbio();
+ if (wdc->select)
+ wdc->select(chp,0);
+ /* master */
+ bus_space_write_1(wdr->cmd_iot, wdr->cmd_iohs[wd_sdh], 0, WDSD_IBM);
+ delay(10); /* 400ns delay */
+ /* assert SRST, wait for reset to complete */
+ bus_space_write_1(wdr->ctl_iot, wdr->ctl_ioh, wd_aux_ctlr,
+ WDCTL_RST | WDCTL_IDS | WDCTL_4BIT);
+ delay(2000);
+ (void) bus_space_read_1(wdr->cmd_iot, wdr->cmd_iohs[wd_error], 0);
+ bus_space_write_1(wdr->ctl_iot, wdr->ctl_ioh, wd_aux_ctlr,
+ WDCTL_4BIT | WDCTL_IDS);
+ delay(10); /* 400ns delay */
+ if (poll != RESET_SLEEP) {
+ if (wdc->irqack)
+ wdc->irqack(chp);
+ splx(s);
+ }
+}
+
static int
__wdcwait_reset(struct ata_channel *chp, int drv_mask, int poll)
{
diff -r 7ebb1ef33f1c -r 0bca2edd899f sys/dev/ic/wdcvar.h
--- a/sys/dev/ic/wdcvar.h Sat Aug 06 17:58:13 2005 +0000
+++ b/sys/dev/ic/wdcvar.h Sat Aug 06 22:07:24 2005 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: wdcvar.h,v 1.82 2005/03/02 12:25:28 mycroft Exp $ */
+/* $NetBSD: wdcvar.h,v 1.83 2005/08/06 22:07:24 bouyer Exp $ */
/*-
* Copyright (c) 1998, 2003, 2004 The NetBSD Foundation, Inc.
@@ -101,6 +101,9 @@
/* Optional callback to ack IRQ. */
void (*irqack)(struct ata_channel *);
+ /* Optional callback to perform a bus reset */
+ void (*reset)(struct ata_channel *, int);
+
/* overridden if the backend has a different data transfer method */
void (*datain_pio)(struct ata_channel *, int, void *, size_t);
void (*dataout_pio)(struct ata_channel *, int, void *, size_t);
@@ -144,6 +147,7 @@
void wdctimeout(void *arg);
void wdc_reset_drive(struct ata_drive_datas *, int);
void wdc_reset_channel(struct ata_channel *, int);
+void wdc_do_reset(struct ata_channel *, int);
int wdc_exec_command(struct ata_drive_datas *, struct ata_command*);
diff -r 7ebb1ef33f1c -r 0bca2edd899f sys/dev/pci/aceride.c
--- a/sys/dev/pci/aceride.c Sat Aug 06 17:58:13 2005 +0000
+++ b/sys/dev/pci/aceride.c Sat Aug 06 22:07:24 2005 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: aceride.c,v 1.15 2005/05/24 05:25:15 lukem Exp $ */
+/* $NetBSD: aceride.c,v 1.16 2005/08/06 22:07:24 bouyer Exp $ */
/*
* Copyright (c) 1999, 2000, 2001 Manuel Bouyer.
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: aceride.c,v 1.15 2005/05/24 05:25:15 lukem Exp $");
+__KERNEL_RCSID(0, "$NetBSD: aceride.c,v 1.16 2005/08/06 22:07:24 bouyer Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -41,6 +41,8 @@
#include <dev/pci/pciidevar.h>
#include <dev/pci/pciide_acer_reg.h>
+static int acer_pcib_match(struct pci_attach_args *);
+static void acer_do_reset(struct ata_channel *, int);
static void acer_chip_map(struct pciide_softc*, struct pci_attach_args*);
static void acer_setup_channel(struct ata_channel*);
static int acer_pci_intr(void *);
@@ -48,7 +50,12 @@
static int aceride_match(struct device *, struct cfdata *, void *);
static void aceride_attach(struct device *, struct device *, void *);
-CFATTACH_DECL(aceride, sizeof(struct pciide_softc),
+struct aceride_softc {
+ struct pciide_softc pciide_sc;
+ struct pci_attach_args pcib_pa;
+};
+
+CFATTACH_DECL(aceride, sizeof(struct aceride_softc),
aceride_match, aceride_attach, NULL, NULL);
static const struct pciide_product_desc pciide_acer_products[] = {
@@ -89,6 +96,21 @@
}
+static int
+acer_pcib_match(struct pci_attach_args *pa)
+{
+ /*
+ * we need to access the PCI config space of the pcib, see
+ * acer_do_reset()
+ */
+ if (PCI_CLASS(pa->pa_class) == PCI_CLASS_BRIDGE &&
+ PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_BRIDGE_ISA &&
+ PCI_VENDOR(pa->pa_id) == PCI_VENDOR_ALI &&
+ PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_ALI_M1543)
+ return 1;
+ return 0;
+}
+
static void
acer_chip_map(struct pciide_softc *sc, struct pci_attach_args *pa)
{
@@ -97,6 +119,7 @@
pcireg_t cr, interface;
bus_size_t cmdsize, ctlsize;
pcireg_t rev = PCI_REVISION(pa->pa_class);
+ struct aceride_softc *acer_sc = (struct aceride_softc *)sc;
if (pciide_chipen(sc, pa) == 0)
return;
@@ -154,6 +177,14 @@
}
wdc_allocate_regs(&sc->sc_wdcdev);
+ if (rev == 0xC3) {
+ /* install reset bug workaround */
+ if (pci_find_device(&acer_sc->pcib_pa, acer_pcib_match) == 0) {
+ printf("%s: WARNING: can't find pci-isa bridge\n",
+ sc->sc_wdcdev.sc_atac.atac_dev.dv_xname);
+ } else
+ sc->sc_wdcdev.reset = acer_do_reset;
+ }
for (channel = 0; channel < sc->sc_wdcdev.sc_atac.atac_nchannels;
channel++) {
@@ -173,6 +204,30 @@
}
static void
+acer_do_reset(struct ata_channel *chp, int poll)
+{
+ struct pciide_softc *sc = CHAN_TO_PCIIDE(chp);
+ struct aceride_softc *acer_sc = (struct aceride_softc *)sc;
+ u_int8_t reg;
+
+ /*
+ * From OpenSolaris: after a reset we need to disable/enable the
+ * corresponding channel, or data corruption will occur in
+ * UltraDMA modes
+ */
+
+ wdc_do_reset(chp, poll);
+ reg = pciide_pci_read(acer_sc->pcib_pa.pa_pc, acer_sc->pcib_pa.pa_tag,
+ ACER_PCIB_CTRL);
+ printf("acer_do_reset reg 0x%x\n", reg);
+ pciide_pci_write(acer_sc->pcib_pa.pa_pc, acer_sc->pcib_pa.pa_tag,
+ ACER_PCIB_CTRL, reg & ACER_PCIB_CTRL_ENCHAN(chp->ch_channel));
+ delay(1000);
+ pciide_pci_write(acer_sc->pcib_pa.pa_pc, acer_sc->pcib_pa.pa_tag,
+ ACER_PCIB_CTRL, reg);
+}
+
+static void
acer_setup_channel(struct ata_channel *chp)
{
struct ata_drive_datas *drvp;
diff -r 7ebb1ef33f1c -r 0bca2edd899f sys/dev/pci/pciide_acer_reg.h
--- a/sys/dev/pci/pciide_acer_reg.h Sat Aug 06 17:58:13 2005 +0000
+++ b/sys/dev/pci/pciide_acer_reg.h Sat Aug 06 22:07:24 2005 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: pciide_acer_reg.h,v 1.8 2005/02/27 00:27:33 perry Exp $ */
+/* $NetBSD: pciide_acer_reg.h,v 1.9 2005/08/06 22:07:24 bouyer Exp $ */
/*
* Copyright (c) 1999 Manuel Bouyer.
@@ -90,6 +90,10 @@
#define ACER_0x79_REVC2_EN 0x4
#define ACER_0x79_EN 0x2
+/* OpenSolaris: channel enable/disable in the PCI-ISA bridge */
+#define ACER_PCIB_CTRL 0x58
+#define ACER_PCIB_CTRL_ENCHAN(chan) (0x4 << (chan))
+
/*
* IDE bus frequency (1 byte)
* This should be setup by the BIOS - can we rely on this ?
- Prev by Date:
[src/trunk]: src/doc Update gcc, xfree86, and zlib.
- Next by Date:
[src/trunk]: src/usr.bin/netstat Use sysctl to fetch IP, ICMP, TCP, and UDP s...
- Previous by Thread:
[src/trunk]: src/doc Update gcc, xfree86, and zlib.
- Next by Thread:
[src/trunk]: src/usr.bin/netstat Use sysctl to fetch IP, ICMP, TCP, and UDP s...
- Indexes:
Home |
Main Index |
Thread Index |
Old Index