All of lore.kernel.org
 help / color / mirror / Atom feed
From: Sergei Shtylyov <sshtylyov@ru.mvista.com>
To: bzolnier@gmail.com
Cc: linux-ide@vger.kernel.org
Subject: [PATCH] (pata-2.6 fix queue) cmd64x: add back MWDMA support
Date: Wed, 28 Feb 2007 23:52:41 +0300	[thread overview]
Message-ID: <200702282352.41128.sshtylyov@ru.mvista.com> (raw)
In-Reply-To: <200702040004.24918.sshtylyov@ru.mvista.com>

Add back the multiword DMA support (I think nobody will miss single-word DMA).
In order to do it, a number of changes had to be done:

- rename program_drive_counts() to program_cycle_times(), pass to it cycle's
  total/active times instead of the clock counts, and convert them into the
  active/recovery clocks there instead of cmd64x_tune_pio() -- this causes
  quantize_timing() to also move;

- contrarywise, move all the code handling the address setup timing into
  cmd64x_tune_pio(), so that setting MWDMA mode wouldn't change address setup;

- add MWDMA cases to the speedproc() method and handle them by just calling
  program_cycle_times();

- set hwif->mdwma_mask in the init_hwif() method.

In addition to those changes, do the following:

- when writing to ARTTIM23 register for the secondary channel, preserve the
  interrupt status bit; eliminate the local_irq_{save|restore}() around this
  code as there is *no* actual race with interrupt handler;

- make {arttim|drwtim}_regs[] single-dimensional, indexed with drive->dn;

- rename {setup|recovery}_counts[] into more fitting {setup|recovery}_values[];

While at it, also do remove:

- needless and misplaced timing registers initialization in the init_chipset()
  method;

- meaningless register "aliases";

- meaningless comment about the driver being used only on SPARC Ultra. :-)

Signed-off-by: Sergei Shtylyov <sshtylyov@ru.mvista.com>

---
Warning: this has only been compile-tested, as usual, so *needs* real testing.

Note that this implementation doesn't take care of properly merging MWDMA and
PIO timings which share the same registers (well, that's not done by the most
IDE drivers anyway).

Still have no idea about why PPC needs to explicitly disable UltraDMA on the
primary channel -- it should be disabled by default...

 drivers/ide/pci/cmd64x.c |  194 +++++++++++++++++++++--------------------------
 1 files changed, 88 insertions(+), 106 deletions(-)

Index: linux-2.6/drivers/ide/pci/cmd64x.c
===================================================================
--- linux-2.6.orig/drivers/ide/pci/cmd64x.c
+++ linux-2.6/drivers/ide/pci/cmd64x.c
@@ -1,10 +1,8 @@
 /* $Id: cmd64x.c,v 1.21 2000/01/30 23:23:16
  *
- * linux/drivers/ide/pci/cmd64x.c		Version 1.47	Feb 16, 2007
+ * linux/drivers/ide/pci/cmd64x.c		Version 1.50	Feb 27, 2007
  *
  * cmd64x.c: Enable interrupts at initialization time on Ultra/PCI machines.
- *           Note, this driver is not used at all on other systems because
- *           there the "BIOS" has done all of the following already.
  *           Due to massive hardware bugs, UltraDMA is only supported
  *           on the 646U2 and not on the 646U.
  *
@@ -55,9 +53,6 @@
 #define   ARTTIM23_DIS_RA2	0x04
 #define   ARTTIM23_DIS_RA3	0x08
 #define   ARTTIM23_INTR_CH1	0x10
-#define ARTTIM2		0x57
-#define ARTTIM3		0x57
-#define DRWTIM23	0x58
 #define DRWTIM2		0x58
 #define BRST		0x59
 #define DRWTIM3		0x5b
@@ -168,122 +163,111 @@ static int cmd64x_get_info (char *buffer
 
 #endif	/* defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS) */
 
+static u8 quantize_timing (int timing, int quant)
+{
+	return (timing + quant - 1) / quant;
+}
+
 /*
- * This routine writes the prepared setup/active/recovery counts
- * for a drive into the cmd646 chipset registers to active them.
+ * This routine calculates active/recovery counts and then writes them into
+ * the chipset registers.
  */
