patch-2.1.30 linux/drivers/block/triton.c
Next file: linux/drivers/char/keyboard.c
Previous file: linux/drivers/block/ll_rw_blk.c
Back to the patch index
Back to the overall index
- Lines: 501
- Date:
Tue Mar 11 14:19:12 1997
- Orig file:
v2.1.29/linux/drivers/block/triton.c
- Orig date:
Mon Jan 27 23:32:47 1997
diff -u --recursive --new-file v2.1.29/linux/drivers/block/triton.c linux/drivers/block/triton.c
@@ -1,28 +1,34 @@
/*
- * linux/drivers/block/triton.c Version 1.20 Jan 27, 1997
+ * linux/drivers/block/triton.c Version 2.00 March 9, 1997
*
* Copyright (c) 1995-1997 Mark Lord
* May be copied or modified under the terms of the GNU General Public License
*/
/*
- * This module provides support for the Bus Master IDE DMA function
- * of the Intel PCI Triton I/II chipsets (i82371FB or i82371SB).
+ * This module provides support for the bus-master IDE DMA function
+ * of the Intel PCI Triton chipset families, which use the PIIX (i82371FB,
+ * for the 430 FX chipset), and the enhanced PIIX3 (i82371SB for the 430 HX/VX
+ * and 440 chipsets).
*
- * Pretty much the same code will work for the OPTi "Viper" chipset.
- * Look for DMA support for this in linux kernel 2.1.xx, when it appears.
+ * "PIIX" stands for "PCI ISA IDE Xcellerator".
*
- * Up to four drives may be enabled for DMA, and the Triton chipset will
- * (hopefully) arbitrate the PCI bus among them. Note that the i82371 chip
+ * Pretty much the same code could work for other IDE PCI bus-mastering chipsets.
+ * Look for DMA support for this someday in the not too distant future.
+ *
+ * DMA is supported for all IDE devices (disk drives, cdroms, tapes, floppies).
+ *
+ * Up to four drives may be enabled for DMA, and the PIIX/PIIX3 chips
+ * will arbitrate the PCI bus among them. Note that the PIIX/PIIX3
* provides a single "line buffer" for the BM IDE function, so performance of
* multiple (two) drives doing DMA simultaneously will suffer somewhat,
* as they contest for that resource bottleneck. This is handled transparently
- * inside the i82371 chip.
+ * inside the PIIX/PIIX3.
*
* By default, DMA support is prepared for use, but is currently enabled only
- * for drives which support multi-word DMA mode2 (mword2), or which are
+ * for drives which support DMA mode2 (multi/single word), or which are
* recognized as "good" (see table below). Drives with only mode0 or mode1
- * (single or multi) DMA should also work with this chipset/driver (eg. MC2112A)
+ * (multi/single word) DMA should also work with this chipset/driver (eg. MC2112A)
* but are not enabled by default. Use "hdparm -i" to view modes supported
* by a given drive.
*
@@ -39,55 +45,11 @@
* the "hdparm -X" feature. There is seldom a need to do this, as drives
* normally power-up with their "best" PIO/DMA modes enabled.
*
- * Testing was done with an ASUS P55TP4XE/100 system and the following drives:
+ * Testing has been done with a rather extensive number of drives,
+ * with Quantum & Western Digital models generally outperforming the pack,
+ * and Fujitsu & Conner (and some Seagate which are really Conner) drives
+ * showing more lackluster throughput.
*
- * Quantum Fireball 1080A (1Gig w/83kB buffer), DMA mode2, PIO mode4.
- * - DMA mode2 works well (7.4MB/sec), despite the tiny on-drive buffer.
- * - This drive also does PIO mode4, at about the same speed as DMA mode2.
- * An awesome drive for the price!
- *
- * Fujitsu M1606TA (1Gig w/256kB buffer), DMA mode2, PIO mode4.
- * - DMA mode2 gives horrible performance (1.6MB/sec), despite the good
- * size of the on-drive buffer and a boasted 10ms average access time.
- * - PIO mode4 was better, but peaked at a mere 4.5MB/sec.
- *
- * Micropolis MC2112A (1Gig w/508kB buffer), drive pre-dates EIDE and ATA2.
- * - DMA works fine (2.2MB/sec), probably due to the large on-drive buffer.
- * - This older drive can also be tweaked for fastPIO (3.7MB/sec) by using
- * maximum clock settings (5,4) and setting all flags except prefetch.
- *
- * Western Digital AC31000H (1Gig w/128kB buffer), DMA mode1, PIO mode3.
- * - DMA does not work reliably. The drive appears to be somewhat tardy
- * in deasserting DMARQ at the end of a sector. This is evident in
- * the observation that WRITEs work most of the time, depending on
- * cache-buffer occupancy, but multi-sector reads seldom work.
- *
- * Testing was done with a Gigabyte GA-586 ATE system and the following drive:
- * (Uwe Bonnes - [email protected])
- *
- * Western Digital AC31600H (1.6Gig w/128kB buffer), DMA mode2, PIO mode4.
- * - much better than its 1Gig cousin, this drive is reported to work
- * very well with DMA (7.3MB/sec).
- *
- * Other drives:
- *
- * Maxtor 7540AV (515Meg w/32kB buffer), DMA modes mword0/sword2, PIO mode3.
- * - a budget drive, with budget performance, around 3MB/sec.
- *
- * Western Digital AC2850F (814Meg w/64kB buffer), DMA mode1, PIO mode3.
- * - another "caviar" drive, similar to the AC31000, except that this one
- * worked with DMA in at least one system. Throughput is about 3.8MB/sec
- * for both DMA and PIO.
- *
- * Conner CFS850A (812Meg w/64kB buffer), DMA mode2, PIO mode4.
- * - like most Conner models, this drive proves that even a fast interface
- * cannot improve slow media. Both DMA and PIO peak around 3.5MB/sec.
- *
- * Maxtor 71260AT (1204Meg w/256kB buffer), DMA mword0/sword2, PIO mode3.
- * - works with DMA, on some systems (but not always on others, eg. Dell),
- * giving 3-4MB/sec performance, about the same as mode3.
- *
- * If you have any drive models to add, email your results to: [email protected]
* Keep an eye on /var/adm/messages for "DMA disabled" messages.
*
* Some people have reported trouble with Intel Zappa motherboards.
@@ -98,7 +60,7 @@
* Thanks to "Christopher J. Reimer" <[email protected]> for fixing the
* problem with some (all?) ACER motherboards/BIOSs.
*
- * And, yes, Intel Zappa boards really *do* use the Triton IDE ports.
+ * And, yes, Intel Zappa boards really *do* use both PIIX IDE ports.
*/
#include <linux/types.h>
#include <linux/kernel.h>
@@ -115,17 +77,17 @@
#include <asm/dma.h>
#include "ide.h"
+#include "ide_modes.h"
-#undef DISPLAY_TRITON_TIMINGS /* define this to display timings */
+#define DISPLAY_PIIX_TIMINGS /* define this to display timings */
/*
* good_dma_drives() lists the model names (from "hdparm -i")
- * of drives which do not support mword2 DMA but which are
+ * of drives which do not support mode2 DMA but which are
* known to work fine with this interface under Linux.
*/
const char *good_dma_drives[] = {"Micropolis 2112A",
"CONNER CTMA 4000",
- "CONNER CTT8000-A",
NULL};
/*
@@ -152,6 +114,37 @@
*/
static unsigned int piix_key;
+#define PIIX_FLAGS_FAST_PIO 1
+#define PIIX_FLAGS_USE_IORDY 2
+#define PIIX_FLAGS_PREFETCH 4
+#define PIIX_FLAGS_FAST_DMA 8
+
+typedef struct {
+ unsigned d0_flags :4;
+ unsigned d1_flags :4;
+ unsigned recovery :2;
+ unsigned reserved :2;
+ unsigned sample :2;
+ unsigned sidetim_enabled:1;
+ unsigned ports_enabled :1;
+} piix_timing_t;
+
+typedef struct {
+ unsigned pri_recovery :2;
+ unsigned pri_sample :2;
+ unsigned sec_recovery :2;
+ unsigned sec_sample :2;
+} piix_sidetim_t;
+
+
+/*
+ * We currently can handle only one PIIX chip here
+ */
+static piix_pci_bus = 0;
+static piix_pci_fn = 0;
+
+static int config_drive_for_dma (ide_drive_t *);
+
/*
* dma_intr() is the handler for disk read/write DMA interrupts
*/
@@ -240,31 +233,8 @@
return 1; /* let the PIO routines handle this weirdness */
}
-static int config_drive_for_dma (ide_drive_t *drive)
-{
- const char **list;
-
- struct hd_driveid *id = drive->id;
- if (id && (id->capability & 1)) {
- /* Enable DMA on any drive that supports mword2 DMA */
- if ((id->field_valid & 2) && (id->dma_mword & 0x404) == 0x404) {
- drive->using_dma = 1;
- return 0; /* DMA enabled */
- }
- /* Consult the list of known "good" drives */
- list = good_dma_drives;
- while (*list) {
- if (!strcmp(*list++,id->model)) {
- drive->using_dma = 1;
- return 0; /* DMA enabled */
- }
- }
- }
- return 1; /* DMA not enabled */
-}
-
/*
- * triton_dmaproc() initiates/aborts DMA read/write operations on a drive.
+ * piix_dmaproc() initiates/aborts DMA read/write operations on a drive.
*
* The caller is assumed to have selected the drive and programmed the drive's
* sector address using CHS or LBA. All that remains is to prepare for DMA
@@ -278,12 +248,40 @@
* Returns 1 if DMA read/write could not be started, in which case
* the caller should revert to PIO for the current request.
*/
-static int triton_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
+static int piix_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
{
unsigned long dma_base = HWIF(drive)->dma_base;
unsigned int reading = (1 << 3);
+ piix_timing_t timing;
+ unsigned short reg;
+ byte dflags;
switch (func) {
+ case ide_dma_off:
+ printk("%s: DMA disabled\n", drive->name);
+ case ide_dma_on:
+ drive->using_dma = (func == ide_dma_on);
+ reg = (HWIF(drive)->io_ports[IDE_DATA_OFFSET] == 0x170) ? 0x42 : 0x40;
+ if (pcibios_read_config_word(piix_pci_bus, piix_pci_fn, reg, (short *)&timing)) {
+ printk("%s: pcibios read failed\n", HWIF(drive)->name);
+ return 1;
+ }
+ dflags = drive->select.b.unit ? timing.d1_flags : timing.d0_flags;
+ if (dflags & PIIX_FLAGS_FAST_PIO) {
+ if (func == ide_dma_on && drive->media == ide_disk)
+ dflags |= PIIX_FLAGS_FAST_DMA;
+ else
+ dflags &= ~PIIX_FLAGS_FAST_DMA;
+ if (drive->select.b.unit == 0)
+ timing.d0_flags = dflags;
+ else
+ timing.d1_flags = dflags;
+ if (pcibios_write_config_word(piix_pci_bus, piix_pci_fn, reg, *(short *)&timing)) {
+ printk("%s: pcibios write failed\n", HWIF(drive)->name);
+ return 1;
+ }
+ }
+ return 0;
case ide_dma_abort:
outb(inb(dma_base)&~1, dma_base); /* stop DMA */
return 0;
@@ -305,7 +303,7 @@
outb(inb(dma_base)|1, dma_base); /* begin DMA */
return 0;
default:
- printk("triton_dmaproc: unsupported func: %d\n", func);
+ printk("piix_dmaproc: unsupported func: %d\n", func);
return 1;
}
if (build_dmatable (drive))
@@ -321,31 +319,42 @@
return 0;
}
-#ifdef DISPLAY_TRITON_TIMINGS
+static int config_drive_for_dma (ide_drive_t *drive)
+{
+ const char **list;
+
+ struct hd_driveid *id = drive->id;
+ if (id && (id->capability & 1)) {
+ /* Enable DMA on any drive that supports mode2 (multi/single word) DMA */
+ if (id->field_valid & 2)
+ if ((id->dma_mword & 0x404) == 0x404 || (id->dma_1word & 0x404) == 0x404)
+ return piix_dmaproc(ide_dma_on, drive);
+ /* Consult the list of known "good" drives */
+ list = good_dma_drives;
+ while (*list) {
+ if (!strcmp(*list++,id->model))
+ return piix_dmaproc(ide_dma_on, drive);
+ }
+ }
+ return piix_dmaproc(ide_dma_off, drive);
+}
+
+#ifdef DISPLAY_PIIX_TIMINGS
/*
- * print_triton_drive_flags() displays the currently programmed options
- * in the i82371 (Triton) for a given drive.
- *
- * If fastDMA is "no", then slow ISA timings are used for DMA data xfers.
- * If fastPIO is "no", then slow ISA timings are used for PIO data xfers.
- * If IORDY is "no", then IORDY is assumed to always be asserted.
- * If PreFetch is "no", then data pre-fetch/post are not used.
- *
- * When "fastPIO" and/or "fastDMA" are "yes", then faster PCI timings and
- * back-to-back 16-bit data transfers are enabled, using the sample_CLKs
- * and recovery_CLKs (PCI clock cycles) timing parameters for that interface.
+ * print_piix_drive_flags() displays the currently programmed options
+ * in the PIIX/PIIX3 for a given drive.
*/
-static void print_triton_drive_flags (unsigned int unit, byte flags)
+static void print_piix_drive_flags (const char *unit, byte dflags)
{
- printk(" %s ", unit ? "slave :" : "master:");
- printk( "fastDMA=%s", (flags&9) ? "on " : "off");
- printk(" PreFetch=%s", (flags&4) ? "on " : "off");
- printk(" IORDY=%s", (flags&2) ? "on " : "off");
- printk(" fastPIO=%s\n", ((flags&9)==1) ? "on " : "off");
+ printk(" %s ", unit);
+ printk( "fastDMA=%s", (dflags & PIIX_FLAGS_FAST_PIO) ? "yes" : "no ");
+ printk(" PreFetch=%s", (dflags & PIIX_FLAGS_PREFETCH) ? "on " : "off");
+ printk(" IORDY=%s", (dflags & PIIX_FLAGS_USE_IORDY) ? "on " : "off");
+ printk(" fastPIO=%s\n", ((dflags & (PIIX_FLAGS_FAST_PIO|PIIX_FLAGS_FAST_DMA)) == PIIX_FLAGS_FAST_PIO) ? "on " : "off");
}
-#endif /* DISPLAY_TRITON_TIMINGS */
+#endif /* DISPLAY_PIIX_TIMINGS */
-static void init_triton_dma (ide_hwif_t *hwif, unsigned short base)
+static void init_piix_dma (ide_hwif_t *hwif, unsigned short base)
{
static unsigned long dmatable = 0;
@@ -367,7 +376,7 @@
hwif->dmatable = (unsigned long *) dmatable;
dmatable += (PRD_ENTRIES * PRD_BYTES);
outl(virt_to_bus(hwif->dmatable), base + 4);
- hwif->dmaproc = &triton_dmaproc;
+ hwif->dmaproc = &piix_dmaproc;
}
}
printk("\n");
@@ -429,10 +438,16 @@
{
int rc = 0, h;
int dma_enabled = 0;
- unsigned short pcicmd;
- unsigned int bmiba, timings;
+ unsigned short pcicmd, devid;
+ unsigned int bmiba;
+ const char *chipset = "ide";
+ piix_timing_t timings[2];
+
+ if (pcibios_read_config_word(piix_pci_bus, piix_pci_fn, 0x02, &devid))
+ goto quit;
+ chipset = (devid == PCI_DEVICE_ID_INTEL_82371SB_1) ? "PIIX3" : "PIIX";
- printk("ide: i82371 PIIX (Triton) on PCI bus %d function %d\n", bus, fn);
+ printk("%s: bus-master IDE device on PCI bus %d function %d\n", chipset, bus, fn);
/*
* See if IDE ports are enabled
@@ -440,21 +455,26 @@
if ((rc = pcibios_read_config_word(bus, fn, 0x04, &pcicmd)))
goto quit;
if ((pcicmd & 1) == 0) {
- printk("ide: ports are not enabled (BIOS)\n");
+ printk("%s: IDE ports are not enabled (BIOS)\n", chipset);
goto quit;
}
- if ((rc = pcibios_read_config_dword(bus, fn, 0x40, &timings)))
+ if ((rc = pcibios_read_config_word(bus, fn, 0x40, (short *)&timings[0])))
goto quit;
- if (!(timings & 0x80008000)) {
- printk("ide: neither port is enabled\n");
+ if ((rc = pcibios_read_config_word(bus, fn, 0x42, (short *)&timings[1])))
+ goto quit;
+ if ((!timings[0].ports_enabled) || (!timings[1].ports_enabled)) {
+ printk("%s: neither IDE port is enabled\n", chipset);
goto quit;
}
+ piix_pci_bus = bus;
+ piix_pci_fn = fn;
+
/*
* See if Bus-Mastered DMA is enabled
*/
if ((pcicmd & 4) == 0) {
- printk("ide: BM-DMA feature is not enabled (BIOS)\n");
+ printk("%s: bus-master DMA feature is not enabled (BIOS)\n", chipset);
} else {
/*
* Get the bmiba base address
@@ -466,10 +486,10 @@
dma_enabled = 1;
} else {
unsigned short base;
- printk("ide: BM-DMA base register is invalid (0x%04x, PnP BIOS problem)\n", bmiba);
+ printk("%s: bus-master base address is invalid (0x%04x, BIOS problem)\n", chipset, bmiba);
base = find_free_region(16);
if (base) {
- printk("ide: bypassing BIOS; setting BMIBA to 0x%04x\n", base);
+ printk("%s: bypassing BIOS; setting bus-master base address to 0x%04x\n", chipset, base);
piix_key = 0x80000000 + (fn * 0x100);
put_piix_reg(0x04,get_piix_reg(0x04)&~5);
put_piix_reg(0x20,(get_piix_reg(0x20)&0xFFFF000F)|base|1);
@@ -478,8 +498,10 @@
if (bmiba == base && (get_piix_reg(0x04) & 5) == 5)
dma_enabled = 1;
else
- printk("ide: no such luck; DMA disabled\n");
+ printk("%s: operation failed\n", chipset);
}
+ if (!dma_enabled)
+ printk("%s: DMA is disabled (BIOS)\n", chipset);
}
}
@@ -487,56 +509,51 @@
* Save the dma_base port addr for each interface
*/
for (h = 0; h < MAX_HWIFS; ++h) {
-#ifdef DISPLAY_TRITON_TIMINGS
- byte s_clks, r_clks;
- unsigned short devid;
-#endif /* DISPLAY_TRITON_TIMINGS */
+ unsigned int pri_sec;
+ piix_timing_t timing;
ide_hwif_t *hwif = &ide_hwifs[h];
- unsigned short time;
- if (hwif->io_ports[IDE_DATA_OFFSET] == 0x1f0) {
- time = timings & 0xffff;
- if ((time & 0x8000) == 0) /* interface enabled? */
- continue;
- hwif->chipset = ide_triton;
- if (dma_enabled)
- init_triton_dma(hwif, bmiba);
- } else if (hwif->io_ports[IDE_DATA_OFFSET] == 0x170) {
- time = timings >> 16;
- if ((time & 0x8000) == 0) /* interface enabled? */
- continue;
- hwif->chipset = ide_triton;
- if (dma_enabled)
- init_triton_dma(hwif, bmiba + 8);
- } else
+ switch (hwif->io_ports[IDE_DATA_OFFSET]) {
+ case 0x1f0: pri_sec = 0; break;
+ case 0x170: pri_sec = 1; break;
+ default: continue;
+ }
+ timing = timings[pri_sec];
+ if (!timing.ports_enabled) /* interface disabled? */
continue;
-#ifdef DISPLAY_TRITON_TIMINGS
- s_clks = ((~time >> 12) & 3) + 2;
- r_clks = ((~time >> 8) & 3) + 1;
- printk(" %s timing: (0x%04x) sample_CLKs=%d, recovery_CLKs=%d\n",
- hwif->name, time, s_clks, r_clks);
- if ((time & 0x40) && !pcibios_read_config_word(bus, fn, 0x02, &devid)
- && devid == PCI_DEVICE_ID_INTEL_82371SB_1)
+ hwif->chipset = ide_triton;
+ if (dma_enabled)
+ init_piix_dma(hwif, bmiba + (pri_sec ? 8 : 0));
+#ifdef DISPLAY_PIIX_TIMINGS
+ /*
+ * Display drive timings/modes
+ */
{
- byte stime;
- if (pcibios_read_config_byte(bus, fn, 0x44, &stime)) {
- if (hwif->io_ports[IDE_DATA_OFFSET] == 0x1f0) {
- s_clks = ~stime >> 6;
- r_clks = ~stime >> 4;
+ const char *slave;
+ piix_sidetim_t sidetim;
+ byte sample = 5 - timing.sample;
+ byte recovery = 4 - timing.recovery;
+ if (devid == PCI_DEVICE_ID_INTEL_82371SB_1
+ && timing.sidetim_enabled
+ && !pcibios_read_config_byte(piix_pci_bus, piix_pci_fn, 0x44, (byte *) &sidetim))
+ slave = ""; /* PIIX3 */
+ else
+ slave = "/slave"; /* PIIX, or PIIX3 in compatibility mode */
+ printk(" %s master%s: sample_CLKs=%d, recovery_CLKs=%d\n", hwif->name, slave, sample, recovery);
+ print_piix_drive_flags ("master:", timing.d0_flags);
+ if (!*slave) {
+ if (pri_sec == 0) {
+ sample = 5 - sidetim.pri_sample;
+ recovery = 4 - sidetim.pri_recovery;
} else {
- s_clks = ~stime >> 2;
- r_clks = ~stime;
+ sample = 5 - sidetim.sec_sample;
+ recovery = 4 - sidetim.sec_recovery;
}
- s_clks = (s_clks & 3) + 2;
- r_clks = (r_clks & 3) + 1;
- printk(" slave: sample_CLKs=%d, recovery_CLKs=%d\n",
- s_clks, r_clks);
+ printk(" slave : sample_CLKs=%d, recovery_CLKs=%d\n", sample, recovery);
}
+ print_piix_drive_flags ("slave :", timing.d1_flags);
}
- print_triton_drive_flags (0, time & 0xf);
- print_triton_drive_flags (1, (time >> 4) & 0xf);
-#endif /* DISPLAY_TRITON_TIMINGS */
+#endif /* DISPLAY_PIIX_TIMINGS */
}
-quit: if (rc) printk("ide: pcibios access failed - %s\n", pcibios_strerror(rc));
+quit: if (rc) printk("%s: pcibios access failed - %s\n", chipset, pcibios_strerror(rc));
}
-
FUNET's LINUX-ADM group, [email protected]
TCL-scripts by Sam Shen, [email protected]