From 60349ab99f2742a6f04da86724740498c7b1f885 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Mon, 18 Jan 2010 07:18:26 +0000 Subject: cmd64x: fix PIO and MWDMA timings calculations Just use the standard ide_timing_compute() helper to calculate PIO and MWDMA timings. This fixes some issues with the open-coded version like allowing faster MWDMA timings than the ones required by the current PIO mode or not accounting for the enhanced MWDMA cycle time specified by the device. Based on libata pata_cmd64x host driver. Signed-off-by: Bartlomiej Zolnierkiewicz Signed-off-by: David S. Miller --- drivers/ide/cmd64x.c | 88 +++++++++++++++++----------------------------------- 1 file changed, 29 insertions(+), 59 deletions(-) (limited to 'drivers/ide/cmd64x.c') diff --git a/drivers/ide/cmd64x.c b/drivers/ide/cmd64x.c index f2500c8826bb..5c5dd90d032b 100644 --- a/drivers/ide/cmd64x.c +++ b/drivers/ide/cmd64x.c @@ -7,6 +7,7 @@ * Copyright (C) 1998 David S. Miller (davem@redhat.com) * * Copyright (C) 1999-2002 Andre Hedrick + * Copyright (C) 2007-2010 Bartlomiej Zolnierkiewicz * Copyright (C) 2007,2009 MontaVista Software, Inc. */ @@ -50,72 +51,45 @@ #define UDIDETCR1 0x7B #define DTPR1 0x7C -static u8 quantize_timing(int timing, int quant) -{ - return (timing + quant - 1) / quant; -} - -/* - * This routine calculates active/recovery counts and then writes them into - * the chipset registers. - */ -static void program_cycle_times (ide_drive_t *drive, int cycle_time, int active_time) +static void cmd64x_program_timings(ide_drive_t *drive, u8 mode) { + ide_hwif_t *hwif = drive->hwif; struct pci_dev *dev = to_pci_dev(drive->hwif->dev); - int clock_time = 1000 / (ide_pci_clk ? ide_pci_clk : 33); - u8 cycle_count, active_count, recovery_count, drwtim; + int bus_speed = ide_pci_clk ? ide_pci_clk : 33; + const unsigned long T = 1000000 / bus_speed; 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 setup_values[] = {0x40, 0x40, 0x40, 0x80, 0, 0xc0}; + static const u8 arttim_regs[4] = {ARTTIM0, ARTTIM1, ARTTIM23, ARTTIM23}; static const u8 drwtim_regs[4] = {DRWTIM0, DRWTIM1, DRWTIM2, DRWTIM3}; + struct ide_timing t; + u8 arttim = 0; - cycle_count = quantize_timing( cycle_time, clock_time); - active_count = quantize_timing(active_time, clock_time); - recovery_count = cycle_count - active_count; + ide_timing_compute(drive, mode, &t, T, 0); /* * In case we've got too long recovery phase, try to lengthen * the active phase */ - if (recovery_count > 16) { - active_count += recovery_count - 16; - recovery_count = 16; + if (t.recover > 16) { + t.active += t.recover - 16; + t.recover = 16; } - if (active_count > 16) /* shouldn't actually happen... */ - active_count = 16; + if (t.active > 16) /* shouldn't actually happen... */ + t.active = 16; /* * Convert values to internal chipset representation */ - recovery_count = recovery_values[recovery_count]; - active_count &= 0x0f; + t.recover = recovery_values[t.recover]; + t.active &= 0x0f; /* 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); -} + pci_write_config_byte(dev, drwtim_regs[drive->dn], + (t.active << 4) | t.recover); -/* - * This routine writes into the chipset registers - * PIO setup/active/recovery timings. - */ -static void cmd64x_tune_pio(ide_drive_t *drive, const u8 pio) -{ - ide_hwif_t *hwif = drive->hwif; - struct pci_dev *dev = to_pci_dev(hwif->dev); - struct ide_timing *t = ide_timing_find_mode(XFER_PIO_0 + pio); - unsigned long setup_count; - unsigned int cycle_time; - u8 arttim = 0; - - static const u8 setup_values[] = {0x40, 0x40, 0x40, 0x80, 0, 0xc0}; - static const u8 arttim_regs[4] = {ARTTIM0, ARTTIM1, ARTTIM23, ARTTIM23}; - - cycle_time = ide_pio_cycle_time(drive, pio); - - program_cycle_times(drive, cycle_time, t->active); - - setup_count = quantize_timing(t->setup, - 1000 / (ide_pci_clk ? ide_pci_clk : 33)); + if (mode >= XFER_SW_DMA_0) + return; /* * The primary channel has individual address setup timing registers @@ -126,15 +100,15 @@ static void cmd64x_tune_pio(ide_drive_t *drive, const u8 pio) if (hwif->channel) { ide_drive_t *pair = ide_get_pair_dev(drive); - ide_set_drivedata(drive, (void *)setup_count); + ide_set_drivedata(drive, (void *)(unsigned long)t.setup); if (pair) - setup_count = max_t(u8, setup_count, + t.setup = max_t(u8, t.setup, (unsigned long)ide_get_drivedata(pair)); } - if (setup_count > 5) /* shouldn't actually happen... */ - setup_count = 5; + if (t.setup > 5) /* shouldn't actually happen... */ + t.setup = 5; /* * Program the address setup clocks into the ARTTIM registers. @@ -144,7 +118,7 @@ static void cmd64x_tune_pio(ide_drive_t *drive, const u8 pio) if (hwif->channel) arttim &= ~ARTTIM23_INTR_CH1; arttim &= ~0xc0; - arttim |= setup_values[setup_count]; + arttim |= setup_values[t.setup]; (void) pci_write_config_byte(dev, arttim_regs[drive->dn], arttim); } @@ -162,7 +136,7 @@ static void cmd64x_set_pio_mode(ide_drive_t *drive, const u8 pio) if (pio == 8 || pio == 9) return; - cmd64x_tune_pio(drive, pio); + cmd64x_program_timings(drive, XFER_PIO_0 + pio); } static void cmd64x_set_dma_mode(ide_drive_t *drive, const u8 speed) @@ -197,13 +171,9 @@ static void cmd64x_set_dma_mode(ide_drive_t *drive, const u8 speed) 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); + cmd64x_program_timings(drive, speed); break; } @@ -471,6 +441,6 @@ static void __exit cmd64x_ide_exit(void) module_init(cmd64x_ide_init); module_exit(cmd64x_ide_exit); -MODULE_AUTHOR("Eddie Dost, David Miller, Andre Hedrick"); +MODULE_AUTHOR("Eddie Dost, David Miller, Andre Hedrick, Bartlomiej Zolnierkiewicz"); MODULE_DESCRIPTION("PCI driver module for CMD64x IDE"); MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 22cabc2619a58d3e5f95bb8df823da535e103bf4 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Mon, 18 Jan 2010 07:18:38 +0000 Subject: cmd64x: remove superfluous checks from cmd64x_set_dma_mode() Signed-off-by: Bartlomiej Zolnierkiewicz Signed-off-by: David S. Miller --- drivers/ide/cmd64x.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers/ide/cmd64x.c') diff --git a/drivers/ide/cmd64x.c b/drivers/ide/cmd64x.c index 5c5dd90d032b..9f89f3116df0 100644 --- a/drivers/ide/cmd64x.c +++ b/drivers/ide/cmd64x.c @@ -146,10 +146,8 @@ static void cmd64x_set_dma_mode(ide_drive_t *drive, const u8 speed) u8 unit = drive->dn & 0x01; u8 regU = 0, pciU = hwif->channel ? UDIDETCR1 : UDIDETCR0; - if (speed >= XFER_SW_DMA_0) { - (void) pci_read_config_byte(dev, pciU, ®U); - regU &= ~(unit ? 0xCA : 0x35); - } + pci_read_config_byte(dev, pciU, ®U); + regU &= ~(unit ? 0xCA : 0x35); switch(speed) { case XFER_UDMA_5: @@ -177,8 +175,7 @@ static void cmd64x_set_dma_mode(ide_drive_t *drive, const u8 speed) break; } - if (speed >= XFER_SW_DMA_0) - (void) pci_write_config_byte(dev, pciU, regU); + pci_write_config_byte(dev, pciU, regU); } static void cmd648_clear_irq(ide_drive_t *drive) -- cgit v1.2.3 From e085b3cae85af47eb0a3eda3186bd898310fb322 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Tue, 19 Jan 2010 01:44:41 -0800 Subject: ide: change ->set_pio_mode method parameters Change ->set_pio_mode method parameters to match ->set_piomode method used in struct ata_port_operations. Signed-off-by: Bartlomiej Zolnierkiewicz Signed-off-by: David S. Miller --- drivers/ide/cmd64x.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/ide/cmd64x.c') diff --git a/drivers/ide/cmd64x.c b/drivers/ide/cmd64x.c index 9f89f3116df0..0b11745937e7 100644 --- a/drivers/ide/cmd64x.c +++ b/drivers/ide/cmd64x.c @@ -127,8 +127,10 @@ static void cmd64x_program_timings(ide_drive_t *drive, u8 mode) * Special cases are 8: prefetch off, 9: prefetch on (both never worked) */ -static void cmd64x_set_pio_mode(ide_drive_t *drive, const u8 pio) +static void cmd64x_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) { + const u8 pio = drive->pio_mode - XFER_PIO_0; + /* * Filter out the prefetch control values * to prevent PIO5 from being programmed -- cgit v1.2.3 From 8776168ca2151850164af1de5565d01f7b8b2c53 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Tue, 19 Jan 2010 01:45:29 -0800 Subject: ide: change ->set_dma_mode method parameters Change ->set_dma_mode method parameters to match ->set_dmamode method used in struct ata_port_operations. Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/cmd64x.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/ide/cmd64x.c') diff --git a/drivers/ide/cmd64x.c b/drivers/ide/cmd64x.c index 0b11745937e7..a65a69171250 100644 --- a/drivers/ide/cmd64x.c +++ b/drivers/ide/cmd64x.c @@ -141,12 +141,12 @@ static void cmd64x_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) cmd64x_program_timings(drive, XFER_PIO_0 + pio); } -static void cmd64x_set_dma_mode(ide_drive_t *drive, const u8 speed) +static void cmd64x_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive) { - ide_hwif_t *hwif = drive->hwif; struct pci_dev *dev = to_pci_dev(hwif->dev); u8 unit = drive->dn & 0x01; u8 regU = 0, pciU = hwif->channel ? UDIDETCR1 : UDIDETCR0; + const u8 speed = drive->dma_mode; pci_read_config_byte(dev, pciU, ®U); regU &= ~(unit ? 0xCA : 0x35); -- cgit v1.2.3 From 23d874054663efaf18340dc554df1b935820cbab Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Mon, 18 Jan 2010 07:21:41 +0000 Subject: cmd64x: fix handling of address setup timings Account for the requirements of the DMA mode currently used. Signed-off-by: Bartlomiej Zolnierkiewicz Signed-off-by: David S. Miller --- drivers/ide/cmd64x.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) (limited to 'drivers/ide/cmd64x.c') diff --git a/drivers/ide/cmd64x.c b/drivers/ide/cmd64x.c index a65a69171250..5f80312e636b 100644 --- a/drivers/ide/cmd64x.c +++ b/drivers/ide/cmd64x.c @@ -88,9 +88,6 @@ static void cmd64x_program_timings(ide_drive_t *drive, u8 mode) pci_write_config_byte(dev, drwtim_regs[drive->dn], (t.active << 4) | t.recover); - if (mode >= XFER_SW_DMA_0) - return; - /* * The primary channel has individual address setup timing registers * for each drive and the hardware selects the slowest timing itself. @@ -100,11 +97,17 @@ static void cmd64x_program_timings(ide_drive_t *drive, u8 mode) if (hwif->channel) { ide_drive_t *pair = ide_get_pair_dev(drive); - ide_set_drivedata(drive, (void *)(unsigned long)t.setup); + if (pair) { + struct ide_timing tp; - if (pair) - t.setup = max_t(u8, t.setup, - (unsigned long)ide_get_drivedata(pair)); + ide_timing_compute(pair, pair->pio_mode, &tp, T, 0); + ide_timing_merge(&t, &tp, &t, IDE_TIMING_SETUP); + if (pair->dma_mode) { + ide_timing_compute(pair, pair->dma_mode, + &tp, T, 0); + ide_timing_merge(&tp, &t, &t, IDE_TIMING_SETUP); + } + } } if (t.setup > 5) /* shouldn't actually happen... */ -- cgit v1.2.3