-static void program_drive_counts (ide_drive_t *drive, int setup_count, int active_count, int recovery_count)
+static void program_cycle_times (ide_drive_t *drive, int cycle_time, int active_time)
 {
-	unsigned long flags;
-	struct pci_dev *dev = HWIF(drive)->pci_dev;
-	ide_drive_t *drives = HWIF(drive)->drives;
-	u8 temp_b;
-	static const u8 setup_counts[] = {0x40, 0x40, 0x40, 0x80, 0, 0xc0};
-	static const u8 recovery_counts[] =
+	struct pci_dev *dev	= HWIF(drive)->pci_dev;
+	int clock_time		= 1000 / system_bus_clock();
+	u8  cycle_count, active_count, recovery_count, drwtim;
+	static const u8 recovery_values[] =
 		{15, 15, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 0};
-	static const u8 arttim_regs[2][2] = {
-			{ ARTTIM0, ARTTIM1 },
-			{ ARTTIM23, ARTTIM23 }
-		};
-	static const u8 drwtim_regs[2][2] = {
-			{ DRWTIM0, DRWTIM1 },
-			{ DRWTIM2, DRWTIM3 }
-		};
-	int channel = (int) HWIF(drive)->channel;
-	int slave = (drives != drive);  /* Is this really the best way to determine this?? */
+	static const u8 drwtim_regs[4] = {DRWTIM0, DRWTIM1, DRWTIM2, DRWTIM3};
 
-	cmdprintk("program_drive_count parameters = s(%d),a(%d),r(%d),p(%d)\n",
-		setup_count, active_count, recovery_count, drive->present);
-	/*
-	 * Set up address setup count registers.
-	 * Primary interface has individual count/timing registers for
-	 * each drive.  Secondary interface has one common set of registers,
-	 * for address setup so we merge these timings, using the slowest
-	 * value.
-	 */
-	if (channel) {
-		drive->drive_data = setup_count;
-		setup_count = max(drives[0].drive_data,
-					drives[1].drive_data);
-		cmdprintk("Secondary interface, setup_count = %d\n",
-					setup_count);
-	}
+	cmdprintk("program_cycle_times parameters: total=%d, active=%d\n",
+		  cycle_time, active_time);
+
+	cycle_count	= quantize_timing( cycle_time, clock_time);
+	active_count	= quantize_timing(active_time, clock_time);
+	recovery_count	= cycle_count - active_count;
 
 	/*
-	 * Convert values to internal chipset representation
+	 * In case we've got too long recovery phase, try to lengthen
+	 * the active phase
 	 */
-	setup_count = (setup_count > 5) ? 0xc0 : (int) setup_counts[setup_count];
-	active_count &= 0xf; /* Remember, max value is 16 */
-	recovery_count = (int) recovery_counts[recovery_count];
+	if (recovery_count > 16) {
+		active_count += recovery_count - 16;
+		recovery_count = 16;
+	}
+	if (active_count > 16)		/* shouldn't actually happen... */
+	 	active_count = 16;
 
-	cmdprintk("Final values = %d,%d,%d\n",
-		setup_count, active_count, recovery_count);
+	cmdprintk("Final counts: total=%d, active=%d, recovery=%d\n",
+		  cycle_count, active_count, recovery_count);
 
 	/*
-	 * Now that everything is ready, program the new timings
-	 */
-	local_irq_save(flags);
-	/*
-	 * Program the address_setup clocks into ARTTIM reg,
-	 * and then the active/recovery counts into the DRWTIM reg
+	 * Convert values to internal chipset representation
 	 */
-	(void) pci_read_config_byte(dev, arttim_regs[channel][slave], &temp_b);
-	(void) pci_write_config_byte(dev, arttim_regs[channel][slave],
-		((u8) setup_count) | (temp_b & 0x3f));
-	(void) pci_write_config_byte(dev, drwtim_regs[channel][slave],
-		(u8) ((active_count << 4) | recovery_count));
-	cmdprintk ("Write %x to %x\n",
-		((u8) setup_count) | (temp_b & 0x3f),
-		arttim_regs[channel][slave]);
-	cmdprintk ("Write %x to %x\n",
-		(u8) ((active_count << 4) | recovery_count),
-		drwtim_regs[channel][slave]);
-	local_irq_restore(flags);
-}
+	recovery_count = recovery_values[recovery_count];
+ 	active_count &= 0x0f;
 
