diff options
Diffstat (limited to 'sys')
-rw-r--r-- | sys/conf/NOTES | 19 | ||||
-rw-r--r-- | sys/dev/pci/pcireg.h | 3 | ||||
-rw-r--r-- | sys/i386/conf/LINT | 19 | ||||
-rw-r--r-- | sys/i386/conf/NOTES | 19 | ||||
-rw-r--r-- | sys/i386/isa/wd.c | 88 | ||||
-rw-r--r-- | sys/i386/isa/wdreg.h | 10 | ||||
-rw-r--r-- | sys/pci/ide_pci.c | 1698 | ||||
-rw-r--r-- | sys/pci/pcireg.h | 3 |
8 files changed, 1205 insertions, 654 deletions
diff --git a/sys/conf/NOTES b/sys/conf/NOTES index 4e09a86..7b6675e 100644 --- a/sys/conf/NOTES +++ b/sys/conf/NOTES @@ -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.366 1997/09/16 07:45:31 joerg Exp $ +# $Id: LINT,v 1.367 1997/09/19 15:25:48 jmg 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 @@ -763,8 +763,23 @@ controller wds0 at isa? port 0x350 bio irq 15 drq 6 vector wdsintr # allowed to probe for 32 bit transfers, but will allow multi-sector # transfers up to the maximum that the drive supports. # - +# If you are using a PCI controller that is not running in compatibility +# mode (for example, it is a 2nd IDE PCI interface), then use config line(s) +# such as: +# +#controller wdc2 at isa? port "0" bio irq ? flags 0xa0ffa0ff vector wdintr +#disk wd4 at wdc2 drive 0 +#disk wd5 at wdc2 drive 1 +# +#controller wdc3 at isa? port "0" bio irq ? flags 0xa0ffa0ff vector wdintr +#disk wd6 at wdc3 drive 0 +#disk wd7 at wdc3 drive 1 # +# Note that the above config would be useful for a Promise card, when used +# on a MB that already has a PIIX controller. Note the bogus irq and port +# entries. These are automatically filled in by the IDE/PCI support. +# + controller wdc0 at isa? port "IO_WD1" bio irq 14 vector wdintr disk wd0 at wdc0 drive 0 disk wd1 at wdc0 drive 1 diff --git a/sys/dev/pci/pcireg.h b/sys/dev/pci/pcireg.h index c24237f..9e8c85e 100644 --- a/sys/dev/pci/pcireg.h +++ b/sys/dev/pci/pcireg.h @@ -26,7 +26,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: pcireg.h,v 1.17 1997/05/28 20:37:19 se Exp $ + * $Id: pcireg.h,v 1.18 1997/06/01 16:00:43 peter Exp $ * */ @@ -241,6 +241,7 @@ #define PCI_CLASS_REG 0x08 #define PCI_CLASS_MASK 0xff000000 #define PCI_SUBCLASS_MASK 0x00ff0000 +#define PCI_REVISION_MASK 0x000000ff #define PCI_CLASS_PREHISTORIC 0x00000000 #define PCI_SUBCLASS_PREHISTORIC_VGA 0x00010000 #define PCI_CLASS_MASS_STORAGE 0x01000000 diff --git a/sys/i386/conf/LINT b/sys/i386/conf/LINT index 4e09a86..7b6675e 100644 --- a/sys/i386/conf/LINT +++ b/sys/i386/conf/LINT @@ -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.366 1997/09/16 07:45:31 joerg Exp $ +# $Id: LINT,v 1.367 1997/09/19 15:25:48 jmg 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 @@ -763,8 +763,23 @@ controller wds0 at isa? port 0x350 bio irq 15 drq 6 vector wdsintr # allowed to probe for 32 bit transfers, but will allow multi-sector # transfers up to the maximum that the drive supports. # - +# If you are using a PCI controller that is not running in compatibility +# mode (for example, it is a 2nd IDE PCI interface), then use config line(s) +# such as: +# +#controller wdc2 at isa? port "0" bio irq ? flags 0xa0ffa0ff vector wdintr +#disk wd4 at wdc2 drive 0 +#disk wd5 at wdc2 drive 1 +# +#controller wdc3 at isa? port "0" bio irq ? flags 0xa0ffa0ff vector wdintr +#disk wd6 at wdc3 drive 0 +#disk wd7 at wdc3 drive 1 # +# Note that the above config would be useful for a Promise card, when used +# on a MB that already has a PIIX controller. Note the bogus irq and port +# entries. These are automatically filled in by the IDE/PCI support. +# + controller wdc0 at isa? port "IO_WD1" bio irq 14 vector wdintr disk wd0 at wdc0 drive 0 disk wd1 at wdc0 drive 1 diff --git a/sys/i386/conf/NOTES b/sys/i386/conf/NOTES index 4e09a86..7b6675e 100644 --- a/sys/i386/conf/NOTES +++ b/sys/i386/conf/NOTES @@ -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.366 1997/09/16 07:45:31 joerg Exp $ +# $Id: LINT,v 1.367 1997/09/19 15:25:48 jmg 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 @@ -763,8 +763,23 @@ controller wds0 at isa? port 0x350 bio irq 15 drq 6 vector wdsintr # allowed to probe for 32 bit transfers, but will allow multi-sector # transfers up to the maximum that the drive supports. # - +# If you are using a PCI controller that is not running in compatibility +# mode (for example, it is a 2nd IDE PCI interface), then use config line(s) +# such as: +# +#controller wdc2 at isa? port "0" bio irq ? flags 0xa0ffa0ff vector wdintr +#disk wd4 at wdc2 drive 0 +#disk wd5 at wdc2 drive 1 +# +#controller wdc3 at isa? port "0" bio irq ? flags 0xa0ffa0ff vector wdintr +#disk wd6 at wdc3 drive 0 +#disk wd7 at wdc3 drive 1 # +# Note that the above config would be useful for a Promise card, when used +# on a MB that already has a PIIX controller. Note the bogus irq and port +# entries. These are automatically filled in by the IDE/PCI support. +# + controller wdc0 at isa? port "IO_WD1" bio irq 14 vector wdintr disk wd0 at wdc0 drive 0 disk wd1 at wdc0 drive 1 diff --git a/sys/i386/isa/wd.c b/sys/i386/isa/wd.c index 7d8f8a1..eecfbaa 100644 --- a/sys/i386/isa/wd.c +++ b/sys/i386/isa/wd.c @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * from: @(#)wd.c 7.2 (Berkeley) 5/9/91 - * $Id: wd.c,v 1.137 1997/09/10 12:31:38 joerg Exp $ + * $Id: wd.c,v 1.138 1997/09/13 16:12:12 joerg Exp $ */ /* TODO: @@ -66,6 +66,7 @@ #if NWDC > 0 +#include "pci.h" #include <sys/param.h> #include <sys/dkbad.h> #include <sys/systm.h> @@ -157,11 +158,13 @@ struct disk { #endif int dk_unit; /* physical unit number */ int dk_lunit; /* logical unit number */ + int dk_interface; /* interface (two ctrlrs per interface) */ char dk_state; /* control state */ u_char dk_status; /* copy of status reg. */ u_char dk_error; /* copy of error reg. */ u_char dk_timeout; /* countdown to next timeout */ int dk_port; /* i/o port base */ + int dk_altport; /* altstatus port base */ #ifdef DEVFS void *dk_bdev; /* devfs token for whole disk */ void *dk_cdev; /* devfs token for raw whole disk */ @@ -204,7 +207,7 @@ static struct { int b_active; } wdtab[NWDC]; -struct wddma wddma; +struct wddma wddma[NWDC]; #ifdef notyet static struct buf rwdbuf[NWD]; /* buffers for raw IO */ @@ -276,6 +279,8 @@ static int wdprobe(struct isa_device *dvp) { int unit = dvp->id_unit; + void *cookie; + int interface; struct disk *du; if (unit >= NWDC) @@ -286,8 +291,21 @@ wdprobe(struct isa_device *dvp) return (0); bzero(du, sizeof *du); du->dk_ctrlr = dvp->id_unit; + interface = du->dk_ctrlr / 2; + du->dk_interface = interface; +#if !defined(DISABLE_PCI_IDE) && (NPCI > 0) + if (wddma[interface].wdd_candma) { + du->dk_dmacookie = wddma[interface].wdd_candma(dvp->id_iobase, du->dk_ctrlr); + du->dk_port = dvp->id_iobase; + du->dk_altport = wddma[interface].wdd_altiobase(du->dk_dmacookie); + } else { + du->dk_port = dvp->id_iobase; + du->dk_altport = du->dk_port + wd_ctlr; + } +#else du->dk_port = dvp->id_iobase; - + du->dk_altport = du->dk_port + wd_ctlr; +#endif /* check if we have registers that work */ outb(du->dk_port + wd_sdh, WDSD_IBM); /* set unit 0 */ @@ -317,14 +335,16 @@ wdprobe(struct isa_device *dvp) goto reset_ok; #endif DELAY(RECOVERYTIME); - if (wdreset(du) != 0) + if (wdreset(du) != 0) { goto nodevice; + } reset_ok: /* execute a controller only command */ if (wdcommand(du, 0, 0, 0, 0, WDCC_DIAGNOSE) != 0 - || wdwait(du, 0, TIMEOUT) < 0) + || wdwait(du, 0, TIMEOUT) < 0) { goto nodevice; + } /* * drive(s) did not time out during diagnostic : @@ -338,7 +358,6 @@ reset_ok: * drive 2. (This seems to contradict the ATA spec.) */ du->dk_error = inb(du->dk_port + wd_error); - /* printf("Error : %x\n", du->dk_error); */ if(du->dk_error != 0x01) { if(du->dk_error & 0x80) { /* drive 1 failure */ @@ -776,7 +795,7 @@ wdstart(int ctrlr) (bp->b_flags & B_READ) ? "read" : "write", bp->b_bcount, blknum); else - printf(" %d)%x", du->dk_skip, inb(du->dk_port + wd_altsts)); + printf(" %d)%x", du->dk_skip, inb(du->dk_altport)); #endif lp = &du->dk_dd; @@ -844,7 +863,7 @@ wdstart(int ctrlr) du->dk_currentiosize = 1; } else { if((du->dk_flags & DKFL_USEDMA) && - wddma.wdd_dmaverify(du->dk_dmacookie, + wddma[du->dk_interface].wdd_dmaverify(du->dk_dmacookie, (void *)((int)bp->b_un.b_addr + du->dk_skip * DEV_BSIZE), du->dk_bc, @@ -893,7 +912,7 @@ wdstart(int ctrlr) } if ((du->dk_flags & (DKFL_DMA|DKFL_SINGLE)) == DKFL_DMA) { - wddma.wdd_dmaprep(du->dk_dmacookie, + wddma[du->dk_interface].wdd_dmaprep(du->dk_dmacookie, (void *)((int)bp->b_un.b_addr + du->dk_skip * DEV_BSIZE), du->dk_bc, @@ -909,7 +928,7 @@ wdstart(int ctrlr) printf("cylin %ld head %ld sector %ld addr %x sts %x\n", cylin, head, sector, (int)bp->b_un.b_addr + du->dk_skip * DEV_BSIZE, - inb(du->dk_port + wd_altsts)); + inb(du->dk_altport)); #endif } @@ -937,7 +956,7 @@ wdstart(int ctrlr) /* 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) { - wddma.wdd_dmastart(du->dk_dmacookie); + wddma[du->dk_interface].wdd_dmastart(du->dk_dmacookie); return; } @@ -1049,10 +1068,10 @@ wdintr(int unit) /* finish off DMA */ if (du->dk_flags & (DKFL_DMA|DKFL_USEDMA)) { /* XXX SMP boxes sometimes generate an early intr. Why? */ - if ((wddma.wdd_dmastatus(du->dk_dmacookie) & WDDS_INTERRUPT) + if ((wddma[du->dk_interface].wdd_dmastatus(du->dk_dmacookie) & WDDS_INTERRUPT) == 0) return; - dmastat = wddma.wdd_dmadone(du->dk_dmacookie); + dmastat = wddma[du->dk_interface].wdd_dmadone(du->dk_dmacookie); } du->dk_timeout = 0; @@ -1834,20 +1853,22 @@ failed: du->dk_multi = wp->wdp_nsecperint & 0xff; wdsetmulti(du); - du->dk_dmacookie = NULL; /* * check drive's DMA capability */ + if (wddma[du->dk_interface].wdd_candma) { + du->dk_dmacookie = wddma[du->dk_interface].wdd_candma(du->dk_port, du->dk_ctrlr); /* does user want this? */ - if ((du->cfg_flags & WDOPT_DMA) && + if ((du->cfg_flags & WDOPT_DMA) && /* have we got a DMA controller? */ - (wddma.wdd_candma && - (du->dk_dmacookie = wddma.wdd_candma(du->dk_port, - du->dk_unit))) && - /* can said drive do DMA? */ - (wddma.wdd_dmainit(du->dk_dmacookie, wp, wdsetmode, du))) - - du->dk_flags |= DKFL_USEDMA; + du->dk_dmacookie && + /* can said drive do DMA? */ + wddma[du->dk_interface].wdd_dmainit(du->dk_dmacookie, wp, wdsetmode, du)) { + du->dk_flags |= DKFL_USEDMA; + } + } else { + du->dk_dmacookie = NULL; + } #ifdef WDDEBUG printf( @@ -2210,28 +2231,28 @@ wdflushirq(struct disk *du, int old_ipl) static int wdreset(struct disk *du) { - int wdc, err = 0; + int err = 0; if ((du->dk_flags & (DKFL_DMA|DKFL_USEDMA)) && du->dk_dmacookie) - wddma.wdd_dmadone(du->dk_dmacookie); + wddma[du->dk_interface].wdd_dmadone(du->dk_dmacookie); - wdc = du->dk_port; (void)wdwait(du, 0, TIMEOUT); - outb(wdc + wd_ctlr, WDCTL_IDS | WDCTL_RST); + outb(du->dk_altport, WDCTL_IDS | WDCTL_RST); DELAY(10 * 1000); - outb(wdc + wd_ctlr, WDCTL_IDS); + outb(du->dk_altport, WDCTL_IDS); #ifdef ATAPI if (wdwait(du, WDCS_READY | WDCS_SEEKCMPLT, TIMEOUT) != 0) err = 1; /* no IDE drive found */ - du->dk_error = inb(wdc + wd_error); + du->dk_error = inb(du->dk_port + wd_error); if (du->dk_error != 0x01) err = 1; /* the drive is incompatible */ #else - if (wdwait(du, WDCS_READY | WDCS_SEEKCMPLT, TIMEOUT) != 0 - || (du->dk_error = inb(wdc + wd_error)) != 0x01) + if (wdwait(du, WDCS_READY | WDCS_SEEKCMPLT, TIMEOUT) != 0) { + printf("wdreset: error1: 0x%x\n", du->dk_error); return (1); + } #endif - outb(wdc + wd_ctlr, WDCTL_4BIT); + outb(du->dk_altport, WDCTL_4BIT); return (err); } @@ -2273,7 +2294,7 @@ wdtimeout(void *cdu) if (du->dk_dmacookie) printf("wd%d: wdtimeout() DMA status %b\n", du->dk_lunit, - wddma.wdd_dmastatus(du->dk_dmacookie), + wddma[du->dk_interface].wdd_dmastatus(du->dk_dmacookie), WDDS_BITS); } wdunwedge(du); @@ -2384,8 +2405,9 @@ wdwait(struct disk *du, u_char bits_wanted, int timeout) * command completion. */ } - if ((status & bits_wanted) == bits_wanted) + if ((status & bits_wanted) == bits_wanted) { return (status & WDCS_ERR); + } } if (timeout < TIMEOUT) /* diff --git a/sys/i386/isa/wdreg.h b/sys/i386/isa/wdreg.h index 9bb2f9b..0b37456 100644 --- a/sys/i386/isa/wdreg.h +++ b/sys/i386/isa/wdreg.h @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * from: @(#)wdreg.h 7.1 (Berkeley) 5/9/91 - * $Id: wdreg.h,v 1.12.2.3 1997/01/14 17:32:07 bde Exp $ + * $Id: wdreg.h,v 1.19 1997/09/04 18:49:48 sos Exp $ */ /* @@ -260,7 +260,7 @@ int wdformat(struct buf *bp); * WDDS_* constants below. */ struct wddma { - void *(*wdd_candma) /* returns a cookie if can do DMA */ + void *(*wdd_candma) /* returns a cookie if PCI */ __P((int ctlr, int drive)); int (*wdd_dmaverify) /* verify that request is DMA-able */ __P((void *cookie, char *vaddr, u_long len, int direction)); @@ -277,6 +277,10 @@ struct wddma { struct wdparams *wp, int(wdcmd)__P((int mode, void *wdinfo)), void *wdinfo)); + int (*wdd_iobase) /* returns iobase address */ + __P((void *cookie)); + int (*wdd_altiobase) /* returns altiobase address */ + __P((void *cookie)); }; /* logical status bits returned by wdd_dmastatus */ @@ -305,6 +309,6 @@ struct wddma { #define WDDMA_UDMA1 0x41 #define WDDMA_UDMA2 0x42 -extern struct wddma wddma; +extern struct wddma wddma[]; #endif /* KERNEL */ diff --git a/sys/pci/ide_pci.c b/sys/pci/ide_pci.c index 9f16080..b3a301f 100644 --- a/sys/pci/ide_pci.c +++ b/sys/pci/ide_pci.c @@ -26,13 +26,15 @@ * 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.2 1997/08/02 14:33:09 bde Exp $ + * $Id: wd82371.c,v 1.5.2.1 1996/11/16 21:19:51 phk Exp $ */ #include "pci.h" #if NPCI > 0 #include "opt_wd.h" +#include "wd.h" + +#if NWDC > 0 #include <sys/param.h> #include <sys/systm.h> @@ -43,6 +45,8 @@ #include <vm/pmap.h> #include <i386/isa/wdreg.h> +#include <i386/isa/isa.h> +#include <i386/isa/isa_device.h> #include <pci/pcivar.h> #include <pci/pcireg.h> @@ -52,17 +56,19 @@ #define MIN(a,b) (((a)<(b))?(a):(b)) #endif +#define PROMISE_ULTRA33 0x4d33105a + struct ide_pci_cookie; /* structs vendor_fns, ide_pci_cookie are recursive */ struct vendor_fns { int (*vendor_dmainit) /* initialize DMA controller and drive */ - (struct ide_pci_cookie *cookie, - struct wdparams *wp, - int(*wdcmd)(int, void *), - void *); + (struct ide_pci_cookie *cookie, + struct wdparams *wp, + int (*wdcmd)(int, void *), + void *); - void (*vendor_status) /* prints off DMA timing info */ - (struct ide_pci_cookie *cookie); + void (*vendor_status) /* prints off DMA timing info */ + (struct ide_pci_cookie *cookie); }; /* @@ -75,77 +81,93 @@ 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; - pcidi_t type; - struct ide_pci_prd *prd; - struct vendor_fns vs; + LIST_ENTRY(ide_pci_cookie) le; + int iobase_wd; + int ctlr; /* controller 0/1 on PCI IDE interface */ + int unit; + int iobase_bm; /* SFF-8038 control registers */ + int altiobase_wd; + pcici_t tag; + pcidi_t type; + struct ide_pci_prd *prd; + struct vendor_fns vs; }; struct ide_pci_softc { - LIST_HEAD(, ide_pci_cookie) cookies; + LIST_HEAD(, ide_pci_cookie) cookies; }; static int -generic_dmainit(struct ide_pci_cookie *cookie, - struct wdparams *wp, - int(*wdcmd)(int, void *), - void *wdinfo); +generic_dmainit(struct ide_pci_cookie *cookie, + struct wdparams *wp, + int (*wdcmd)(int, void *), + void *wdinfo); + static void generic_status(struct ide_pci_cookie *cookie); static void via_571_status(struct ide_pci_cookie *cookie); +static int +via_571_dmainit(struct ide_pci_cookie *cookie, + struct wdparams *wp, + int (*wdcmd)(int, void *), + void *wdinfo); + static void -intel_piix_dump_drive(char *ctlr, - int sitre, - int is_piix4, - int word40, - int word44, - int word48, - int word4a, - int drive); +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(struct ide_pci_cookie *cookie); static int -intel_piix_dmainit(struct ide_pci_cookie *cookie, - struct wdparams *wp, - int(*wdcmd)(int, void *), - void *wdinfo); +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, - pcidi_t type, - struct vendor_fns *vp); +mkcookie(int iobase_wd, + int ctlr, + int unit, + int iobase_bm, + pcici_t tag, + pcidi_t type, + struct vendor_fns *vp, + int altiobase_wd); static void ide_pci_attach(pcici_t tag, int unit); static void *ide_pci_candma(int, int); static int ide_pci_dmainit(void *, - struct wdparams *, - int (*)(int, void *), - void *); + struct wdparams *, + int (*)(int, void *), + void *); + static int ide_pci_dmaverify(void *, char *, u_long, int); static int ide_pci_dmasetup(void *, char *, u_long, int); static void ide_pci_dmastart(void *); static int ide_pci_dmadone(void *); static int ide_pci_status(void *); static int ide_pci_timing(void *, int); +static int ide_pci_iobase(void *xcp); +static int ide_pci_altiobase(void *xcp); static struct ide_pci_softc softc; static int ide_pci_softc_cookies_initted = 0; +extern void wdintr(void *); +extern struct isa_driver wdcdriver; + /* * PRD_ALLOC_SIZE should be something that will not be allocated across a 64k * boundary. @@ -166,6 +188,58 @@ static void *prdbuf_next = 0; * encapsulated here. */ +/* helper funcs */ + +/* + * nnn_mode() return the highest valid mode, or -1 if the mode class is + * not supported + */ + +static inline int +pio_mode(struct wdparams *wp) +{ + if ((wp->wdp_atavalid & 2) == 2) { + if ((wp->wdp_eidepiomodes & 2) == 2) return 4; + if ((wp->wdp_eidepiomodes & 1) == 1) return 3; + } + return -1; +} + +#if 0 +static inline int +dma_mode(struct wdparams *wp) +{ + /* XXX not quite sure how to verify validity on this field */ +} +#endif + +static inline int +mwdma_mode(struct wdparams *wp) +{ + /* + * XXX technically, using wdp_atavalid to test for validity of + * this field is not quite correct + */ + if ((wp->wdp_atavalid & 2) == 2) { + if ((wp->wdp_dmamword & 4) == 4) return 2; + if ((wp->wdp_dmamword & 2) == 2) return 1; + if ((wp->wdp_dmamword & 1) == 1) return 0; + } + return -1; +} + +static inline int +udma_mode(struct wdparams *wp) +{ + if ((wp->wdp_atavalid & 4) == 4) { + if ((wp->wdp_udmamode & 4) == 4) return 2; + if ((wp->wdp_udmamode & 2) == 2) return 1; + if ((wp->wdp_udmamode & 1) == 1) return 0; + } + return -1; +} + + /* Generic busmastering PCI-IDE */ static int @@ -174,35 +248,42 @@ generic_dmainit(struct ide_pci_cookie *cookie, int(*wdcmd)(int, void *), void *wdinfo) { - /* - * 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. - */ - /* 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 == 4)))) - return 0; + /* + * 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. + * + * XXX there are examples where this approach is now known to be + * broken, at least on systems based on Intel chipsets. + */ - return 1; + if ((pio_mode(wp) >= 4 && mwdma_mode(wp) >= 2) || + (udma_mode(wp) >= 2)) { + printf("ide_pci: generic_dmainit %04x:%d: warning, IDE controller timing not set\n", + cookie->iobase_wd, + cookie->unit); + return 1; + } +#ifdef IDE_PCI_DEBUG + printf("pio_mode: %d, mwdma_mode(wp): %d, udma_mode(wp): %d\n", + pio_mode(wp), mwdma_mode(wp), udma_mode(wp)); +#endif + return 0; } static void generic_status(struct ide_pci_cookie *cookie) { - printf("generic_status: no PCI IDE timing info available\n"); + printf("generic_status: no PCI IDE timing info available\n"); } static struct vendor_fns vs_generic = { - generic_dmainit, - generic_status + generic_dmainit, + generic_status }; /* VIA Technologies "82C571" PCI-IDE controller core */ @@ -210,60 +291,250 @@ static struct vendor_fns vs_generic = static void 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; + int iobase_wd; + int ctlr, unit; + int iobase_bm; + pcici_t tag; + pcidi_t type; + u_long word40[5]; + int i, unitno; + + iobase_wd = cookie->iobase_wd; + unit = cookie->unit; + ctlr = cookie->ctlr; + iobase_bm = cookie->iobase_bm; + tag = cookie->tag; + type = cookie->type; + + unitno = ctlr * 2 + unit; + + for (i=0; i<5; i++) { + word40[i] = pci_conf_read(tag, i * 4 + 0x40); + } - iobase_wd = cookie->iobase_wd; - unit = cookie->unit; - iobase_bm = cookie->iobase_bm; - tag = cookie->tag; - type = cookie->type; + if (ctlr == 0) + printf("via_571_status: Primary IDE prefetch/postwrite %s/%s\n", + word40[0] & 0x8000 ? "enabled" : "disabled", + word40[0] & 0x4000 ? "enabled" : "disabled"); + else + printf("via_571_status: Secondary IDE prefetch/postwrite %s/%s\n", + word40[0] & 0x2000 ? "enabled" : "disabled", + word40[0] & 0x1000 ? "enabled" : "disabled"); - /* XXX how to handle four calls for one controller? */ - if (iobase_wd != 0x1f0 || unit != 0) - return; + printf("via_571_status: busmaster status read retry %s\n", + (word40[1] & 0x08) ? "enabled" : "disabled"); - for (i=0; i<5; i++) { - word40[i] = pci_conf_read(tag, i * 4 + 0x40); - } + + printf("via_571_status: %s drive %d data setup=%d active=%d recovery=%d\n", + unitno < 2 ? "primary" : "secondary", + unitno & 1, + ((word40[3] >> ((3 - unitno) * 2)) & 3) + 1, + ((word40[2] >> (((3 - unitno) * 8) + 4)) & 0x0f) + 1, + ((word40[2] >> ((3 - unitno) * 8)) & 0x0f) + 1); + + if (ctlr == 0) + printf("via_571_status: primary ctrl active=%d recovery=%d\n", + ((word40[3] >> 28) & 0x0f) + 1, + ((word40[2] >> 24) & 0x0f) + 1); + else + printf("via_571_status: secondary ctrl active=%d recovery=%d\n", + ((word40[3] >> 20) & 0x0f) + 1, + ((word40[2] >> 16) & 0x0f) + 1); + + /* UltraDMA dump */ + { + int foo; + + foo = word40[4] >> ((3 - unitno) * 8); + printf("via_571_status: %s drive %d udma method=%d enable=%d PIOmode=%d cycle=%d\n", + i < 2 ? "primary" : "secondary", + i & 1, + (foo >> 7) & 1, + (foo >> 6) & 1, + (foo >> 5) & 1, + (foo & 3) + 2); + } +} + +/* + * XXX timing values set here are only good for 30/33MHz buses; should deal + * with slower ones too (BTW: you overclock-- you lose) + */ + +static int +via_571_dmainit(struct ide_pci_cookie *cookie, + struct wdparams *wp, + int(*wdcmd)(int, void *), + void *wdinfo) +{ + int r; + u_long pci_revision; + int unitno; + + pci_revision = pci_conf_read(cookie->tag, PCI_CLASS_REG) & + PCI_REVISION_MASK; + + unitno = cookie->ctlr * 2 + cookie->unit; + + /* If it's a UDMA drive on a '590, set it up */ + /* + * XXX the revision number we check for is of dubious validity. + * it's extracted from the AMD 645 datasheet. + */ + if (pci_revision >= 1 && udma_mode(wp) >= 2) { + unsigned int word50, mask, new; + word50 = pci_conf_read(cookie->tag, 0x50); + + /* UDMA enable by SET FEATURES, DMA cycles, cycle time 2T */ + mask = 0xe3000000 >> (unitno * 8); + new = 0x80000000 >> (unitno * 8); + + word50 &= ~mask; + word50 |= new; + + pci_conf_write(cookie->tag, 0x50, word50); + + /* + * With the '590, drive configuration should come *after* the + * controller configuration, to make sure the controller sees + * the SET FEATURES command and does the right thing. + */ + /* Set UDMA mode 2 on drive */ + 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; + } + + if (bootverbose) + via_571_status(cookie); + return 1; + + } - printf("via_571_status: Primary IDE prefetch/postwrite %s/%s\n", - word40[0] & 0x8000 ? "enabled" : "disabled", - word40[0] & 0x4000 ? "enabled" : "disabled"); - printf("via_571_status: Secondary IDE prefetch/postwrite %s/%s\n", - word40[0] & 0x2000 ? "enabled" : "disabled", - word40[0] & 0x1000 ? "enabled" : "disabled"); - - printf("via_571_status: Master %d read/%d write IRDY# wait states\n", - (word40[1] & 0x40) >> 6, - (word40[1] & 0x20) >> 5); - printf("via_571_status: busmaster status read retry %s\n", - (word40[1] & 0x10) ? "enabled" : "disabled"); - - for (i=0; i<4; i++) - printf("via_571_status: %s drive %d setup=%d active=%d recovery=%d\n", - i < 2 ? "primary" : "secondary", - i & 1, - ((word40[3] >> ((3 - i) * 2)) & 3) + 1, - ((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 */ + /* otherwise, try and program it for MW DMA mode 2 */ + else if (mwdma_mode(wp) >= 2 && pio_mode(wp) >= 4) { + u_long workword; + + /* Set multiword DMA mode 2 on drive */ + 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; + } + + /* Configure the controller appropriately for MWDMA mode 2 */ + + workword = pci_conf_read(cookie->tag, 0x40); + + /* + * enable prefetch/postwrite-- XXX may cause problems + * with CD-ROMs? + */ + workword &= ~(3 << (cookie->ctlr * 2 + 12)); + workword |= 3 << (cookie->ctlr * 2 + 12); + + /* FIFO configurations-- equal split, threshold 1/2 */ + workword &= 0x90ffffff; + workword |= 0x2a000000; + + pci_conf_write(cookie->tag, 0x40, workword); + + workword = pci_conf_read(cookie->tag, 0x44); + + /* enable status read retry */ + workword |= 8; + + /* enable FIFO flush on interrupt and end of sector */ + workword &= 0xff0cffff; + workword |= 0x00f00000; + pci_conf_write(cookie->tag, 0x44, workword); + + workword = pci_conf_read(cookie->tag, 0x48); + /* set Mode2 timing */ + workword &= ~(0xff000000 >> (unitno * 8)); + workword |= 0x31000000 >> (unitno * 8); + pci_conf_write(cookie->tag, 0x48, workword); + + /* set sector size */ + pci_conf_write(cookie->tag, cookie->ctlr ? 0x68 : 0x60, 0x200); + + if (bootverbose) + via_571_status(cookie); + + return 1; + + } + return 0; } + static struct vendor_fns vs_via_571 = { + via_571_dmainit, + via_571_status +}; + + +static void +promise_status(struct ide_pci_cookie *cookie) +{ + pcici_t tag; + int i,j; + u_int32_t port0_command, port0_altstatus; + u_int32_t port1_command, port1_altstatus; + u_int32_t dma_block; + + u_int32_t lat_and_interrupt; + u_int32_t drivetiming; + int pa, pb, mb, mc; + + tag = cookie->tag; + port0_command = pci_conf_read(tag, 0x10); + port0_altstatus = pci_conf_read(tag, 0x14); + port1_command = pci_conf_read(tag, 0x18); + port1_altstatus = pci_conf_read(tag, 0x1c); + + dma_block = pci_conf_read(tag, 0x20); + lat_and_interrupt = pci_conf_read(tag, 0x3c); + + printf("promise_status: port0: 0x%lx, port0_alt: 0x%lx, port1: 0x%lx, port1_alt: 0x%lx\n", + port0_command, port0_altstatus, port1_command, port1_altstatus); + printf("promise_status: dma control blk address: 0x%lx, int: %d, irq: %d\n", + dma_block, (lat_and_interrupt >> 8) & 0xff, lat_and_interrupt & 0xff); + + for(i=0;i<4;i+=2) { + drivetiming = pci_conf_read(tag, 0x60 + i * 4); + printf("drivebits%d-%d: %b\n", i, i+1, drivetiming, + "\020\05Prefetch\06Iordy\07Errdy\010Sync\025DmaW\026DmaR"); + pa = drivetiming & 0xf; + pb = (drivetiming >> 8) & 0x1f; + mb = (drivetiming >> 13) & 0x7; + mc = (drivetiming >> 16) & 0xf; + printf("drivetiming%d: pa: 0x%x, pb: 0x%x, mb: 0x%x, mc: 0x%x\n", + i, pa, pb, mb, mc); + + drivetiming = pci_conf_read(tag, 0x60 + (i + 1) * 4); + pa = drivetiming & 0xf; + pb = (drivetiming >> 8) & 0x1f; + mb = (drivetiming >> 13) & 0x7; + mc = (drivetiming >> 16) & 0xf; + printf("drivetiming%d: pa: 0x%x, pb: 0x%x, mb: 0x%x, mc: 0x%x\n", + i + 1, pa, pb, mb, mc); + } +} + +static struct vendor_fns vs_promise = +{ generic_dmainit, - via_571_status + promise_status }; /* Intel PIIX, PIIX3, and PIIX4 IDE controller subfunctions */ - static void intel_piix_dump_drive(char *ctlr, int sitre, @@ -274,16 +545,15 @@ intel_piix_dump_drive(char *ctlr, int word4a, int drive) { - char *ms; + char *ms; - if (!sitre) - ms = "master/slave"; - else if (drive == 0) - ms = "master"; - else - ms = "slave"; + if (!sitre) + ms = "master/slave"; + else if (drive == 0) + ms = "master"; + else + ms = "slave"; - if (sitre || drive == 0) printf("intel_piix_status: %s %s sample = %d, %s recovery = %d\n", ctlr, ms, @@ -295,217 +565,270 @@ intel_piix_dump_drive(char *ctlr, ((word44 >> 0) & 3) : ((word40 >> 8) & 3))); - word40 >>= (drive * 4); - printf("\ -intel_piix_status: %s %s fastDMAonly %s, pre/post %s,\n\ + word40 >>= (drive * 4); + printf("intel_piix_status: %s %s fastDMAonly %s, pre/post %s,\n\ intel_piix_status: IORDY sampling %s,\n\ intel_piix_status: fast PIO %s%s\n", - ctlr, - (drive == 0) ? "master" : "slave", - (word40 & 8) ? "enabled" : "disabled", - (word40 & 4) ? "enabled" : "disabled", - (word40 & 2) ? "enabled" : "disabled", - (word40 & 1) ? "enabled" : "disabled", - ((word40 & 9) == 9) ? " (overridden by fastDMAonly)" : "" ); - - if (is_piix4) - printf("intel_piix_status: UltraDMA %s, CT/RP = %d/%d\n", - word48 ? "enabled": "disabled", - 4 - (word4a & 3), - 6 - (word4a & 3)); - + ctlr, + (drive == 0) ? "master" : "slave", + (word40 & 8) ? "enabled" : "disabled", + (word40 & 4) ? "enabled" : "disabled", + (word40 & 2) ? "enabled" : "disabled", + (word40 & 1) ? "enabled" : "disabled", + ((word40 & 9) == 9) ? " (overridden by fastDMAonly)" : "" ); + + 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(struct ide_pci_cookie *cookie) { - 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; - - 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; - - 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); - } + int iobase_wd; + int unit; + int iobase_bm; + pcici_t tag; + pcidi_t type; + int ctlr; + u_long word40, word44, word48; + int sitre, is_piix4; + + 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; + + switch (ctlr * 2 + unit) { + case 0: + intel_piix_dump_drive("primary", + sitre, + is_piix4, + word40 & 0xffff, + word44 & 0x0f, + word48, + word48 >> 16, + 0); + break; + case 1: + intel_piix_dump_drive("primary", + sitre, + is_piix4, + word40 & 0xffff, + word44 & 0x0f, + word48 >> 1, + word48 >> 20, + 1); + break; + case 2: + intel_piix_dump_drive("secondary", + sitre, + is_piix4, + (word40 >> 16) & 0xffff, + (word44 >> 4) & 0x0f, + word48 >> 2, + word48 >> 24, + 0); + break; + case 3: + intel_piix_dump_drive("secondary", + sitre, + is_piix4, + (word40 >> 16) & 0xffff, + (word44 >> 4) & 0x0f, + word48 >> 3, + word48 >> 28, + 1); + break; + default: + printf("intel_piix_status: bad drive or controller number\n"); + } } +/* + * XXX timing values set hereare only good for 30/33MHz buses; should deal + * with slower ones too (BTW: you overclock-- you lose) + */ + static int intel_piix_dmainit(struct ide_pci_cookie *cookie, - struct wdparams *wp, - int(*wdcmd)(int, void *), - void *wdinfo) + 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; - } + int r; - unitno = cookie->ctlr * 2 + cookie->unit; + /* If it's a UDMA drive and a PIIX4, set it up */ + if (cookie->type == 0x71118086 && udma_mode(wp) >= 2) { + /* Set UDMA mode 2 on controller */ + int unitno, mask, new; - mask = 1 << unitno + 3 << (16 + unitno * 4); - new = 1 << unitno + 2 << (16 + unitno * 4); + if (bootverbose) + printf("intel_piix_dmainit: setting ultra DMA mode 2\n"); - 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; - } + 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 (bootverbose) + intel_piix_status(cookie); + return 1; + } /* - * backward compatible hardware leaves us with such twisted masses - * of software (aka twiddle the extremely weird register layout on - * a PIIX3) + * if it's an 82371FB, which can't do independent programming of + * drive timing, we punt; we're not going to fuss with trying to + * coordinate timing modes between drives. if this is you, get a + * new motherboard. or contribute patches :) + * + * we do now at least see if the modes set are OK to use. this should + * satisfy the majority of people, with mwdma mode2 drives. */ - if (cookie->unit == 0) { - mask40 = 0x330f; - new40 = 0x2307; - mask44 = 0; - new44 = 0; - } - else { - mask40 = 0x00f0; - new40 = 0x0070; - mask44 = 0x000f; - new44 = 0x000b; + else if (cookie->type == 0x12308086) + { + u_long word40; + + /* can drive do PIO 4 and MW DMA 2? */ + if (!(mwdma_mode(wp) >= 4 && pio_mode(wp) >= 4)) + return 0; + + word40 = pci_conf_read(cookie->tag, 0x40); + word40 >>= cookie->ctlr * 16; + + /* Check for timing config usable for DMA on controller */ + if (!((word40 & 0x3300) == 0x2300 && + ((word40 >> (cookie->unit * 4)) & 1) == 1)) + return 0; + + /* Set multiword DMA mode 2 on drive */ + 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; + } + return 1; } - if (cookie->ctlr) { - mask40 <<= 16; - new40 <<= 16; - mask44 <<= 4; - new44 <<= 4; + + /* otherwise, treat it as a PIIX3 and program it for MW DMA mode 2 */ + else if (mwdma_mode(wp) >= 2 && pio_mode(wp) >= 4) { + u_long mask40, mask44, new40, new44; + + /* + * If SITRE is not set, set it and copy the + * appropriate bits into the secondary registers. Do + * both controllers at once. + */ + if (((pci_conf_read(cookie->tag, 0x40) >> (16 * cookie->ctlr)) + & 0x4000) == 0) { + unsigned int word40, word44; + + word40 = pci_conf_read(cookie->tag, 0x40); + + /* copy bits to secondary register */ + word44 = pci_conf_read(cookie->tag, 0x44); + /* + * I've got a Biostar motherboard with Award + * BIOS that sets SITRE and secondary timing + * on one controller but not the other. + * Bizarre. + */ + if ((word40 & 0x4000) == 0) { + word44 &= ~0xf; + word44 |= ((word40 & 0x3000) >> 10) | + ((word40 & 0x0300) >> 8); + } + if ((word40 & 0x40000000) == 0) { + word44 &= ~0xf0; + word44 |= ((word40 & 0x30000000) >> 22) | + ((word40 & 0x03000000) >> 20); + } + /* set SITRE */ + word40 |= 0x40004000; + + pci_conf_write(cookie->tag, 0x40, word40); + pci_conf_write(cookie->tag, 0x44, word44); + } + + /* Set multiword DMA mode 2 on drive */ + 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, setting + * PIO mode 4 and MWDMA mode 2) + */ + 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; } - 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; + return 0; } static struct vendor_fns vs_intel_piix = { - intel_piix_dmainit, - intel_piix_status + intel_piix_dmainit, + intel_piix_status }; /* Generic SFF-8038i code-- all code below here, except for PCI probes, @@ -517,214 +840,343 @@ 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, - pcidi_t type, - struct vendor_fns *vp) + int ctlr, + int unit, + int iobase_bm, + pcici_t tag, + pcidi_t type, + struct vendor_fns *vp, + int altiobase_wd) { - struct ide_pci_cookie *cp; + struct ide_pci_cookie *cp; - cp = malloc(sizeof *cp, M_DEVBUF, M_NOWAIT); - if (!cp) return cp; + cp = malloc(sizeof *cp, M_DEVBUF, M_NOWAIT); + if (!cp) return 0; - cp->iobase_wd = iobase_wd; - cp->ctlr = ctlr; - cp->unit = unit; - cp->tag = tag; - cp->type = type; - cp->iobase_bm = iobase_bm; - bcopy(vp, &cp->vs, sizeof(struct vendor_fns)); + cp->iobase_wd = iobase_wd; + cp->ctlr = ctlr; + cp->unit = unit; + cp->tag = tag; + cp->type = type; + cp->iobase_bm = iobase_bm; + cp->altiobase_wd = altiobase_wd; + bcopy(vp, &cp->vs, sizeof(struct vendor_fns)); - if (!prdbuf) { - prdbuf = malloc(PRD_ALLOC_SIZE, M_DEVBUF, M_NOWAIT); if (!prdbuf) { - FREE(cp, M_DEVBUF); - return 0; + prdbuf = malloc(PRD_ALLOC_SIZE, M_DEVBUF, M_NOWAIT); + if (!prdbuf) { + FREE(cp, M_DEVBUF); + return 0; + } + if (((int)prdbuf >> PAGE_SHIFT) ^ + (((int)prdbuf + PRD_ALLOC_SIZE - 1) >> PAGE_SHIFT)) { + printf("ide_pci: prdbuf straddles page boundary, no DMA\n"); + FREE(cp, M_DEVBUF); + FREE(prdbuf, M_DEVBUF); + return 0; + } + + prdbuf_next = prdbuf; } - if (((int)prdbuf >> PAGE_SHIFT) ^ - (((int)prdbuf + PRD_ALLOC_SIZE - 1) >> PAGE_SHIFT)) { - printf("ide_pci: prdbuf straddles page boundary, no DMA\n"); - FREE(cp, M_DEVBUF); - FREE(prdbuf, M_DEVBUF); - return 0; + if (((char *)prdbuf_next + PRD_BUF_SIZE) > + ((char *)prdbuf + PRD_ALLOC_SIZE)) { + printf("ide_pci: mkcookie %04x:%d: no more space for PRDs, no DMA\n", + iobase_wd, unit); + FREE(cp, M_DEVBUF); + return 0; } - prdbuf_next = prdbuf; - } - cp->prd = prdbuf_next; - (char *)prdbuf_next += PRD_BUF_SIZE; - - 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; - } + cp->prd = prdbuf_next; + (char *)prdbuf_next += PRD_BUF_SIZE; -#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; + LIST_INSERT_HEAD(&softc.cookies, cp, le); + return cp; } static char * ide_pci_probe(pcici_t tag, pcidi_t type) { - int data = pci_conf_read(tag, PCI_CLASS_REG); - - 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)"); + u_long data; + + data = pci_conf_read(tag, PCI_CLASS_REG); + + if ((data & PCI_CLASS_MASK) == PCI_CLASS_MASS_STORAGE && + ((data & PCI_SUBCLASS_MASK) == 0x00010000 || + ((data & PCI_SUBCLASS_MASK) == 0x00040000))) { + 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 == PROMISE_ULTRA33) + return ("Promise Ultra/33 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)"); + /* + * XXX the CMD640B hack should be better integrated, or + * something. + */ + else + return ("PCI IDE controller (not busmaster capable)"); #endif - }; - return ((char*)0); + }; + return ((char*)0); } static void ide_pci_attach(pcici_t tag, int unit) { - u_long idetm; - int class; - 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; - - /* is it busmaster capable? bail if not */ - class = pci_conf_read(tag, PCI_CLASS_REG); - if (!(class & 0x8000)) return; - - /* is it enabled and is busmastering turned on? */ - cmd = pci_conf_read(tag, PCI_COMMAND_STATUS_REG); - if ((cmd & 5) != 5) return; - - /* set up vendor-specific stuff */ - type = pci_conf_read(tag, PCI_ID_REG); - - switch (type) { - case 0x71118086: - case 0x70108086: - case 0x12308086: - /* Intel PIIX, PIIX3, PIIX4 */ - vp = &vs_intel_piix; - break; - - case 0x5711106: - /* VIA Apollo chipset family */ - vp = &vs_via_571; - break; - - default: - /* everybody else */ - vp = &vs_generic; - break; - } + u_long idetm; + u_long class, cmd; + int bmista_1, bmista_2; + int iobase_wd_1, iobase_wd_2, iobase_bm_1, iobase_bm_2; + int altiobase_wd_1, altiobase_wd_2; + struct vendor_fns *vp; + pcidi_t type; + struct ide_pci_cookie *cookie; + int ctlridx; + + ctlridx = unit * 2; + + /* set up vendor-specific stuff */ + type = pci_conf_read(tag, PCI_ID_REG); + + if (type != PROMISE_ULTRA33) { + /* is it busmaster capable? bail if not */ + class = pci_conf_read(tag, PCI_CLASS_REG); + if (!(class & 0x8000)) { + return; + } + + /* is it enabled and is busmastering turned on? */ + cmd = pci_conf_read(tag, PCI_COMMAND_STATUS_REG); + if ((cmd & 5) != 5) { + return; + } + } - iobase_wd_1 = (class & 0x100) ? - (pci_conf_read(tag, 0x10) & 0xfffc) : - 0x1f0; - iobase_bm_1 = pci_conf_read(tag, 0x20) & 0xfffc; + switch (type) { + case 0x71118086: + case 0x70108086: + case 0x12308086: + /* Intel PIIX, PIIX3, PIIX4 */ + vp = &vs_intel_piix; + break; + + case 0x5711106: + /* VIA Apollo chipset family */ + vp = &vs_via_571; + break; + + case PROMISE_ULTRA33: + /* Promise controllers */ + vp = &vs_promise; + break; + + default: + /* everybody else */ + vp = &vs_generic; + break; + } - iobase_wd_2 = (class & 0x400) ? - (pci_conf_read(tag, 0x10) & 0xfffc) : - 0x170; - iobase_bm_2 = iobase_bm_1 + SFF8038_CTLR_1; + if (type != PROMISE_ULTRA33) { + if ((class & 0x100) == 0) { + iobase_wd_1 = IO_WD1; + altiobase_wd_1 = iobase_wd_1 + wd_altsts; + } else { + iobase_wd_1 = pci_conf_read(tag, 0x10) & 0xfffc; + altiobase_wd_1 = pci_conf_read(tag, 0x14) & 0xfffc; + } + + if ((class & 0x400) == 0) { + iobase_wd_2 = IO_WD2; + altiobase_wd_2 = iobase_wd_2 + wd_altsts; + } else { + iobase_wd_2 = pci_conf_read(tag, 0x18) & 0xfffc; + altiobase_wd_2 = pci_conf_read(tag, 0x1c) & 0xfffc; + } + } else { + iobase_wd_1 = pci_conf_read(tag, 0x10) & 0xfffc; + altiobase_wd_1 = pci_conf_read(tag, 0x14) & 0xfffc; + iobase_wd_2 = pci_conf_read(tag, 0x18) & 0xfffc; + altiobase_wd_2 = pci_conf_read(tag, 0x1c) & 0xfffc; + } - if (iobase_bm_1 == 0) { - printf("ide_pci: BIOS has not configured busmaster I/O address,\n" - "ide_pci: giving up\n"); - return; - } + iobase_bm_1 = pci_conf_read(tag, 0x20) & 0xfffc; + iobase_bm_2 = iobase_bm_1 + SFF8038_CTLR_1; + 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; - wddma.wdd_dmainit = ide_pci_dmainit; - wddma.wdd_dmaverify = ide_pci_dmaverify; - wddma.wdd_dmaprep = ide_pci_dmasetup; - wddma.wdd_dmastart = ide_pci_dmastart; - wddma.wdd_dmadone = ide_pci_dmadone; - wddma.wdd_dmastatus = ide_pci_status; + wddma[unit].wdd_candma = ide_pci_candma; + wddma[unit].wdd_dmainit = ide_pci_dmainit; + wddma[unit].wdd_dmaverify = ide_pci_dmaverify; + wddma[unit].wdd_dmaprep = ide_pci_dmasetup; + wddma[unit].wdd_dmastart = ide_pci_dmastart; + wddma[unit].wdd_dmadone = ide_pci_dmadone; + wddma[unit].wdd_dmastatus = ide_pci_status; + wddma[unit].wdd_iobase = ide_pci_iobase; + wddma[unit].wdd_altiobase = ide_pci_altiobase; - 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; - } + /* + * This code below is mighty bogus. The config entries for the + * isa_devtab_bio are plugged in before the standard ISA bios scan. + * This is our "hack" way to simulate a dynamic assignment of I/O + * addresses, from a PCI device to an ISA probe. Sorry :-). + */ + if (iobase_wd_1 != IO_WD1) { + struct isa_device *dvp, *dvp1, *dvup, *dvup1; + for( dvp = isa_devtab_bio; + dvp->id_id != 0; + dvp++) { + if ((dvp->id_driver == &wdcdriver) && (dvp->id_iobase == 0)) { + int biotabunit; + biotabunit = dvp->id_unit * 2; + dvp->id_iobase = iobase_wd_1; + dvp1 = dvp + 1; + dvp1->id_iobase = iobase_wd_2; + printf("ide_pci%d: adding drives to controller %d:", + unit, biotabunit); + for(dvup = isa_biotab_wdc; + dvup->id_id != 0; + dvup++) { + if (dvup->id_driver != &wdcdriver) + continue; + if (dvup->id_unit != biotabunit) + continue; + + dvup->id_iobase = dvp->id_iobase; + printf(" %d", dvup->id_unit); + dvup++; + + pci_map_int(tag, wdintr, (void *) dvp->id_unit, &bio_imask); + if (dvup->id_id == 0) + break; + + if (dvup->id_unit == biotabunit + 1) { + dvup->id_iobase = dvp->id_iobase; + printf(" %d", dvup->id_unit); + dvup++; + if (dvup->id_id == 0) { + iobase_wd_2 = 0; + break; + } + } + + if (dvup->id_unit == biotabunit + 2) { + pci_map_int(tag, wdintr, (void *) ((int) dvp->id_unit + 1), &bio_imask); + dvup->id_iobase = dvp1->id_iobase; + printf(" %d", dvup->id_unit); + dvup++; + if (dvup->id_id == 0) { + break; + } + } + + if (dvup->id_unit == biotabunit + 3) { + pci_map_int(tag, wdintr, (void *) ((int) dvp->id_unit + 1), &bio_imask); + dvup->id_iobase = dvp1->id_iobase; + printf(" %d", dvup->id_unit); + } + + break; + } + printf("\n"); + break; + } + } + } - 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"); - } - } + 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, + ctlridx, + 0, + iobase_bm_1, + tag, + type, + vp, + altiobase_wd_1); + if (bootverbose) + vp->vendor_status(cookie); + cookie = mkcookie(iobase_wd_1, + ctlridx, + 1, + iobase_bm_1, + tag, + type, + vp, + altiobase_wd_1); + 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, + ctlridx + 1, + 0, + iobase_bm_2, + tag, + type, + vp, + altiobase_wd_2); + if (bootverbose) + vp->vendor_status(cookie); + cookie = mkcookie(iobase_wd_2, + ctlridx + 1, + 1, + iobase_bm_2, + tag, + type, + vp, + altiobase_wd_2); + 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; static struct pci_device ide_pci_device = { - "ide_pci", - ide_pci_probe, - ide_pci_attach, - &ide_pci_count, - 0 + "ide_pci", + ide_pci_probe, + ide_pci_attach, + &ide_pci_count, + 0 }; DATA_SET(pcidevice_set, ide_pci_device); @@ -735,16 +1187,17 @@ DATA_SET(pcidevice_set, ide_pci_device); static void * ide_pci_candma(int iobase_wd, int unit) { - struct ide_pci_cookie *cp; - - cp = softc.cookies.lh_first; - while(cp) { - if (cp->unit == unit && cp->iobase_wd == iobase_wd) - break; - cp = cp->le.le_next; - } + struct ide_pci_cookie *cp; + + cp = softc.cookies.lh_first; + while(cp) { + if (cp->ctlr == unit && + ((iobase_wd == 0) || (cp->iobase_wd == iobase_wd))) + break; + cp = cp->le.le_next; + } - return cp; + return cp; } /* @@ -758,19 +1211,19 @@ ide_pci_dmainit(void *cookie, int(*wdcmd)(int, void *), void *wdinfo) { - 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) & + 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; + return 1; - /* We take a stab at it with device-dependent code */ - return(cp->vs.vendor_dmainit(cp, wp, wdcmd, wdinfo)); + /* We take a stab at it with device-dependent code */ + return(cp->vs.vendor_dmainit(cp, wp, wdcmd, wdinfo)); } + /* * Verify that controller can handle a dma request for cp. Should * not affect any hardware or driver state. @@ -778,19 +1231,19 @@ ide_pci_dmainit(void *cookie, static int ide_pci_dmaverify(void *xcp, char *vaddr, u_long count, int dir) { - int badfu; + int badfu; - /* - * check for nonaligned or odd-length Stuff - */ - badfu = ((unsigned int)vaddr & 1) || (count & 1); + /* + * check for nonaligned or odd-length Stuff + */ + badfu = ((unsigned int)vaddr & 1) || (count & 1); #ifdef DIAGNOSTIC - if (badfu) { - printf("ide_pci: dmaverify odd vaddr or length, "); - printf("vaddr = %08x length = %08x\n", (int)vaddr, count); - } + if (badfu) { + printf("ide_pci: dmaverify odd vaddr or length, "); + printf("vaddr = %08x length = %08x\n", (int)vaddr, count); + } #endif - return (!badfu); + return (!badfu); } /* @@ -801,155 +1254,180 @@ ide_pci_dmaverify(void *xcp, char *vaddr, u_long count, int dir) static int 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 firstpage; - u_long prd_base, prd_count; - u_long nbase, ncount, nend; - int iobase_bm; - static int trashmore = 0xdeadbeef; - static int *trashmore_p = 0; - u_long count, checkcount; - - prd = cp->prd; + struct ide_pci_cookie *cp = xcp; + struct ide_pci_prd *prd; + int i; + u_long firstpage; + u_long prd_base, prd_count; + u_long nbase, ncount, nend; + int iobase_bm; + static int trashmore = 0xdeadbeef; + static int *trashmore_p = 0; + u_long count, checkcount; - count = vcount; + prd = cp->prd; - i = 0; - - iobase_bm = cp->iobase_bm; - - if (count == 0) { - printf("ide_pci: dmasetup 0-length transfer, "); - printf("vaddr = %08x length = %08x\n", (int)vaddr, count); - return 1; - } + count = vcount; - /* Generate first PRD entry, which may be non-aligned. */ + i = 0; - firstpage = PAGE_SIZE - ((u_long)vaddr & PAGE_MASK); + iobase_bm = cp->iobase_bm; - prd_base = vtophys(vaddr); - prd_count = MIN(count, firstpage); - - vaddr += prd_count; - count -= prd_count; - - /* 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 = prd_base; - prd[i].prd_count = (prd_count & 0xffff); - i++; - if (i >= PRD_MAX_SEGS) { - printf("wd82371: too many segments in PRD table\n"); + if (count == 0) { + printf("ide_pci: dmasetup 0-length transfer, "); + printf("vaddr = %08x length = %08x\n", (int)vaddr, count); return 1; - } - prd_base = nbase; - prd_count = ncount; } - vaddr += ncount; - count -= ncount; - } - /* Write last PRD entry. */ - prd[i].prd_base = prd_base; - prd[i].prd_count = (prd_count & 0xffff) | PRD_EOT_BIT; + /* Generate first PRD entry, which may be non-aligned. */ + + firstpage = PAGE_SIZE - ((u_long)vaddr & PAGE_MASK); + + prd_base = vtophys(vaddr); + prd_count = MIN(count, firstpage); + + vaddr += prd_count; + count -= prd_count; + + /* 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 = prd_base; + prd[i].prd_count = (prd_count & 0xffff); + i++; + if (i >= PRD_MAX_SEGS) { + printf("wd82371: too many segments in PRD table\n"); + return 1; + } + prd_base = nbase; + prd_count = ncount; + } + vaddr += ncount; + count -= ncount; + } + + /* Write last PRD entry. */ + prd[i].prd_base = prd_base; + prd[i].prd_count = (prd_count & 0xffff) | PRD_EOT_BIT; #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; + /* 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 (prd[i].prd_count & PRD_EOT_BIT) - break; - } - if (checkcount != vcount) { - printf("ide_pci: dmasetup() diagnostic fails-- bad length\n"); - return 1; - } + 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 up PRD base register */ + outl(iobase_bm + BMIDTP_PORT, vtophys(prd)); - /* Set direction of transfer */ - outb(iobase_bm + BMICOM_PORT, (dir == B_READ) ? BMICOM_READ_WRITE : 0); + /* Set direction of transfer */ + 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))); + /* Clear interrupt and error bits */ + outb(iobase_bm + BMISTA_PORT, + (inb(iobase_bm + BMISTA_PORT) + | (BMISTA_INTERRUPT | BMISTA_DMA_ERROR))); - return 0; + return 0; } static void ide_pci_dmastart(void *xcp) { - struct ide_pci_cookie *cp = xcp; - int iobase_bm; + struct ide_pci_cookie *cp = xcp; + int iobase_bm; - iobase_bm = cp->iobase_bm; + iobase_bm = cp->iobase_bm; - outb(iobase_bm + BMICOM_PORT, - inb(iobase_bm + BMICOM_PORT) | BMICOM_STOP_START); + outb(iobase_bm + BMICOM_PORT, + inb(iobase_bm + BMICOM_PORT) | BMICOM_STOP_START); } static int ide_pci_dmadone(void *xcp) { - struct ide_pci_cookie *cp = xcp; - int iobase_bm, status; + struct ide_pci_cookie *cp = xcp; + int iobase_bm, status; - status = ide_pci_status(xcp); - iobase_bm = cp->iobase_bm; + status = ide_pci_status(xcp); + iobase_bm = cp->iobase_bm; - outb(iobase_bm + BMICOM_PORT, - inb(iobase_bm + BMICOM_PORT) & ~BMICOM_STOP_START); + outb(iobase_bm + BMICOM_PORT, + inb(iobase_bm + BMICOM_PORT) & ~BMICOM_STOP_START); - return status; + return status; } static int ide_pci_status(void *xcp) { - struct ide_pci_cookie *cp = xcp; - int iobase_bm, status, bmista; + struct ide_pci_cookie *cp = xcp; + int iobase_bm, status, bmista; - status = 0; - iobase_bm = cp->iobase_bm; + status = 0; + iobase_bm = cp->iobase_bm; - bmista = inb(iobase_bm + BMISTA_PORT); + bmista = inb(iobase_bm + BMISTA_PORT); - if (bmista & BMISTA_INTERRUPT) - status |= WDDS_INTERRUPT; - if (bmista & BMISTA_DMA_ERROR) - status |= WDDS_ERROR; - if (bmista & BMISTA_DMA_ACTIVE) - status |= WDDS_ACTIVE; + if (bmista & BMISTA_INTERRUPT) + status |= WDDS_INTERRUPT; + if (bmista & BMISTA_DMA_ERROR) + status |= WDDS_ERROR; + if (bmista & BMISTA_DMA_ACTIVE) + status |= WDDS_ACTIVE; - return status; + return status; } +static int +ide_pci_altiobase(void *xcp) +{ + struct ide_pci_cookie *cp = xcp; + if (cp == 0) { + return 0; + } else { + return cp->altiobase_wd; + } +} + +static int +ide_pci_iobase(void *xcp) +{ + struct ide_pci_cookie *cp = xcp; + if (cp == 0) { + return 0; + } else { + return cp->iobase_wd; + } +} + +#endif #endif /* NPCI > 0 */ diff --git a/sys/pci/pcireg.h b/sys/pci/pcireg.h index c24237f..9e8c85e 100644 --- a/sys/pci/pcireg.h +++ b/sys/pci/pcireg.h @@ -26,7 +26,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: pcireg.h,v 1.17 1997/05/28 20:37:19 se Exp $ + * $Id: pcireg.h,v 1.18 1997/06/01 16:00:43 peter Exp $ * */ @@ -241,6 +241,7 @@ #define PCI_CLASS_REG 0x08 #define PCI_CLASS_MASK 0xff000000 #define PCI_SUBCLASS_MASK 0x00ff0000 +#define PCI_REVISION_MASK 0x000000ff #define PCI_CLASS_PREHISTORIC 0x00000000 #define PCI_SUBCLASS_PREHISTORIC_VGA 0x00010000 #define PCI_CLASS_MASS_STORAGE 0x01000000 |