Upgrade of EIDE DMA support, Johns comments:
* lots of fixes to error handling-- mostly works now * improve DMA timing config for Triton chipsets-- PIIX4 and UDMA drive still untested * generally improve DMA config in many ways-- mostly cleanup * clean up boot-time messages * rewrite PRD generation algorithm * first wd timeout is now longer, to handle drive spinup Submitted by: John Hood <cgull@smoke.marlboro.vt.us>
This commit is contained in:
parent
fb633824a1
commit
4d6dd4fc2d
@ -24,7 +24,7 @@
|
||||
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
.\"
|
||||
.\" $Id: wd.4,v 1.5 1997/03/07 02:50:00 jmg Exp $
|
||||
.\" $Id: wd.4,v 1.6 1997/07/15 09:44:05 charnier Exp $
|
||||
.\"
|
||||
.Dd August 31, 1994
|
||||
.Dt WD 4 i386
|
||||
@ -61,6 +61,9 @@ Test and use the 32bit transfer capability of the drive.
|
||||
.It 0x4000
|
||||
If drive looks like it's comming out of sleep mode, assume it's
|
||||
confused and reinitialize it.
|
||||
.It 0x2000
|
||||
Probe for and use the bus-mastering DMA capabilities of modern
|
||||
PCI chipsets.
|
||||
.It 0x0f00
|
||||
Force number of heads to ((flags & 0xf00)>>8), recalculate number
|
||||
of cylinders to match.
|
||||
|
@ -2,7 +2,7 @@
|
||||
# LINT -- config file for checking all the sources, tries to pull in
|
||||
# as much of the source tree as it can.
|
||||
#
|
||||
# $Id: LINT,v 1.359 1997/08/28 12:18:07 jkh Exp $
|
||||
# $Id: LINT,v 1.360 1997/08/28 15:00:05 jlemon Exp $
|
||||
#
|
||||
# NB: You probably don't want to try running a kernel built from this
|
||||
# file. Instead, you should start from GENERIC, and add options from
|
||||
@ -724,8 +724,6 @@ controller wds0 at isa? port 0x350 bio irq 15 drq 6 vector wdsintr
|
||||
#
|
||||
# ST-506, ESDI, and IDE hard disks: `wdc' and `wd'
|
||||
#
|
||||
# NB: ``Enhanced IDE'' is NOT supported at this time.
|
||||
#
|
||||
# The flags fields are used to enable the multi-sector I/O and
|
||||
# the 32BIT I/O modes. The flags may be used in either the controller
|
||||
# definition or in the individual disk definitions. The controller
|
||||
@ -735,7 +733,10 @@ controller wds0 at isa? port 0x350 bio irq 15 drq 6 vector wdsintr
|
||||
# The low 8 bits are the maximum value for the multi-sector I/O,
|
||||
# where 0xff defaults to the maximum that the drive can handle.
|
||||
# The high bit of the 16 bit flags (0x8000) allows probing for
|
||||
# 32 bit transfers.
|
||||
# 32 bit transfers. Bit 14 (0x4000) enables a hack to wake
|
||||
# up powered-down laptop drives. Bit 13 (0x2000) allows
|
||||
# probing for PCI IDE DMA controllers, such as Intel's PIIX
|
||||
# south bridges. See the wd.4 man page.
|
||||
#
|
||||
# The flags field for the drives can be specified in the controller
|
||||
# specification with the low 16 bits for drive 0, and the high 16 bits
|
||||
|
@ -2,7 +2,7 @@
|
||||
# LINT -- config file for checking all the sources, tries to pull in
|
||||
# as much of the source tree as it can.
|
||||
#
|
||||
# $Id: LINT,v 1.359 1997/08/28 12:18:07 jkh Exp $
|
||||
# $Id: LINT,v 1.360 1997/08/28 15:00:05 jlemon Exp $
|
||||
#
|
||||
# NB: You probably don't want to try running a kernel built from this
|
||||
# file. Instead, you should start from GENERIC, and add options from
|
||||
@ -724,8 +724,6 @@ controller wds0 at isa? port 0x350 bio irq 15 drq 6 vector wdsintr
|
||||
#
|
||||
# ST-506, ESDI, and IDE hard disks: `wdc' and `wd'
|
||||
#
|
||||
# NB: ``Enhanced IDE'' is NOT supported at this time.
|
||||
#
|
||||
# The flags fields are used to enable the multi-sector I/O and
|
||||
# the 32BIT I/O modes. The flags may be used in either the controller
|
||||
# definition or in the individual disk definitions. The controller
|
||||
@ -735,7 +733,10 @@ controller wds0 at isa? port 0x350 bio irq 15 drq 6 vector wdsintr
|
||||
# The low 8 bits are the maximum value for the multi-sector I/O,
|
||||
# where 0xff defaults to the maximum that the drive can handle.
|
||||
# The high bit of the 16 bit flags (0x8000) allows probing for
|
||||
# 32 bit transfers.
|
||||
# 32 bit transfers. Bit 14 (0x4000) enables a hack to wake
|
||||
# up powered-down laptop drives. Bit 13 (0x2000) allows
|
||||
# probing for PCI IDE DMA controllers, such as Intel's PIIX
|
||||
# south bridges. See the wd.4 man page.
|
||||
#
|
||||
# The flags field for the drives can be specified in the controller
|
||||
# specification with the low 16 bits for drive 0, and the high 16 bits
|
||||
|
@ -2,7 +2,7 @@
|
||||
# LINT -- config file for checking all the sources, tries to pull in
|
||||
# as much of the source tree as it can.
|
||||
#
|
||||
# $Id: LINT,v 1.359 1997/08/28 12:18:07 jkh Exp $
|
||||
# $Id: LINT,v 1.360 1997/08/28 15:00:05 jlemon Exp $
|
||||
#
|
||||
# NB: You probably don't want to try running a kernel built from this
|
||||
# file. Instead, you should start from GENERIC, and add options from
|
||||
@ -724,8 +724,6 @@ controller wds0 at isa? port 0x350 bio irq 15 drq 6 vector wdsintr
|
||||
#
|
||||
# ST-506, ESDI, and IDE hard disks: `wdc' and `wd'
|
||||
#
|
||||
# NB: ``Enhanced IDE'' is NOT supported at this time.
|
||||
#
|
||||
# The flags fields are used to enable the multi-sector I/O and
|
||||
# the 32BIT I/O modes. The flags may be used in either the controller
|
||||
# definition or in the individual disk definitions. The controller
|
||||
@ -735,7 +733,10 @@ controller wds0 at isa? port 0x350 bio irq 15 drq 6 vector wdsintr
|
||||
# The low 8 bits are the maximum value for the multi-sector I/O,
|
||||
# where 0xff defaults to the maximum that the drive can handle.
|
||||
# The high bit of the 16 bit flags (0x8000) allows probing for
|
||||
# 32 bit transfers.
|
||||
# 32 bit transfers. Bit 14 (0x4000) enables a hack to wake
|
||||
# up powered-down laptop drives. Bit 13 (0x2000) allows
|
||||
# probing for PCI IDE DMA controllers, such as Intel's PIIX
|
||||
# south bridges. See the wd.4 man page.
|
||||
#
|
||||
# The flags field for the drives can be specified in the controller
|
||||
# specification with the low 16 bits for drive 0, and the high 16 bits
|
||||
|
@ -34,7 +34,7 @@
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* from: @(#)wd.c 7.2 (Berkeley) 5/9/91
|
||||
* $Id: wd.c,v 1.134 1997/08/04 05:26:49 dyson Exp $
|
||||
* $Id: wd.c,v 1.135 1997/08/09 01:44:25 julian Exp $
|
||||
*/
|
||||
|
||||
/* TODO:
|
||||
@ -193,7 +193,6 @@ static int wdtest = 0;
|
||||
static struct disk *wddrives[NWD]; /* table of units */
|
||||
static struct buf_queue_head drive_queue[NWD]; /* head of queue per drive */
|
||||
static struct {
|
||||
int b_errcnt;
|
||||
int b_active;
|
||||
} wdutab[NWD];
|
||||
/*
|
||||
@ -818,8 +817,13 @@ wdstart(int ctrlr)
|
||||
head = (blknum % secpercyl) / secpertrk;
|
||||
sector = blknum % secpertrk;
|
||||
|
||||
/*
|
||||
* XXX this looks like an attempt to skip bad sectors
|
||||
* on write.
|
||||
*/
|
||||
if (wdtab[ctrlr].b_errcnt && (bp->b_flags & B_READ) == 0)
|
||||
du->dk_bc += DEV_BSIZE;
|
||||
|
||||
count = howmany( du->dk_bc, DEV_BSIZE);
|
||||
|
||||
du->dk_flags &= ~DKFL_MULTI;
|
||||
@ -914,6 +918,9 @@ wdstart(int ctrlr)
|
||||
* unmarked bad blocks can take 3 seconds! Then it is not good that
|
||||
* we retry 5 times.
|
||||
*
|
||||
* On the first try, we give it 10 seconds, for drives that may need
|
||||
* to spin up.
|
||||
*
|
||||
* XXX wdtimeout() doesn't increment the error count so we may loop
|
||||
* forever. More seriously, the loop isn't forever but causes a
|
||||
* crash.
|
||||
@ -923,7 +930,10 @@ wdstart(int ctrlr)
|
||||
* think). Discarding them would be OK if the (special) file offset
|
||||
* was not advanced.
|
||||
*/
|
||||
du->dk_timeout = 1 + 3;
|
||||
if (wdtab[ctrlr].b_errcnt == 0)
|
||||
du->dk_timeout = 1 + 10;
|
||||
else
|
||||
du->dk_timeout = 1 + 3;
|
||||
|
||||
/* if this is a DMA op, start DMA and go away until it's done. */
|
||||
if ((du->dk_flags & (DKFL_DMA|DKFL_SINGLE)) == DKFL_DMA) {
|
||||
@ -985,11 +995,13 @@ wdstart(int ctrlr)
|
||||
* the next request. Also check for a partially done transfer, and
|
||||
* continue with the next chunk if so.
|
||||
*/
|
||||
|
||||
void
|
||||
wdintr(int unit)
|
||||
{
|
||||
register struct disk *du;
|
||||
register struct buf *bp;
|
||||
int dmastat;
|
||||
|
||||
#ifdef CMD640
|
||||
int ctrlr_atapi;
|
||||
@ -1033,20 +1045,19 @@ wdintr(int unit)
|
||||
#endif
|
||||
bp = wdtab[unit].controller_queue.tqh_first;
|
||||
du = wddrives[dkunit(bp->b_dev)];
|
||||
du->dk_timeout = 0;
|
||||
|
||||
/* finish off DMA. ignore errors if we're not using it. */
|
||||
/* finish off DMA */
|
||||
if (du->dk_flags & (DKFL_DMA|DKFL_USEDMA)) {
|
||||
if ((wddma.wdd_dmastatus(du->dk_dmacookie) & WDDS_INTERRUPT) == 0)
|
||||
/* XXX SMP boxes sometimes generate an early intr. Why? */
|
||||
if ((wddma.wdd_dmastatus(du->dk_dmacookie) & WDDS_INTERRUPT)
|
||||
== 0)
|
||||
return;
|
||||
|
||||
if ((wddma.wdd_dmadone(du->dk_dmacookie) != WDDS_INTERRUPT) &&
|
||||
!(du->dk_flags & DKFL_USEDMA)) {
|
||||
wderror(bp, du, "wdintr: DMA failure");
|
||||
du->dk_status |= WDCS_ERR; /* XXX totally bogus err */
|
||||
}
|
||||
dmastat = wddma.wdd_dmadone(du->dk_dmacookie);
|
||||
}
|
||||
|
||||
du->dk_timeout = 0;
|
||||
|
||||
/* check drive status/failure */
|
||||
if (wdwait(du, 0, TIMEOUT) < 0) {
|
||||
wderror(bp, du, "wdintr: timeout waiting for status");
|
||||
du->dk_status |= WDCS_ERR; /* XXX */
|
||||
@ -1067,21 +1078,32 @@ wdintr(int unit)
|
||||
}
|
||||
|
||||
/* have we an error? */
|
||||
if (du->dk_status & (WDCS_ERR | WDCS_ECCCOR)) {
|
||||
if ((du->dk_status & (WDCS_ERR | WDCS_ECCCOR))
|
||||
|| (((du->dk_flags & (DKFL_DMA|DKFL_SINGLE)) == DKFL_DMA)
|
||||
&& dmastat != WDDS_INTERRUPT)) {
|
||||
|
||||
unsigned int errstat;
|
||||
oops:
|
||||
/*
|
||||
* XXX bogus inb() here, register 0 is assumed and intr status
|
||||
* is reset.
|
||||
* XXX bogus inb() here
|
||||
*/
|
||||
if((du->dk_flags & DKFL_DMA ) &&
|
||||
(inb(du->dk_port) & WDERR_ABORT)) {
|
||||
errstat = inb(du->dk_port + wd_error);
|
||||
|
||||
if(((du->dk_flags & (DKFL_DMA|DKFL_SINGLE)) == DKFL_DMA) &&
|
||||
(errstat & WDERR_ABORT)) {
|
||||
wderror(bp, du, "reverting to PIO mode");
|
||||
du->dk_flags |= ~DKFL_USEDMA;
|
||||
du->dk_flags &= ~DKFL_USEDMA;
|
||||
} else if((du->dk_flags & DKFL_MULTI) &&
|
||||
(inb(du->dk_port) & WDERR_ABORT)) {
|
||||
(errstat & WDERR_ABORT)) {
|
||||
wderror(bp, du, "reverting to non-multi sector mode");
|
||||
du->dk_multi = 1;
|
||||
}
|
||||
|
||||
if (!(du->dk_status & (WDCS_ERR | WDCS_ECCCOR)) &&
|
||||
(((du->dk_flags & (DKFL_DMA|DKFL_SINGLE)) == DKFL_DMA) &&
|
||||
(dmastat != WDDS_INTERRUPT)))
|
||||
printf("wd%d: DMA failure, DMA status %b\n",
|
||||
du->dk_lunit, dmastat, WDDS_BITS);
|
||||
#ifdef WDDEBUG
|
||||
wderror(bp, du, "wdintr");
|
||||
#endif
|
||||
@ -1108,7 +1130,7 @@ oops:
|
||||
bp->b_error = EIO;
|
||||
bp->b_flags |= B_ERROR; /* flag the error */
|
||||
}
|
||||
} else
|
||||
} else if (du->dk_status & WDCS_ECCCOR)
|
||||
wderror(bp, du, "soft ecc");
|
||||
}
|
||||
|
||||
@ -1116,7 +1138,7 @@ oops:
|
||||
* If this was a successful read operation, fetch the data.
|
||||
*/
|
||||
if (((bp->b_flags & (B_READ | B_ERROR)) == B_READ)
|
||||
&& !(du->dk_flags & DKFL_DMA)
|
||||
&& !((du->dk_flags & (DKFL_DMA|DKFL_SINGLE)) == DKFL_DMA)
|
||||
&& wdtab[unit].b_active) {
|
||||
int chk, dummy, multisize;
|
||||
multisize = chk = du->dk_currentiosize * DEV_BSIZE;
|
||||
@ -1160,7 +1182,7 @@ oops:
|
||||
|
||||
/* final cleanup on DMA */
|
||||
if (((bp->b_flags & B_ERROR) == 0)
|
||||
&& (du->dk_flags & DKFL_DMA)
|
||||
&& ((du->dk_flags & (DKFL_DMA|DKFL_SINGLE)) == DKFL_DMA)
|
||||
&& wdtab[unit].b_active) {
|
||||
int iosize;
|
||||
|
||||
@ -1208,7 +1230,6 @@ done: ;
|
||||
wdtab[unit].b_errcnt = 0;
|
||||
bp->b_resid = bp->b_bcount - du->dk_skip * DEV_BSIZE;
|
||||
wdutab[du->dk_lunit].b_active = 0;
|
||||
wdutab[du->dk_lunit].b_errcnt = 0;
|
||||
du->dk_skip = 0;
|
||||
biodone(bp);
|
||||
}
|
||||
@ -1258,6 +1279,7 @@ wdopen(dev_t dev, int flags, int fmt, struct proc *p)
|
||||
|
||||
du->dk_flags &= ~DKFL_BADSCAN;
|
||||
|
||||
/* spin waiting for anybody else reading the disk label */
|
||||
while (du->dk_flags & DKFL_LABELLING)
|
||||
tsleep((caddr_t)&du->dk_flags, PZERO - 1, "wdopen", 1);
|
||||
#if 1
|
||||
@ -1512,6 +1534,8 @@ wdcommand(struct disk *du, u_int cylinder, u_int head, u_int sector,
|
||||
return (1);
|
||||
if( command == WDCC_FEATURES) {
|
||||
outb(wdc + wd_features, count);
|
||||
if ( count == WDFEA_SETXFER )
|
||||
outb(wdc + wd_seccnt, sector);
|
||||
} else {
|
||||
outb(wdc + wd_precomp, du->dk_dd.d_precompcyl / 4);
|
||||
outb(wdc + wd_cyl_lo, cylinder);
|
||||
@ -1647,7 +1671,8 @@ wdsetmode(int mode, void *wdinfo)
|
||||
|
||||
du = wdinfo;
|
||||
if (bootverbose)
|
||||
printf("wdsetmode() setting transfer mode to %02x\n", mode);
|
||||
printf("wd%d: wdsetmode() setting transfer mode to %02x\n",
|
||||
du->dk_lunit, mode);
|
||||
i = wdcommand(du, 0, 0, mode, WDFEA_SETXFER,
|
||||
WDCC_FEATURES) == 0 &&
|
||||
wdwait(du, WDCS_READY, TIMEOUT) == 0;
|
||||
@ -2234,11 +2259,19 @@ wdtimeout(void *cdu)
|
||||
du = (struct disk *)cdu;
|
||||
x = splbio();
|
||||
if (du->dk_timeout != 0 && --du->dk_timeout == 0) {
|
||||
if(timeouts++ == 5)
|
||||
wderror((struct buf *)NULL, du,
|
||||
"Last time I say: interrupt timeout. Probably a portable PC.");
|
||||
else if(timeouts < 5)
|
||||
wderror((struct buf *)NULL, du, "interrupt timeout");
|
||||
if(timeouts++ <= 5) {
|
||||
char *msg;
|
||||
|
||||
msg = (timeouts > 5) ?
|
||||
"Last time I say: interrupt timeout. Probably a portable PC." :
|
||||
"interrupt timeout";
|
||||
wderror((struct buf *)NULL, du, msg);
|
||||
if (du->dk_dmacookie)
|
||||
printf("wd%d: wdtimeout() DMA status %b\n",
|
||||
du->dk_lunit,
|
||||
wddma.wdd_dmastatus(du->dk_dmacookie),
|
||||
WDDS_BITS);
|
||||
}
|
||||
wdunwedge(du);
|
||||
wdflushirq(du, x);
|
||||
du->dk_skip = 0;
|
||||
|
@ -34,7 +34,7 @@
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* from: @(#)wdreg.h 7.1 (Berkeley) 5/9/91
|
||||
* $Id: wdreg.h,v 1.17 1997/02/22 09:37:27 peter Exp $
|
||||
* $Id: wdreg.h,v 1.12.2.3 1997/01/14 17:32:07 bde Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -284,10 +284,11 @@ struct wddma {
|
||||
#define WDDS_ERROR 0x0002
|
||||
#define WDDS_INTERRUPT 0x0004
|
||||
|
||||
#if 0
|
||||
/* XXX are these now useless? */
|
||||
/* local defines for ATA timing modes */
|
||||
#define WDDMA_GRPMASK 0xf0
|
||||
#define WDDS_BITS "\20\4interrupt\2error\1active"
|
||||
|
||||
/* defines for ATA timing modes */
|
||||
#define WDDMA_GRPMASK 0xf8
|
||||
#define WDDMA_MODEMASK 0x07
|
||||
/* flow-controlled PIO modes */
|
||||
#define WDDMA_PIO 0x10
|
||||
#define WDDMA_PIO3 0x10
|
||||
@ -299,11 +300,10 @@ struct wddma {
|
||||
#define WDDMA_MDMA2 0x22
|
||||
|
||||
/* Ultra DMA timing modes */
|
||||
#define WDDMA_UDMA 0x30
|
||||
#define WDDMA_UDMA0 0x30
|
||||
#define WDDMA_UDMA1 0x31
|
||||
#define WDDMA_UDMA2 0x32
|
||||
#endif
|
||||
#define WDDMA_UDMA 0x40
|
||||
#define WDDMA_UDMA0 0x40
|
||||
#define WDDMA_UDMA1 0x41
|
||||
#define WDDMA_UDMA2 0x42
|
||||
|
||||
extern struct wddma wddma;
|
||||
|
||||
|
@ -26,12 +26,13 @@
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* From: wd82371.c,v 1.5.2.1 1996/11/16 21:19:51 phk Exp $
|
||||
* $Id: ide_pci.c,v 1.1 1997/07/29 12:57:09 sos Exp $
|
||||
* From: wd82371.c,v 1.5.2.1 1996/11/16 21:19:51 phk Exp $
|
||||
* $Id: ide_pci.c,v 1.2 1997/08/02 14:33:09 bde Exp $
|
||||
*/
|
||||
|
||||
#include "pci.h"
|
||||
#if NPCI > 0
|
||||
#include "opt_wd.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
@ -47,6 +48,10 @@
|
||||
#include <pci/pcireg.h>
|
||||
#include <pci/ide_pcireg.h>
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a,b) (((a)<(b))?(a):(b))
|
||||
#endif
|
||||
|
||||
struct ide_pci_cookie; /* structs vendor_fns, ide_pci_cookie are recursive */
|
||||
|
||||
struct vendor_fns {
|
||||
@ -57,11 +62,7 @@ struct vendor_fns {
|
||||
void *);
|
||||
|
||||
void (*vendor_status) /* prints off DMA timing info */
|
||||
(int iobase_wd,
|
||||
int unit,
|
||||
int iobase_bm,
|
||||
pcici_t tag,
|
||||
pcidi_t type);
|
||||
(struct ide_pci_cookie *cookie);
|
||||
};
|
||||
|
||||
/*
|
||||
@ -76,6 +77,7 @@ struct vendor_fns {
|
||||
struct ide_pci_cookie {
|
||||
LIST_ENTRY(ide_pci_cookie) le;
|
||||
int iobase_wd;
|
||||
int ctlr; /* pri/sec controller on this PCI IDE interface */
|
||||
int unit;
|
||||
int iobase_bm; /* SFF-8038 control registers */
|
||||
pcici_t tag;
|
||||
@ -94,32 +96,31 @@ generic_dmainit(struct ide_pci_cookie *cookie,
|
||||
int(*wdcmd)(int, void *),
|
||||
void *wdinfo);
|
||||
static void
|
||||
generic_status(int iobase_wd,
|
||||
int unit,
|
||||
int iobase_bm,
|
||||
pcici_t tag,
|
||||
pcidi_t type);
|
||||
generic_status(struct ide_pci_cookie *cookie);
|
||||
|
||||
static void
|
||||
via_571_status(int iobase_wd,
|
||||
int unit,
|
||||
int iobase_bm,
|
||||
pcici_t tag,
|
||||
pcidi_t type);
|
||||
via_571_status(struct ide_pci_cookie *cookie);
|
||||
|
||||
static void
|
||||
intel_piix_dump_drive(char *ctlr,
|
||||
int sitre,
|
||||
int is_piix4,
|
||||
int word40,
|
||||
int word44,
|
||||
int word48,
|
||||
int word4a,
|
||||
int drive);
|
||||
static void
|
||||
intel_piix_status(int iobase_wd,
|
||||
int unit,
|
||||
int iobase_bm,
|
||||
pcici_t tag,
|
||||
pcidi_t type);
|
||||
intel_piix_status(struct ide_pci_cookie *cookie);
|
||||
static int
|
||||
intel_piix_dmainit(struct ide_pci_cookie *cookie,
|
||||
struct wdparams *wp,
|
||||
int(*wdcmd)(int, void *),
|
||||
void *wdinfo);
|
||||
|
||||
static struct ide_pci_cookie *
|
||||
mkcookie(int iobase_wd,
|
||||
int ctlr,
|
||||
int unit,
|
||||
int iobase_bm,
|
||||
pcici_t tag,
|
||||
@ -173,16 +174,13 @@ generic_dmainit(struct ide_pci_cookie *cookie,
|
||||
int(*wdcmd)(int, void *),
|
||||
void *wdinfo)
|
||||
{
|
||||
int mode, r;
|
||||
/*
|
||||
* XXX punt on the whole timing issue by looking for either a
|
||||
* punt on the whole timing issue by looking for either a
|
||||
* drive programmed for both PIO4 and mDMA2 (which use similar
|
||||
* timing) or a drive in an UltraDMA mode (hopefully all
|
||||
* controllers have separate timing for UDMA). one hopes that if
|
||||
* the drive's DMA mode has been configured by the BIOS, the
|
||||
* controller's has also. this code may eventually be replaced
|
||||
* by gunk in the hw-specific code to deal with specific
|
||||
* controllers.
|
||||
* controller's has also.
|
||||
*/
|
||||
/* XXX way too sick and twisted conditional */
|
||||
if (!((((wp->wdp_atavalid & 2) == 2) &&
|
||||
@ -192,35 +190,11 @@ generic_dmainit(struct ide_pci_cookie *cookie,
|
||||
(wp->wdp_udmamode == 4))))
|
||||
return 0;
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* XXX flesh this out into real code that actually
|
||||
* does something-- this was just testing gunk.
|
||||
*/
|
||||
if (((wp->wdp_atavalid & 0x4) == 0x4) &&
|
||||
(wp->wdp_udmamode == 4)) {
|
||||
printf("UDMA mode\n");
|
||||
mode = 0x42; /* XXX where's the #defines... */
|
||||
}
|
||||
else {
|
||||
printf("MDMA mode\n");
|
||||
mode = 0x24;
|
||||
}
|
||||
|
||||
r = wdcmd(mode, wdinfo);
|
||||
printf("dmainit out like we expect\n");
|
||||
if (!r)
|
||||
return 0;
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
generic_status(int iobase_wd,
|
||||
int unit,
|
||||
int iobase_bm,
|
||||
pcici_t tag,
|
||||
pcidi_t type)
|
||||
generic_status(struct ide_pci_cookie *cookie)
|
||||
{
|
||||
printf("generic_status: no PCI IDE timing info available\n");
|
||||
}
|
||||
@ -234,15 +208,22 @@ static struct vendor_fns vs_generic =
|
||||
/* VIA Technologies "82C571" PCI-IDE controller core */
|
||||
|
||||
static void
|
||||
via_571_status(int iobase_wd,
|
||||
int unit,
|
||||
int iobase_bm,
|
||||
pcici_t tag,
|
||||
pcidi_t type)
|
||||
via_571_status(struct ide_pci_cookie *cookie)
|
||||
{
|
||||
int iobase_wd;
|
||||
int unit;
|
||||
int iobase_bm;
|
||||
pcici_t tag;
|
||||
pcidi_t type;
|
||||
unsigned int word40[5];
|
||||
int i;
|
||||
|
||||
iobase_wd = cookie->iobase_wd;
|
||||
unit = cookie->unit;
|
||||
iobase_bm = cookie->iobase_bm;
|
||||
tag = cookie->tag;
|
||||
type = cookie->type;
|
||||
|
||||
/* XXX how to handle four calls for one controller? */
|
||||
if (iobase_wd != 0x1f0 || unit != 0)
|
||||
return;
|
||||
@ -272,7 +253,6 @@ via_571_status(int iobase_wd,
|
||||
((word40[2] >> (((3 - i) * 8) + 4)) & 0x0f) + 1,
|
||||
((word40[2] >> ((3 - i) * 8)) & 0x0f) + 1);
|
||||
|
||||
|
||||
/* XXX could go on and do UDMA status for '586B */
|
||||
}
|
||||
|
||||
@ -287,8 +267,11 @@ static struct vendor_fns vs_via_571 =
|
||||
static void
|
||||
intel_piix_dump_drive(char *ctlr,
|
||||
int sitre,
|
||||
int is_piix4,
|
||||
int word40,
|
||||
int word44,
|
||||
int word48,
|
||||
int word4a,
|
||||
int drive)
|
||||
{
|
||||
char *ms;
|
||||
@ -325,43 +308,203 @@ intel_piix_status: fast PIO %s%s\n",
|
||||
(word40 & 1) ? "enabled" : "disabled",
|
||||
((word40 & 9) == 9) ? " (overridden by fastDMAonly)" : "" );
|
||||
|
||||
/* XXX extend to dump 82371AB's UltraDMA modes */
|
||||
if (is_piix4)
|
||||
printf("intel_piix_status: UltraDMA %s, CT/RP = %d/%d\n",
|
||||
word48 ? "enabled": "disabled",
|
||||
4 - (word4a & 3),
|
||||
6 - (word4a & 3));
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
intel_piix_status(int iobase_wd,
|
||||
int unit,
|
||||
int iobase_bm,
|
||||
pcici_t tag,
|
||||
pcidi_t type)
|
||||
intel_piix_status(struct ide_pci_cookie *cookie)
|
||||
{
|
||||
unsigned int word40, word44;
|
||||
int sitre;
|
||||
int iobase_wd;
|
||||
int unit;
|
||||
int iobase_bm;
|
||||
pcici_t tag;
|
||||
pcidi_t type;
|
||||
int ctlr;
|
||||
unsigned int word40, word44, word48;
|
||||
int sitre, is_piix4;
|
||||
|
||||
/* XXX how to handle four calls for one controller? */
|
||||
if (iobase_wd != 0x1f0 || unit != 0)
|
||||
return;
|
||||
iobase_wd = cookie->iobase_wd;
|
||||
unit = cookie->unit;
|
||||
iobase_bm = cookie->iobase_bm;
|
||||
tag = cookie->tag;
|
||||
type = cookie->type;
|
||||
ctlr = cookie->ctlr;
|
||||
|
||||
word40 = pci_conf_read(tag, 0x40);
|
||||
word44 = pci_conf_read(tag, 0x44);
|
||||
word48 = pci_conf_read(tag, 0x48);
|
||||
|
||||
/*
|
||||
* XXX will not be right for the *next* generation of upward-compatible
|
||||
* intel IDE controllers...
|
||||
*/
|
||||
is_piix4 = pci_conf_read(tag, PCI_CLASS_REG) == 0x71118086;
|
||||
|
||||
sitre = word40 & 0x4000;
|
||||
|
||||
intel_piix_dump_drive("primary", sitre, word40 & 0xffff, word44 & 0x0f, 0);
|
||||
intel_piix_dump_drive("primary", sitre, word40 & 0xffff, word44 & 0x0f, 1);
|
||||
intel_piix_dump_drive("secondary",
|
||||
sitre,
|
||||
(word40 >> 16) & 0xffff,
|
||||
(word44 >> 4) & 0x0f,0);
|
||||
intel_piix_dump_drive("secondary",
|
||||
sitre,
|
||||
(word40 >> 16) & 0xffff,
|
||||
(word44 >> 4) & 0x0f,1);
|
||||
switch (ctlr * 2 + unit) {
|
||||
case 0:
|
||||
intel_piix_dump_drive("primary",
|
||||
sitre,
|
||||
is_piix4,
|
||||
word40 & 0xffff,
|
||||
word44 & 0x0f,
|
||||
word48,
|
||||
word48 >> 16,
|
||||
0);
|
||||
case 1:
|
||||
intel_piix_dump_drive("primary",
|
||||
sitre,
|
||||
is_piix4,
|
||||
word40 & 0xffff,
|
||||
word44 & 0x0f,
|
||||
word48 >> 1,
|
||||
word48 >> 20,
|
||||
1);
|
||||
case 2:
|
||||
intel_piix_dump_drive("secondary",
|
||||
sitre,
|
||||
is_piix4,
|
||||
(word40 >> 16) & 0xffff,
|
||||
(word44 >> 4) & 0x0f,
|
||||
word48 >> 2,
|
||||
word48 >> 24,
|
||||
0);
|
||||
case 3:
|
||||
intel_piix_dump_drive("secondary",
|
||||
sitre,
|
||||
is_piix4,
|
||||
(word40 >> 16) & 0xffff,
|
||||
(word44 >> 4) & 0x0f,
|
||||
word48 >> 3,
|
||||
word48 >> 28,
|
||||
1);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
intel_piix_dmainit(struct ide_pci_cookie *cookie,
|
||||
struct wdparams *wp,
|
||||
int(*wdcmd)(int, void *),
|
||||
void *wdinfo)
|
||||
{
|
||||
int r, pci_id;
|
||||
|
||||
pci_id = pci_conf_read(cookie->tag, PCI_CLASS_REG);
|
||||
|
||||
/*
|
||||
* If the drive is already in mDMA2 or UDMA2, we leave it and the
|
||||
* controller alone, on the theory that the BIOS already DTRT.
|
||||
*
|
||||
* XXX this does not handle the conceivable case where the drive
|
||||
* has been left in a the right mode from a previous boot, the
|
||||
* BIOS has not reset it, and the BIOS has also not set the modes
|
||||
* on the controller. The one case seen so far where the BIOS
|
||||
* doesn't dink the drives (Tyan S1563D with Award v4.01) it
|
||||
* *does* seem to correctly program the controller.
|
||||
*
|
||||
* Aren't PC's fun?
|
||||
*/
|
||||
|
||||
/* XXX way too sick and twisted conditional */
|
||||
if ((((wp->wdp_atavalid & 2) == 2) &&
|
||||
((wp->wdp_dmamword & 0x404) == 0x404) &&
|
||||
((wp->wdp_eidepiomodes & 2) == 2)) ||
|
||||
(((wp->wdp_atavalid & 4) == 4) &&
|
||||
(wp->wdp_udmamode & 0x404 == 0x404)))
|
||||
return 1;
|
||||
|
||||
/* If it's a UDMA drive and a PIIX4, set it up */
|
||||
if (((wp->wdp_atavalid & 4) == 4) &&
|
||||
((wp->wdp_udmamode & 4) == 4) &&
|
||||
pci_id == 0x71118086) {
|
||||
/* Set UDMA mode 2 on controller */
|
||||
int unitno, mask, new;
|
||||
|
||||
if (bootverbose)
|
||||
printf("intel_piix_dmainit: setting ultra DMA mode 2\n");
|
||||
r = wdcmd(WDDMA_UDMA2, wdinfo);
|
||||
if (!r) {
|
||||
printf("intel_piix_dmainit: setting DMA mode failed\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
unitno = cookie->ctlr * 2 + cookie->unit;
|
||||
|
||||
mask = 1 << unitno + 3 << (16 + unitno * 4);
|
||||
new = 1 << unitno + 2 << (16 + unitno * 4);
|
||||
|
||||
pci_conf_write(cookie->tag,
|
||||
0x48,
|
||||
(pci_conf_read(cookie->tag, 0x48) & ~mask) | new);
|
||||
}
|
||||
/*
|
||||
* if the SITRE bit is not set, indicating independent programming
|
||||
* of drive timing, we punt; we're not gonna fuss with trying to
|
||||
* coordinate timing modes between drives. if this is you, get a
|
||||
* BIOS that does this for us, or get a new motherboard if it's an
|
||||
* 82371FB (Triton FX). Or contribute patches :)
|
||||
*/
|
||||
else if ((pci_conf_read(cookie->tag, 0x40) >> (16 * cookie->ctlr))
|
||||
& 0x4000 == 0)
|
||||
return 0;
|
||||
/* otherwise, program it for MW DMA mode 2 */
|
||||
else if (((wp->wdp_atavalid & 2) == 2) &&
|
||||
((wp->wdp_dmamword & 4) == 4)) {
|
||||
/* Set multiword DMA mode 2 on controller */
|
||||
unsigned int mask40, mask44, new40, new44;
|
||||
|
||||
if (bootverbose)
|
||||
printf("intel_piix_dmainit: setting multiword DMA mode 2\n");
|
||||
r = wdcmd(WDDMA_MDMA2, wdinfo);
|
||||
if (!r) {
|
||||
printf("intel_piix_dmainit: setting DMA mode failed\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* backward compatible hardware leaves us with such twisted masses
|
||||
* of software (aka twiddle the extremely weird register layout on
|
||||
* a PIIX3)
|
||||
*/
|
||||
if (cookie->unit == 0) {
|
||||
mask40 = 0x330f;
|
||||
new40 = 0x2307;
|
||||
mask44 = 0;
|
||||
new44 = 0;
|
||||
}
|
||||
else {
|
||||
mask40 = 0x00f0;
|
||||
new40 = 0x0070;
|
||||
mask44 = 0x000f;
|
||||
new44 = 0x000b;
|
||||
}
|
||||
if (cookie->ctlr) {
|
||||
mask40 <<= 16;
|
||||
new40 <<= 16;
|
||||
mask44 <<= 4;
|
||||
new44 <<= 4;
|
||||
}
|
||||
pci_conf_write(cookie->tag,
|
||||
0x40,
|
||||
(pci_conf_read(cookie->tag, 0x40) & ~mask40) | new40);
|
||||
pci_conf_write(cookie->tag,
|
||||
0x44,
|
||||
(pci_conf_read(cookie->tag, 0x44) & ~mask44) | new44);
|
||||
}
|
||||
if (bootverbose)
|
||||
intel_piix_status(cookie);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct vendor_fns vs_intel_piix =
|
||||
{
|
||||
generic_dmainit,
|
||||
intel_piix_dmainit,
|
||||
intel_piix_status
|
||||
};
|
||||
|
||||
@ -374,6 +517,7 @@ static struct vendor_fns vs_intel_piix =
|
||||
|
||||
static struct ide_pci_cookie *
|
||||
mkcookie(int iobase_wd,
|
||||
int ctlr,
|
||||
int unit,
|
||||
int iobase_bm,
|
||||
pcici_t tag,
|
||||
@ -386,6 +530,7 @@ mkcookie(int iobase_wd,
|
||||
if (!cp) return cp;
|
||||
|
||||
cp->iobase_wd = iobase_wd;
|
||||
cp->ctlr = ctlr;
|
||||
cp->unit = unit;
|
||||
cp->tag = tag;
|
||||
cp->type = type;
|
||||
@ -400,7 +545,7 @@ mkcookie(int iobase_wd,
|
||||
}
|
||||
if (((int)prdbuf >> PAGE_SHIFT) ^
|
||||
(((int)prdbuf + PRD_ALLOC_SIZE - 1) >> PAGE_SHIFT)) {
|
||||
printf("ide_pci: prdbuf straddles page boundary, no DMA");
|
||||
printf("ide_pci: prdbuf straddles page boundary, no DMA\n");
|
||||
FREE(cp, M_DEVBUF);
|
||||
FREE(prdbuf, M_DEVBUF);
|
||||
return 0;
|
||||
@ -411,12 +556,17 @@ mkcookie(int iobase_wd,
|
||||
cp->prd = prdbuf_next;
|
||||
(char *)prdbuf_next += PRD_BUF_SIZE;
|
||||
|
||||
if ((char *)prdbuf_next > ((char *)prdbuf + PRD_ALLOC_SIZE))
|
||||
panic("ide_pci: too many prdbufs allocated");
|
||||
if ((char *)prdbuf_next > ((char *)prdbuf + PRD_ALLOC_SIZE)) {
|
||||
printf("ide_pci: mkcookie %04x:%d: no more space for PRDs, no DMA\n",
|
||||
iobase_wd, unit);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (bootverbose)
|
||||
printf("ide_pci: mkcookie %04x:%d: PRD vstart = %08x vend = %08x\n",
|
||||
iobase_wd, unit, (int)cp->prd, ((int)cp->prd)+PRD_BUF_SIZE);
|
||||
#endif
|
||||
LIST_INSERT_HEAD(&softc.cookies, cp, le);
|
||||
return cp;
|
||||
}
|
||||
@ -426,29 +576,26 @@ ide_pci_probe(pcici_t tag, pcidi_t type)
|
||||
{
|
||||
int data = pci_conf_read(tag, PCI_CLASS_REG);
|
||||
|
||||
switch (data & PCI_CLASS_MASK) {
|
||||
|
||||
case PCI_CLASS_MASS_STORAGE:
|
||||
if ((data & PCI_SUBCLASS_MASK) == 0x00010000) {
|
||||
if (type == 0x71118086)
|
||||
return ("Intel PIIX4 Bus-master IDE controller");
|
||||
if (type == 0x70108086)
|
||||
return ("Intel PIIX3 Bus-master IDE controller");
|
||||
if (type == 0x12308086)
|
||||
return ("Intel PIIX Bus-master IDE controller");
|
||||
if (type == 0x05711106)
|
||||
return ("VIA 82C586x (Apollo) Bus-master IDE controller");
|
||||
if (data & 0x8000)
|
||||
return ("PCI IDE controller (busmaster capable)");
|
||||
/*
|
||||
* XXX leave this out for now, to allow CMD640B hack to work. said
|
||||
* hack should be better integrated, or something.
|
||||
*/
|
||||
#if 0
|
||||
else
|
||||
return ("PCI IDE controller (not busmaster capable)");
|
||||
if ((data & PCI_CLASS_MASK) == PCI_CLASS_MASS_STORAGE &&
|
||||
(data & PCI_SUBCLASS_MASK) == 0x00010000) {
|
||||
if (type == 0x71118086)
|
||||
return ("Intel PIIX4 Bus-master IDE controller");
|
||||
if (type == 0x70108086)
|
||||
return ("Intel PIIX3 Bus-master IDE controller");
|
||||
if (type == 0x12308086)
|
||||
return ("Intel PIIX Bus-master IDE controller");
|
||||
if (type == 0x05711106)
|
||||
return ("VIA 82C586x (Apollo) Bus-master IDE controller");
|
||||
if (data & 0x8000)
|
||||
return ("PCI IDE controller (busmaster capable)");
|
||||
#ifndef CMD640
|
||||
/*
|
||||
* XXX the CMD640B hack should be better integrated, or
|
||||
* something.
|
||||
*/
|
||||
else
|
||||
return ("PCI IDE controller (not busmaster capable)");
|
||||
#endif
|
||||
}
|
||||
};
|
||||
return ((char*)0);
|
||||
}
|
||||
@ -458,11 +605,12 @@ ide_pci_attach(pcici_t tag, int unit)
|
||||
{
|
||||
u_long idetm;
|
||||
int class;
|
||||
int bmista;
|
||||
int iobase_wd, iobase_bm;
|
||||
int bmista_1, bmista_2;
|
||||
int iobase_wd_1, iobase_wd_2, iobase_bm_1, iobase_bm_2;
|
||||
int cmd;
|
||||
struct vendor_fns *vp;
|
||||
pcidi_t type;
|
||||
struct ide_pci_cookie *cookie;
|
||||
|
||||
if (unit) return;
|
||||
|
||||
@ -496,61 +644,20 @@ ide_pci_attach(pcici_t tag, int unit)
|
||||
break;
|
||||
}
|
||||
|
||||
iobase_wd = (class & 0x100) ?
|
||||
(pci_conf_read(tag, 0x10) & 0xfffc) :
|
||||
0x1f0;
|
||||
iobase_bm = pci_conf_read(tag, 0x20) & 0xfffc;
|
||||
iobase_wd_1 = (class & 0x100) ?
|
||||
(pci_conf_read(tag, 0x10) & 0xfffc) :
|
||||
0x1f0;
|
||||
iobase_bm_1 = pci_conf_read(tag, 0x20) & 0xfffc;
|
||||
|
||||
if (!ide_pci_softc_cookies_initted) {
|
||||
LIST_INIT(&softc.cookies);
|
||||
ide_pci_softc_cookies_initted = 1;
|
||||
}
|
||||
iobase_wd_2 = (class & 0x400) ?
|
||||
(pci_conf_read(tag, 0x10) & 0xfffc) :
|
||||
0x170;
|
||||
iobase_bm_2 = iobase_bm_1 + SFF8038_CTLR_1;
|
||||
|
||||
bmista = inb(iobase_bm + BMISTA_PORT);
|
||||
|
||||
if (bootverbose)
|
||||
printf("ide_pci: busmaster 0 status: %02x from port: %08x\n",
|
||||
bmista, iobase_bm+BMISTA_PORT);
|
||||
|
||||
if (!(bmista & BMISTA_DMA0CAP))
|
||||
printf("ide_pci: warning, ide0:0 not configured for DMA?\n");
|
||||
mkcookie(iobase_wd, 0, iobase_bm, tag, type, vp);
|
||||
if (bootverbose)
|
||||
vp->vendor_status(iobase_wd, 0, iobase_bm, tag, type);
|
||||
|
||||
if (!(bmista & BMISTA_DMA1CAP))
|
||||
printf("ide_pci: warning, ide0:1 not configured for DMA?\n");
|
||||
mkcookie(iobase_wd, 1, iobase_bm, tag, type, vp);
|
||||
if (bootverbose)
|
||||
vp->vendor_status(iobase_wd, 1, iobase_bm, tag, type);
|
||||
|
||||
if (bmista & BMISTA_SIMPLEX) {
|
||||
printf("ide_pci: primary is simplex-only, no DMA on secondary\n");
|
||||
} else {
|
||||
iobase_wd = (class & 0x400) ?
|
||||
(pci_conf_read(tag, 0x10) & 0xfffc) :
|
||||
0x170;
|
||||
iobase_bm += SFF8038_CTLR_1;
|
||||
bmista = inb(iobase_bm + BMISTA_PORT);
|
||||
|
||||
if (bootverbose)
|
||||
printf("ide_pci: busmaster 1 status: %02x from port: %08x\n",
|
||||
bmista, iobase_bm+BMISTA_PORT);
|
||||
|
||||
if (bmista & BMISTA_SIMPLEX) {
|
||||
printf("ide_pci: secondary is simplex-only, no DMA on secondary\n");
|
||||
} else {
|
||||
if (!(bmista & BMISTA_DMA0CAP))
|
||||
printf("ide_pci: warning, ide1:0 not configured for DMA?\n");
|
||||
mkcookie(iobase_wd, 0, iobase_bm, tag, type, vp);
|
||||
if (bootverbose)
|
||||
vp->vendor_status(iobase_wd, 0, iobase_bm, tag, type);
|
||||
if (!(bmista & BMISTA_DMA1CAP))
|
||||
printf("ide_pci: warning, ide1:1 not configured for DMA?\n");
|
||||
mkcookie(iobase_wd, 1, iobase_bm, tag, type, vp);
|
||||
if (bootverbose)
|
||||
vp->vendor_status(iobase_wd, 1, iobase_bm, tag, type);
|
||||
}
|
||||
if (iobase_bm_1 == 0) {
|
||||
printf("ide_pci: BIOS has not configured busmaster I/O address,\n"
|
||||
"ide_pci: giving up\n");
|
||||
return;
|
||||
}
|
||||
|
||||
wddma.wdd_candma = ide_pci_candma;
|
||||
@ -560,6 +667,54 @@ ide_pci_attach(pcici_t tag, int unit)
|
||||
wddma.wdd_dmastart = ide_pci_dmastart;
|
||||
wddma.wdd_dmadone = ide_pci_dmadone;
|
||||
wddma.wdd_dmastatus = ide_pci_status;
|
||||
|
||||
bmista_1 = inb(iobase_bm_1 + BMISTA_PORT);
|
||||
bmista_2 = inb(iobase_bm_2 + BMISTA_PORT);
|
||||
|
||||
if (!ide_pci_softc_cookies_initted) {
|
||||
LIST_INIT(&softc.cookies);
|
||||
ide_pci_softc_cookies_initted = 1;
|
||||
}
|
||||
|
||||
if (iobase_wd_1 != 0) {
|
||||
cookie = mkcookie(iobase_wd_1, 0, 0, iobase_bm_1, tag, type, vp);
|
||||
if (bootverbose)
|
||||
vp->vendor_status(cookie);
|
||||
cookie = mkcookie(iobase_wd_1, 0, 1, iobase_bm_1, tag, type, vp);
|
||||
if (bootverbose) {
|
||||
vp->vendor_status(cookie);
|
||||
|
||||
printf("ide_pci: busmaster 0 status: %02x from port: %08x\n",
|
||||
bmista_1, iobase_bm_1+BMISTA_PORT);
|
||||
|
||||
if (bmista_1 & BMISTA_DMA0CAP)
|
||||
printf("ide_pci: ide0:0 has been configured for DMA by BIOS\n");
|
||||
if (bmista_1 & BMISTA_DMA1CAP)
|
||||
printf("ide_pci: ide0:1 has been configured for DMA by BIOS\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (bmista_1 & BMISTA_SIMPLEX || bmista_2 & BMISTA_SIMPLEX) {
|
||||
printf("ide_pci: controller is simplex, no DMA on secondary channel\n");
|
||||
}
|
||||
else if (iobase_wd_2 != 0) {
|
||||
cookie = mkcookie(iobase_wd_2, 1, 0, iobase_bm_2, tag, type, vp);
|
||||
if (bootverbose)
|
||||
vp->vendor_status(cookie);
|
||||
cookie = mkcookie(iobase_wd_2, 1, 1, iobase_bm_2, tag, type, vp);
|
||||
if (bootverbose) {
|
||||
vp->vendor_status(cookie);
|
||||
|
||||
printf("ide_pci: busmaster 1 status: %02x from port: %08x\n",
|
||||
bmista_2, iobase_bm_2+BMISTA_PORT);
|
||||
|
||||
if (bmista_2 & BMISTA_DMA0CAP)
|
||||
printf("ide_pci: ide1:0 has been configured for DMA by BIOS\n");
|
||||
if (bmista_2 & BMISTA_DMA1CAP)
|
||||
printf("ide_pci: ide1:1 has been configured for DMA by BIOS\n");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static u_long ide_pci_count;
|
||||
@ -605,6 +760,15 @@ ide_pci_dmainit(void *cookie,
|
||||
{
|
||||
struct ide_pci_cookie *cp = cookie;
|
||||
|
||||
/*
|
||||
* If the controller status indicates that DMA is configured already,
|
||||
* we flounce happily away
|
||||
*/
|
||||
if (inb(cp->iobase_bm + BMISTA_PORT) &
|
||||
((cp->unit == 0) ? BMISTA_DMA0CAP : BMISTA_DMA1CAP))
|
||||
return 1;
|
||||
|
||||
/* We take a stab at it with device-dependent code */
|
||||
return(cp->vs.vendor_dmainit(cp, wp, wdcmd, wdinfo));
|
||||
}
|
||||
/*
|
||||
@ -620,16 +784,12 @@ ide_pci_dmaverify(void *xcp, char *vaddr, u_long count, int dir)
|
||||
* check for nonaligned or odd-length Stuff
|
||||
*/
|
||||
badfu = ((unsigned int)vaddr & 1) || (count & 1);
|
||||
#if 1
|
||||
#ifdef DIAGNOSTIC
|
||||
if (badfu) {
|
||||
printf("ide_pci: dmaverify odd vaddr or length, ");
|
||||
printf("vaddr = %08x length = %08x\n", (int)vaddr, count);
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
* XXX should perhaps be checking that length of generated table
|
||||
* does not exceed space available, but that Would Be Hairy
|
||||
*/
|
||||
return (!badfu);
|
||||
}
|
||||
|
||||
@ -639,118 +799,107 @@ ide_pci_dmaverify(void *xcp, char *vaddr, u_long count, int dir)
|
||||
* is called.
|
||||
*/
|
||||
static int
|
||||
ide_pci_dmasetup(void *xcp, char *vaddr, u_long count, int dir)
|
||||
ide_pci_dmasetup(void *xcp, char *vaddr, u_long vcount, int dir)
|
||||
{
|
||||
struct ide_pci_cookie *cp = xcp;
|
||||
struct ide_pci_prd *prd;
|
||||
int i;
|
||||
u_long pgresid;
|
||||
u_long firstpage;
|
||||
u_long prd_base, prd_count;
|
||||
u_long nbase, ncount, nend;
|
||||
int iobase_bm;
|
||||
static int trashmore;
|
||||
static int trashmore = 0xdeadbeef;
|
||||
static int *trashmore_p = 0;
|
||||
|
||||
u_long count, checkcount;
|
||||
|
||||
prd = cp->prd;
|
||||
|
||||
count = vcount;
|
||||
|
||||
i = 0;
|
||||
|
||||
iobase_bm = cp->iobase_bm;
|
||||
/*
|
||||
* ensure that 0-length transfers get a PRD that won't smash much
|
||||
*/
|
||||
if (!trashmore_p)
|
||||
trashmore_p = (void *)vtophys(&trashmore);
|
||||
|
||||
prd[0].prd_base = (unsigned int)trashmore_p;
|
||||
prd[0].prd_count = 0x80000002;
|
||||
|
||||
if (count == 0) {
|
||||
printf("ide_pci: dmasetup 0-length transfer, ");
|
||||
printf("vaddr = %08x length = %08x\n", (int)vaddr, count);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX the PRD generation code is somewhat ugly and will not
|
||||
* port easily to big endian systems.
|
||||
*
|
||||
* but it works.
|
||||
*/
|
||||
/* Generate first PRD entry, which may be non-aligned. */
|
||||
|
||||
/*
|
||||
* Deal with transfers that don't start on a page
|
||||
* boundary.
|
||||
*/
|
||||
pgresid = (u_long)vaddr % PAGE_SIZE;
|
||||
if (pgresid) {
|
||||
prd[i].prd_base = vtophys(vaddr);
|
||||
if (count >= (PAGE_SIZE - pgresid))
|
||||
prd[i].prd_count = PAGE_SIZE - pgresid;
|
||||
else
|
||||
prd[i].prd_count = count;
|
||||
vaddr += prd[i].prd_count;
|
||||
count -= prd[i].prd_count;
|
||||
i++;
|
||||
}
|
||||
firstpage = PAGE_SIZE - ((u_long)vaddr & PAGE_MASK);
|
||||
|
||||
/*
|
||||
* We have now ensured that vaddr is page-aligned, so just
|
||||
* step through the pages adding each one onto the list.
|
||||
*/
|
||||
while(count) {
|
||||
u_long phys, n;
|
||||
prd_base = vtophys(vaddr);
|
||||
prd_count = MIN(count, firstpage);
|
||||
|
||||
phys = vtophys(vaddr);
|
||||
n = ((count > PAGE_SIZE) ? PAGE_SIZE : count);
|
||||
/*
|
||||
* If the current page is physically contiguous with
|
||||
* whatever we have in the previous PRD, just tack it
|
||||
* onto the end.
|
||||
* CAVEAT: due to a hardware deficiency, PRDs
|
||||
* cannot cross a 64K boundary.
|
||||
* XXX should we bother with this collapsing? scattered
|
||||
* pages appear to be the common case anyway.
|
||||
*/
|
||||
if (i > 0
|
||||
&& (phys == prd[i - 1].prd_base + prd[i - 1].prd_count)
|
||||
&& ((prd[i - 1].prd_base & 0xffff)
|
||||
+ prd[i - 1].prd_count + n) <= 65535) {
|
||||
vaddr += prd_count;
|
||||
count -= prd_count;
|
||||
|
||||
prd[i - 1].prd_count += n;
|
||||
/* Step through virtual pages, coalescing as needed. */
|
||||
while (count) {
|
||||
|
||||
nbase = vtophys(vaddr);
|
||||
ncount = MIN(count, PAGE_SIZE);
|
||||
nend = nbase + ncount;
|
||||
|
||||
/* Coalesce if physically contiguous and not crossing 64k boundary. */
|
||||
if ((prd_base + prd_count == nbase) &&
|
||||
((((nend - 1) ^ prd_base) & ~0xffff) == 0)) {
|
||||
prd_count += ncount;
|
||||
} else {
|
||||
prd[i].prd_base = phys;
|
||||
prd[i].prd_count = n;
|
||||
prd[i].prd_base = prd_base;
|
||||
prd[i].prd_count = (prd_count & 0xffff);
|
||||
i++;
|
||||
if (i >= PRD_MAX_SEGS)
|
||||
panic("wd82371: too many segments\n");
|
||||
if (i >= PRD_MAX_SEGS) {
|
||||
printf("wd82371: too many segments in PRD table\n");
|
||||
return 1;
|
||||
}
|
||||
prd_base = nbase;
|
||||
prd_count = ncount;
|
||||
}
|
||||
count -= n;
|
||||
vaddr += n;
|
||||
vaddr += ncount;
|
||||
count -= ncount;
|
||||
}
|
||||
|
||||
/* put a sign at the edge of the cliff... */
|
||||
prd[(i>0) ? (i-1) : 0].prd_count |= PRD_EOT_BIT;
|
||||
/* Write last PRD entry. */
|
||||
prd[i].prd_base = prd_base;
|
||||
prd[i].prd_count = (prd_count & 0xffff) | PRD_EOT_BIT;
|
||||
|
||||
if (i == 0)
|
||||
printf("ide_pci: dmasetup 0-length PRD???\n");
|
||||
#ifdef DIAGNOSTIC
|
||||
/* sanity check the transfer for length and page-alignment, at least */
|
||||
checkcount = 0;
|
||||
for (i = 0;; i++) {
|
||||
unsigned int modcount;
|
||||
|
||||
modcount = prd[i].prd_count & 0xffffe;
|
||||
if (modcount == 0) modcount = 0x10000;
|
||||
checkcount += modcount;
|
||||
if (i != 0 && ((prd[i].prd_base & PAGE_MASK) != 0)) {
|
||||
printf("ide_pci: dmasetup() diagnostic fails-- unaligned page\n");
|
||||
return 1;
|
||||
}
|
||||
if (prd[i].prd_count & PRD_EOT_BIT)
|
||||
break;
|
||||
}
|
||||
|
||||
if (checkcount != vcount) {
|
||||
printf("ide_pci: dmasetup() diagnostic fails-- bad length\n");
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Set up PRD base register */
|
||||
outl(iobase_bm + BMIDTP_PORT, vtophys(prd));
|
||||
|
||||
/* Set direction of transfer */
|
||||
if (dir == B_READ) {
|
||||
outb(iobase_bm + BMICOM_PORT, BMICOM_READ_WRITE);
|
||||
} else {
|
||||
outb(iobase_bm + BMICOM_PORT, 0);
|
||||
}
|
||||
outb(iobase_bm + BMICOM_PORT, (dir == B_READ) ? BMICOM_READ_WRITE : 0);
|
||||
|
||||
/* Clear interrupt and error bits */
|
||||
outb(iobase_bm + BMISTA_PORT,
|
||||
(inb(iobase_bm + BMISTA_PORT)
|
||||
| (BMISTA_INTERRUPT | BMISTA_DMA_ERROR)));
|
||||
|
||||
/* printf("dma enable: iobase_bm = %08x command/status = %08x pointer = %08x\n", iobase_bm, inl(iobase_bm + BMICOM_PORT), inl(iobase_bm + BMIDTP_PORT)); */
|
||||
|
||||
/* printf("P"); */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -765,7 +914,6 @@ ide_pci_dmastart(void *xcp)
|
||||
outb(iobase_bm + BMICOM_PORT,
|
||||
inb(iobase_bm + BMICOM_PORT) | BMICOM_STOP_START);
|
||||
|
||||
/* printf("["); */
|
||||
}
|
||||
|
||||
static int
|
||||
@ -780,8 +928,6 @@ ide_pci_dmadone(void *xcp)
|
||||
outb(iobase_bm + BMICOM_PORT,
|
||||
inb(iobase_bm + BMICOM_PORT) & ~BMICOM_STOP_START);
|
||||
|
||||
/* printf("]"); */
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
@ -796,8 +942,6 @@ ide_pci_status(void *xcp)
|
||||
|
||||
bmista = inb(iobase_bm + BMISTA_PORT);
|
||||
|
||||
/* printf("dmastatus: iobase_bm = %08x status = %02x command/status = %08x pointer = %08x\n", iobase_bm, bmista, inl(iobase_bm + BMICOM_PORT), inl(iobase_bm + BMIDTP_PORT)); */
|
||||
|
||||
if (bmista & BMISTA_INTERRUPT)
|
||||
status |= WDDS_INTERRUPT;
|
||||
if (bmista & BMISTA_DMA_ERROR)
|
||||
@ -805,8 +949,6 @@ ide_pci_status(void *xcp)
|
||||
if (bmista & BMISTA_DMA_ACTIVE)
|
||||
status |= WDDS_ACTIVE;
|
||||
|
||||
/* printf( (bmista == BMISTA_INTERRUPT)? "?":"!"); */
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user