-static u8 quantize_timing(int timing, int quant)
-{
-	return (timing + quant - 1) / quant;
+	/* Program the active/recovery counts into the DRWTIM register */
+	drwtim = (active_count << 4) | recovery_count;
+	(void) pci_write_config_byte(dev, drwtim_regs[drive->dn], drwtim);
+	cmdprintk ("Write %x to %x\n", drwtim, drwtim_regs[drive->dn]);
 }
 
 /*
- * This routine selects drive's best PIO mode, calculates setup/active/recovery
- * counts, and then writes them into the chipset registers.
+ * This routine selects drive's best PIO mode and writes into the chipset
+ * registers setup/active/recovery timings.
  */
 static u8 cmd64x_tune_pio (ide_drive_t *drive, u8 mode_wanted)
 {
-	int setup_time, active_time, cycle_time;
-	u8  cycle_count, setup_count, active_count, recovery_count;
-	u8  pio_mode;
-	int clock_time = 1000 / system_bus_clock();
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
 	ide_pio_data_t pio;
+	u8 pio_mode, setup_count, arttim = 0;
+	static const u8 setup_values[] = {0x40, 0x40, 0x40, 0x80, 0, 0xc0};
+	static const u8 arttim_regs[4] = {ARTTIM0, ARTTIM1, ARTTIM23, ARTTIM23};
 
 	pio_mode = ide_get_best_pio_mode(drive, mode_wanted, 5, &pio);
-	cycle_time = pio.cycle_time;
 
-	setup_time  = ide_pio_timings[pio_mode].setup_time;
-	active_time = ide_pio_timings[pio_mode].active_time;
+	program_cycle_times(drive, pio.cycle_time,
+			    ide_pio_timings[pio_mode].active_time);
 
-	setup_count  = quantize_timing( setup_time, clock_time);
-	cycle_count  = quantize_timing( cycle_time, clock_time);
-	active_count = quantize_timing(active_time, clock_time);
+	setup_count = quantize_timing(ide_pio_timings[pio_mode].setup_time,
+				      1000 / system_bus_clock());
+
+	/*
+	 * The primary channel has individual address setup timing registers
+	 * for each drive and the hardware selects the slowest timing itself.
+	 * The secondary channel has one common register and we have to select
+	 * the slowest address setup timing ourselves.
+	 */
+	if (hwif->channel) {
+		ide_drive_t *drives = hwif->drives;
+
+		drive->drive_data = setup_count;
+		setup_count = max(drives[0].drive_data, drives[1].drive_data);
 
-	recovery_count = cycle_count - active_count;
-	/* program_drive_counts() takes care of zero recovery cycles */
-	if (recovery_count > 16) {
-		active_count += recovery_count - 16;
-		recovery_count = 16;
 	}
-	if (active_count > 16)
-		active_count = 16; /* maximum allowed by cmd64x */
 
-	program_drive_counts (drive, setup_count, active_count, recovery_count);
+	if (setup_count > 5)		/* shouldn't actually happen... */
+		setup_count = 5;
+	cmdprintk("Final address setup count = %d\n", setup_count);
 
-	cmdprintk("%s: PIO mode wanted %d, selected %d (%dns)%s, "
-		"clocks=%d/%d/%d\n",
-		drive->name, mode_wanted, pio_mode, cycle_time,
-		pio.overridden ? " (overriding vendor mode)" : "",
-		setup_count, active_count, recovery_count);
+	/*
+	 * Program the address setup clocks into the ARTTIM registers.
+	 * Avoid clearing the secondary channel's interrupt bit.
+	 */
+	(void) pci_read_config_byte (dev, arttim_regs[drive->dn], &arttim);
+	if (hwif->channel)
+		arttim &= ~ARTTIM23_INTR_CH1;
+	arttim &= ~0xc0;
+	arttim |= setup_values[setup_count];
+	(void) pci_write_config_byte(dev, arttim_regs[drive->dn], arttim);
+	cmdprintk ("Write %x to %x\n", arttim, arttim_regs[drive->dn]);
+
+	cmdprintk("%s: PIO mode wanted %d, selected %d (%d ns)%s\n",
+		  drive->name, mode_wanted, pio_mode, pio.cycle_time,
+		  pio.overridden ? " (overriding vendor mode)" : "");
 
 	return pio_mode;
 }
@@ -388,6 +372,15 @@ static int cmd64x_tune_chipset (ide_driv
 	case XFER_UDMA_0:
 		regU |= unit ? 0xC2 : 0x31;
 		break;
+	case XFER_MW_DMA_2:
+		program_cycle_times(drive, 120, 70);
+		break;
+	case XFER_MW_DMA_1:
+		program_cycle_times(drive, 150, 80);
+		break;
+	case XFER_MW_DMA_0:
+		program_cycle_times(drive, 480, 215);
+		break;
 	case XFER_PIO_5:
 	case XFER_PIO_4:
 	case XFER_PIO_3:
@@ -575,18 +568,6 @@ static unsigned int __devinit init_chips
 	 */
 	(void) pci_write_config_byte(dev, MRDMODE, mrdmode | 0x02);
 
-	/* Set reasonable active/recovery/address-setup values. */
-	(void) pci_write_config_byte(dev, ARTTIM0,  0x40);
-	(void) pci_write_config_byte(dev, DRWTIM0,  0x3f);
-	(void) pci_write_config_byte(dev, ARTTIM1,  0x40);
-	(void) pci_write_config_byte(dev, DRWTIM1,  0x3f);
-#ifdef __i386__
-	(void) pci_write_config_byte(dev, ARTTIM23, 0x1c);
-#else
-	(void) pci_write_config_byte(dev, ARTTIM23, 0x5c);
-#endif
-	(void) pci_write_config_byte(dev, DRWTIM23, 0x3f);
-	(void) pci_write_config_byte(dev, DRWTIM3,  0x3f);
 #ifdef CONFIG_PPC
 	(void) pci_write_config_byte(dev, UDIDETCR0, 0xf0);
 #endif /* CONFIG_PPC */
@@ -639,6 +620,7 @@ static void __devinit init_hwif_cmd64x(i
 	hwif->atapi_dma = 1;
 
 	hwif->ultra_mask = 0x3f;
+	hwif->mwdma_mask = 0x07;
 
 	if (dev->device == PCI_DEVICE_ID_CMD_643)
 		hwif->ultra_mask = 0x80;


  parent reply	other threads:[~2007-02-28 20:52 UTC|newest]

Thread overview: 69+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-02-03 20:09 [PATCH] (2.6.20-rc7) cmd64x: fix PIO mode setup Sergei Shtylyov
2007-02-03 21:04 ` [PATCH] (2.6.20-rc7) cmd64x: fix PIO mode setup (take 2) Sergei Shtylyov
2007-02-03 22:25   ` Bartlomiej Zolnierkiewicz
2007-02-05 13:29     ` Sergei Shtylyov
2007-02-05 13:57       ` Sergei Shtylyov
     [not found]         ` <58cb370e0702061459r1b001421gb4592d066793ab46@mail.gmail.com>
2007-02-06 23:44           ` Bartlomiej Zolnierkiewicz
2007-02-07 12:50             ` Sergei Shtylyov
     [not found]       ` <58cb370e0702061459k4a147891v3686b267d8e3001a@mail.gmail.com>
2007-02-06 23:33         ` Bartlomiej Zolnierkiewicz
2007-02-06 14:45   ` [PATCH] (2.6.20) cmd64x: fix PIO mode setup (take 3) Sergei Shtylyov
2007-02-06 21:11     ` Mikael Pettersson
2007-02-07  0:28       ` Bartlomiej Zolnierkiewicz
     [not found]     ` <58cb370e0702061500g3047b8ccpca894962491b588a@mail.gmail.com>
2007-02-06 23:48       ` Bartlomiej Zolnierkiewicz
2007-02-09 22:29   ` [PATCH] (pata-2.6 fix queue) cmd64x: fix recovery time calculation Sergei Shtylyov
2007-02-10  0:14     ` Bartlomiej Zolnierkiewicz
2007-02-14 21:42   ` [PATCH] (pata-2.6 fix queue) cmd64x: interrupt status fixes Sergei Shtylyov
2007-02-14 22:35   ` [PATCH] (pata-2.6 fix queue) cmd64x: add/fix enablebits Sergei Shtylyov
2007-02-19 23:09     ` Bartlomiej Zolnierkiewicz
2007-02-20 14:28       ` Sergei Shtylyov
2007-02-23 20:10         ` Bartlomiej Zolnierkiewicz
2007-04-14 19:31     ` [PATCH pata-2.6] cmd64x: add/fix enablebits (take 2) Sergei Shtylyov
2007-04-23 21:54       ` Bartlomiej Zolnierkiewicz
2007-02-15 13:53   ` [PATCH] (pata-2.6 fix queue) cmd64x: interrupt status fixes (resend) Sergei Shtylyov
2007-02-19 23:04     ` Bartlomiej Zolnierkiewicz
2007-04-14 19:17     ` [PATCH pata-2.6] cmd64x: interrupt status fixes (take 2) Sergei Shtylyov
2007-04-23 21:52       ` Bartlomiej Zolnierkiewicz
2007-02-15 19:17   ` [PATCH] (pata-2.6 fix queue) cmd64x: procfs code fixes/cleanups Sergei Shtylyov
2007-02-19 23:10     ` Bartlomiej Zolnierkiewicz
2007-04-14 19:41     ` [PATCH pata-2.6] cmd64x: procfs code fixes/cleanups (take 2) Sergei Shtylyov
2007-04-23 21:58       ` Bartlomiej Zolnierkiewicz
2007-02-16 20:15   ` [PATCH] (pata-2.6 fix queue) cmd64x: Sergei Shtylyov
2007-02-16 20:21   ` [PATCH] (pata-2.6 fix queue) cmd64x: use interrupt status from MRDMODE register Sergei Shtylyov
2007-02-23 20:09     ` Bartlomiej Zolnierkiewicz
2007-04-14 19:53     ` [PATCH pata-2.6] cmd64x: use interrupt status from MRDMODE register (take 2) Sergei Shtylyov
2007-04-23 22:03       ` Bartlomiej Zolnierkiewicz
2007-04-18 19:38     ` [PATCH pata-2.6 fix queue] hpt366: fix kernel oops with HPT302N Sergei Shtylyov
2007-04-20 19:54       ` Bartlomiej Zolnierkiewicz
2007-04-22 18:05     ` [PATCH pata-2.6 fix queue] aec62xx: fix PIO/DMA setup issues Sergei Shtylyov
2007-04-23 22:33       ` Bartlomiej Zolnierkiewicz
2007-05-10 20:01     ` [PATCH pata-2.6 fix queue] cmd64x: init. code cleanup Sergei Shtylyov
2007-05-10 20:04     ` Sergei Shtylyov
2007-05-15 21:16       ` Bartlomiej Zolnierkiewicz
2007-05-11 19:31     ` [PATCH pata-2.6 fix queue] aec62xx: rework init_setup_aec6x80() Sergei Shtylyov
2007-05-15 21:31       ` Bartlomiej Zolnierkiewicz
2007-05-11 21:11     ` [PATCH pata-2.6 fix queue] aec62xx: remove init_dma() method Sergei Shtylyov
2007-05-15 21:40       ` Bartlomiej Zolnierkiewicz
2007-05-11 21:22     ` [PATCH pata-2.6 fix queue] aec62xx: kill speedproc() method wrapper Sergei Shtylyov
2007-05-15 21:43       ` Bartlomiej Zolnierkiewicz
2007-05-16 14:20         ` Sergei Shtylyov
2007-05-23 23:33           ` Bartlomiej Zolnierkiewicz
2007-05-24 13:18             ` Sergei Shtylyov
2007-05-24 16:44     ` [PATCH pata-2.6] aec62xx: remove init_dma() method (take 2) Sergei Shtylyov
2007-05-24 16:46     ` [PATCH pata-2.6] aec62xx: kill speedproc() method wrapper " Sergei Shtylyov
2007-05-28 20:44       ` Bartlomiej Zolnierkiewicz
2007-06-05 15:15         ` Sergei Shtylyov
2007-06-08 12:22           ` Bartlomiej Zolnierkiewicz
2007-06-09 10:05             ` Sergei Shtylyov
2007-11-09 11:07     ` [PATCH] cmd64x: don't clear the other channels interrupt Sergei Shtylyov
2007-11-11 21:52       ` Bartlomiej Zolnierkiewicz
2007-11-13 20:58         ` Bartlomiej Zolnierkiewicz
2007-11-15 19:23           ` Martin Rogge
2007-11-16 13:34           ` Sergei Shtylyov
2007-02-26 20:32   ` [PATCH] (pata-2.6 fix queue) cmd64x: fix recovery time calculation (take 2) Sergei Shtylyov
2007-03-02 20:34     ` Bartlomiej Zolnierkiewicz
2007-03-03 20:17     ` [PATCH pata-2.6 fix queue] cmd64x: fix recovery time calculation (take 3) Sergei Shtylyov
2007-03-15 20:29       ` Bartlomiej Zolnierkiewicz
2007-02-27 21:49   ` [PATCH] (pata-2.6 fix queue) cmd64x: fix primary channel address setup time Sergei Shtylyov
2007-02-28 13:27     ` Sergei Shtylyov
2007-02-28 20:52   ` Sergei Shtylyov [this message]
2007-03-02 22:03     ` [PATCH] (pata-2.6 fix queue) cmd64x: add back MWDMA support Bartlomiej Zolnierkiewicz

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=200702282352.41128.sshtylyov@ru.mvista.com \
    --to=sshtylyov@ru.mvista.com \
    --cc=bzolnier@gmail.com \
    --cc=linux-ide@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.