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.
This commit is contained in:
parent
c1494c99c6
commit
d1278fcba8
|
@ -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 @@ wdcprobe1(struct ata_channel *chp, int poll)
|
|||
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 @@ wdcattach(struct ata_channel *chp)
|
|||
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 @@ wdcreset(struct ata_channel *chp, int poll)
|
|||
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 @@ wdcreset(struct ata_channel *chp, int poll)
|
|||
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)
|
||||
{
|
||||
|
|
|
@ -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 @@ struct wdc_softc {
|
|||
/* 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 wdccommandshort(struct ata_channel *, int, int);
|
|||
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*);
|
||||
|
||||
|
|
|
@ -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 @@ __KERNEL_RCSID(0, "$NetBSD: aceride.c,v 1.15 2005/05/24 05:25:15 lukem Exp $");
|
|||
#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 acer_pci_intr(void *);
|
|||
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 @@ aceride_attach(struct device *parent, struct device *self, void *aux)
|
|||
|
||||
}
|
||||
|
||||
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 @@ acer_chip_map(struct pciide_softc *sc, struct pci_attach_args *pa)
|
|||
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 @@ acer_chip_map(struct pciide_softc *sc, struct pci_attach_args *pa)
|
|||
}
|
||||
|
||||
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++) {
|
||||
|
@ -172,6 +203,30 @@ acer_chip_map(struct pciide_softc *sc, struct pci_attach_args *pa)
|
|||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
|
|
@ -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 ?
|
||||
|
|
Loading…
Reference in New Issue