diff options
author | Bartlomiej Zolnierkiewicz <bzolnier@gmail.com> | 2010-01-18 02:18:26 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-01-19 04:24:58 -0500 |
commit | 60349ab99f2742a6f04da86724740498c7b1f885 (patch) | |
tree | b72202c5b424f14b312d5b5fd8315527e2de4610 /drivers | |
parent | 31bbb668fbe71a207d38ecd1797f4cd5b8bd710b (diff) |
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 <bzolnier@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/ide/cmd64x.c | 88 |
1 files changed, 29 insertions, 59 deletions
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 @@ | |||
7 | * Copyright (C) 1998 David S. Miller (davem@redhat.com) | 7 | * Copyright (C) 1998 David S. Miller (davem@redhat.com) |
8 | * | 8 | * |
9 | * Copyright (C) 1999-2002 Andre Hedrick <andre@linux-ide.org> | 9 | * Copyright (C) 1999-2002 Andre Hedrick <andre@linux-ide.org> |
10 | * Copyright (C) 2007-2010 Bartlomiej Zolnierkiewicz | ||
10 | * Copyright (C) 2007,2009 MontaVista Software, Inc. <source@mvista.com> | 11 | * Copyright (C) 2007,2009 MontaVista Software, Inc. <source@mvista.com> |
11 | */ | 12 | */ |
12 | 13 | ||
@@ -50,72 +51,45 @@ | |||
50 | #define UDIDETCR1 0x7B | 51 | #define UDIDETCR1 0x7B |
51 | #define DTPR1 0x7C | 52 | #define DTPR1 0x7C |
52 | 53 | ||
53 | static u8 quantize_timing(int timing, int quant) | 54 | static void cmd64x_program_timings(ide_drive_t *drive, u8 mode) |
54 | { | ||
55 | return (timing + quant - 1) / quant; | ||
56 | } | ||
57 | |||
58 | /* | ||
59 | * This routine calculates active/recovery counts and then writes them into | ||
60 | * the chipset registers. | ||
61 | */ | ||
62 | static void program_cycle_times (ide_drive_t *drive, int cycle_time, int active_time) | ||
63 | { | 55 | { |
56 | ide_hwif_t *hwif = drive->hwif; | ||
64 | struct pci_dev *dev = to_pci_dev(drive->hwif->dev); | 57 | struct pci_dev *dev = to_pci_dev(drive->hwif->dev); |
65 | int clock_time = 1000 / (ide_pci_clk ? ide_pci_clk : 33); | 58 | int bus_speed = ide_pci_clk ? ide_pci_clk : 33; |
66 | u8 cycle_count, active_count, recovery_count, drwtim; | 59 | const unsigned long T = 1000000 / bus_speed; |
67 | static const u8 recovery_values[] = | 60 | static const u8 recovery_values[] = |
68 | {15, 15, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 0}; | 61 | {15, 15, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 0}; |
62 | static const u8 setup_values[] = {0x40, 0x40, 0x40, 0x80, 0, 0xc0}; | ||
63 | static const u8 arttim_regs[4] = {ARTTIM0, ARTTIM1, ARTTIM23, ARTTIM23}; | ||
69 | static const u8 drwtim_regs[4] = {DRWTIM0, DRWTIM1, DRWTIM2, DRWTIM3}; | 64 | static const u8 drwtim_regs[4] = {DRWTIM0, DRWTIM1, DRWTIM2, DRWTIM3}; |
65 | struct ide_timing t; | ||
66 | u8 arttim = 0; | ||
70 | 67 | ||
71 | cycle_count = quantize_timing( cycle_time, clock_time); | 68 | ide_timing_compute(drive, mode, &t, T, 0); |
72 | active_count = quantize_timing(active_time, clock_time); | ||
73 | recovery_count = cycle_count - active_count; | ||
74 | 69 | ||
75 | /* | 70 | /* |
76 | * In case we've got too long recovery phase, try to lengthen | 71 | * In case we've got too long recovery phase, try to lengthen |
77 | * the active phase | 72 | * the active phase |
78 | */ | 73 | */ |
79 | if (recovery_count > 16) { | 74 | if (t.recover > 16) { |
80 | active_count += recovery_count - 16; | 75 | t.active += t.recover - 16; |
81 | recovery_count = 16; | 76 | t.recover = 16; |
82 | } | 77 | } |
83 | if (active_count > 16) /* shouldn't actually happen... */ | 78 | if (t.active > 16) /* shouldn't actually happen... */ |
84 | active_count = 16; | 79 | t.active = 16; |
85 | 80 | ||
86 | /* | 81 | /* |
87 | * Convert values to internal chipset representation | 82 | * Convert values to internal chipset representation |
88 | */ | 83 | */ |
89 | recovery_count = recovery_values[recovery_count]; | 84 | t.recover = recovery_values[t.recover]; |
90 | active_count &= 0x0f; | 85 | t.active &= 0x0f; |
91 | 86 | ||
92 | /* Program the active/recovery counts into the DRWTIM register */ | 87 | /* Program the active/recovery counts into the DRWTIM register */ |
93 | drwtim = (active_count << 4) | recovery_count; | 88 | pci_write_config_byte(dev, drwtim_regs[drive->dn], |
94 | (void) pci_write_config_byte(dev, drwtim_regs[drive->dn], drwtim); | 89 | (t.active << 4) | t.recover); |
95 | } | ||
96 | 90 | ||
97 | /* | 91 | if (mode >= XFER_SW_DMA_0) |
98 | * This routine writes into the chipset registers | 92 | return; |
99 | * PIO setup/active/recovery timings. | ||
100 | */ | ||
101 | static void cmd64x_tune_pio(ide_drive_t *drive, const u8 pio) | ||
102 | { | ||
103 | ide_hwif_t *hwif = drive->hwif; | ||
104 | struct pci_dev *dev = to_pci_dev(hwif->dev); | ||
105 | struct ide_timing *t = ide_timing_find_mode(XFER_PIO_0 + pio); | ||
106 | unsigned long setup_count; | ||
107 | unsigned int cycle_time; | ||
108 | u8 arttim = 0; | ||
109 | |||
110 | static const u8 setup_values[] = {0x40, 0x40, 0x40, 0x80, 0, 0xc0}; | ||
111 | static const u8 arttim_regs[4] = {ARTTIM0, ARTTIM1, ARTTIM23, ARTTIM23}; | ||
112 | |||
113 | cycle_time = ide_pio_cycle_time(drive, pio); | ||
114 | |||
115 | program_cycle_times(drive, cycle_time, t->active); | ||
116 | |||
117 | setup_count = quantize_timing(t->setup, | ||
118 | 1000 / (ide_pci_clk ? ide_pci_clk : 33)); | ||
119 | 93 | ||
120 | /* | 94 | /* |
121 | * The primary channel has individual address setup timing registers | 95 | * 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) | |||
126 | if (hwif->channel) { | 100 | if (hwif->channel) { |
127 | ide_drive_t *pair = ide_get_pair_dev(drive); | 101 | ide_drive_t *pair = ide_get_pair_dev(drive); |
128 | 102 | ||
129 | ide_set_drivedata(drive, (void *)setup_count); | 103 | ide_set_drivedata(drive, (void *)(unsigned long)t.setup); |
130 | 104 | ||
131 | if (pair) | 105 | if (pair) |
132 | setup_count = max_t(u8, setup_count, | 106 | t.setup = max_t(u8, t.setup, |
133 | (unsigned long)ide_get_drivedata(pair)); | 107 | (unsigned long)ide_get_drivedata(pair)); |
134 | } | 108 | } |
135 | 109 | ||
136 | if (setup_count > 5) /* shouldn't actually happen... */ | 110 | if (t.setup > 5) /* shouldn't actually happen... */ |
137 | setup_count = 5; | 111 | t.setup = 5; |
138 | 112 | ||
139 | /* | 113 | /* |
140 | * Program the address setup clocks into the ARTTIM registers. | 114 | * 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) | |||
144 | if (hwif->channel) | 118 | if (hwif->channel) |
145 | arttim &= ~ARTTIM23_INTR_CH1; | 119 | arttim &= ~ARTTIM23_INTR_CH1; |
146 | arttim &= ~0xc0; | 120 | arttim &= ~0xc0; |
147 | arttim |= setup_values[setup_count]; | 121 | arttim |= setup_values[t.setup]; |
148 | (void) pci_write_config_byte(dev, arttim_regs[drive->dn], arttim); | 122 | (void) pci_write_config_byte(dev, arttim_regs[drive->dn], arttim); |
149 | } | 123 | } |
150 | 124 | ||
@@ -162,7 +136,7 @@ static void cmd64x_set_pio_mode(ide_drive_t *drive, const u8 pio) | |||
162 | if (pio == 8 || pio == 9) | 136 | if (pio == 8 || pio == 9) |
163 | return; | 137 | return; |
164 | 138 | ||
165 | cmd64x_tune_pio(drive, pio); | 139 | cmd64x_program_timings(drive, XFER_PIO_0 + pio); |
166 | } | 140 | } |
167 | 141 | ||
168 | static void cmd64x_set_dma_mode(ide_drive_t *drive, const u8 speed) | 142 | 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) | |||
197 | regU |= unit ? 0xC2 : 0x31; | 171 | regU |= unit ? 0xC2 : 0x31; |
198 | break; | 172 | break; |
199 | case XFER_MW_DMA_2: | 173 | case XFER_MW_DMA_2: |
200 | program_cycle_times(drive, 120, 70); | ||
201 | break; | ||
202 | case XFER_MW_DMA_1: | 174 | case XFER_MW_DMA_1: |
203 | program_cycle_times(drive, 150, 80); | ||
204 | break; | ||
205 | case XFER_MW_DMA_0: | 175 | case XFER_MW_DMA_0: |
206 | program_cycle_times(drive, 480, 215); | 176 | cmd64x_program_timings(drive, speed); |
207 | break; | 177 | break; |
208 | } | 178 | } |
209 | 179 | ||
@@ -471,6 +441,6 @@ static void __exit cmd64x_ide_exit(void) | |||
471 | module_init(cmd64x_ide_init); | 441 | module_init(cmd64x_ide_init); |
472 | module_exit(cmd64x_ide_exit); | 442 | module_exit(cmd64x_ide_exit); |
473 | 443 | ||
474 | MODULE_AUTHOR("Eddie Dost, David Miller, Andre Hedrick"); | 444 | MODULE_AUTHOR("Eddie Dost, David Miller, Andre Hedrick, Bartlomiej Zolnierkiewicz"); |
475 | MODULE_DESCRIPTION("PCI driver module for CMD64x IDE"); | 445 | MODULE_DESCRIPTION("PCI driver module for CMD64x IDE"); |
476 | MODULE_LICENSE("GPL"); | 446 | MODULE_LICENSE("GPL"); |