summaryrefslogtreecommitdiffstats
path: root/sys/pci/ide_pci.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/pci/ide_pci.c')
-rw-r--r--sys/pci/ide_pci.c1698
1 files changed, 1088 insertions, 610 deletions
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 */
OpenPOWER on IntegriCloud