diff options
author | Bartlomiej Zolnierkiewicz <bzolnier@gmail.com> | 2007-05-15 18:51:43 -0400 |
---|---|---|
committer | Bartlomiej Zolnierkiewicz <bzolnier@gmail.com> | 2007-05-15 18:51:43 -0400 |
commit | 5fd216bbb277b645109a889c489e13a7aafbc304 (patch) | |
tree | 9ab2016779ea6e49dff6aa49299bbc37f5381406 /drivers/ide/pci/cs5530.c | |
parent | 793a97228d3da876f42b7fb4d4a52cc8cc86dc81 (diff) |
cs5530/sc1200: add ->udma_filter methods
CS5530/SC1200 specifies that two drives on the same cable cannot mix
UDMA/MDMA. Add {cs5530,sc1200}_udma_filter() to handle this. This also
makes it possible to remove open-coded best DMA mode selection and use
standard ide_use_dma()/ide_max_dma_mode() helpers. While at it bump
version numbers.
There should be no functionality changes caused by this patch.
Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
Diffstat (limited to 'drivers/ide/pci/cs5530.c')
-rw-r--r-- | drivers/ide/pci/cs5530.c | 120 |
1 files changed, 54 insertions, 66 deletions
diff --git a/drivers/ide/pci/cs5530.c b/drivers/ide/pci/cs5530.c index b2d7c132ef4b..845500115f3c 100644 --- a/drivers/ide/pci/cs5530.c +++ b/drivers/ide/pci/cs5530.c | |||
@@ -1,10 +1,10 @@ | |||
1 | /* | 1 | /* |
2 | * linux/drivers/ide/pci/cs5530.c Version 0.7 Sept 10, 2002 | 2 | * linux/drivers/ide/pci/cs5530.c Version 0.71 Mar 10 2007 |
3 | * | 3 | * |
4 | * Copyright (C) 2000 Andre Hedrick <andre@linux-ide.org> | 4 | * Copyright (C) 2000 Andre Hedrick <andre@linux-ide.org> |
5 | * Ditto of GNU General Public License. | ||
6 | * | ||
7 | * Copyright (C) 2000 Mark Lord <mlord@pobox.com> | 5 | * Copyright (C) 2000 Mark Lord <mlord@pobox.com> |
6 | * Copyright (C) 2007 Bartlomiej Zolnierkiewicz | ||
7 | * | ||
8 | * May be copied or modified under the terms of the GNU General Public License | 8 | * May be copied or modified under the terms of the GNU General Public License |
9 | * | 9 | * |
10 | * Development of this chipset driver was funded | 10 | * Development of this chipset driver was funded |
@@ -88,79 +88,66 @@ static void cs5530_tuneproc (ide_drive_t *drive, u8 pio) /* pio=255 means "autot | |||
88 | } | 88 | } |
89 | 89 | ||
90 | /** | 90 | /** |
91 | * cs5530_config_dma - select/set DMA and UDMA modes | 91 | * cs5530_udma_filter - UDMA filter |
92 | * @drive: drive | ||
93 | * | ||
94 | * cs5530_udma_filter() does UDMA mask filtering for the given drive | ||
95 | * taking into the consideration capabilities of the mate device. | ||
96 | * | ||
97 | * The CS5530 specifies that two drives sharing a cable cannot mix | ||
98 | * UDMA/MDMA. It has to be one or the other, for the pair, though | ||
99 | * different timings can still be chosen for each drive. We could | ||
100 | * set the appropriate timing bits on the fly, but that might be | ||
101 | * a bit confusing. So, for now we statically handle this requirement | ||
102 | * by looking at our mate drive to see what it is capable of, before | ||
103 | * choosing a mode for our own drive. | ||
104 | * | ||
105 | * Note: This relies on the fact we never fail from UDMA to MWDMA2 | ||
106 | * but instead drop to PIO. | ||
107 | */ | ||
108 | |||
109 | static u8 cs5530_udma_filter(ide_drive_t *drive) | ||
110 | { | ||
111 | ide_hwif_t *hwif = drive->hwif; | ||
112 | ide_drive_t *mate = &hwif->drives[(drive->dn & 1) ^ 1]; | ||
113 | struct hd_driveid *mateid = mate->id; | ||
114 | u8 mask = hwif->ultra_mask; | ||
115 | |||
116 | if (mate->present == 0) | ||
117 | goto out; | ||
118 | |||
119 | if ((mateid->capability & 1) && __ide_dma_bad_drive(mate) == 0) { | ||
120 | if ((mateid->field_valid & 4) && (mateid->dma_ultra & 7)) | ||
121 | goto out; | ||
122 | if ((mateid->field_valid & 2) && (mateid->dma_mword & 7)) | ||
123 | mask = 0; | ||
124 | } | ||
125 | out: | ||
126 | return mask; | ||
127 | } | ||
128 | |||
129 | /** | ||
130 | * cs5530_config_dma - set DMA/UDMA mode | ||
92 | * @drive: drive to tune | 131 | * @drive: drive to tune |
93 | * | 132 | * |
94 | * cs5530_config_dma() handles selection/setting of DMA/UDMA modes | 133 | * cs5530_config_dma() handles setting of DMA/UDMA mode |
95 | * for both the chipset and drive. The CS5530 has limitations about | 134 | * for both the chipset and drive. |
96 | * mixing DMA/UDMA on the same cable. | ||
97 | */ | 135 | */ |
98 | 136 | ||
99 | static int cs5530_config_dma (ide_drive_t *drive) | 137 | static int cs5530_config_dma(ide_drive_t *drive) |
100 | { | 138 | { |
101 | int udma_ok = 1, mode = 0; | 139 | ide_hwif_t *hwif = drive->hwif; |
102 | ide_hwif_t *hwif = HWIF(drive); | 140 | unsigned int reg, timings = 0; |
103 | int unit = drive->select.b.unit; | 141 | unsigned long basereg; |
104 | ide_drive_t *mate = &hwif->drives[unit^1]; | 142 | u8 unit = drive->dn & 1, mode = 0; |
105 | struct hd_driveid *id = drive->id; | ||
106 | unsigned int reg, timings = 0; | ||
107 | unsigned long basereg; | ||
108 | 143 | ||
109 | /* | 144 | /* |
110 | * Default to DMA-off in case we run into trouble here. | 145 | * Default to DMA-off in case we run into trouble here. |
111 | */ | 146 | */ |
112 | hwif->dma_off_quietly(drive); | 147 | hwif->dma_off_quietly(drive); |
113 | 148 | ||
114 | /* | 149 | if (ide_use_dma(drive)) |
115 | * The CS5530 specifies that two drives sharing a cable cannot | 150 | mode = ide_max_dma_mode(drive); |
116 | * mix UDMA/MDMA. It has to be one or the other, for the pair, | ||
117 | * though different timings can still be chosen for each drive. | ||
118 | * We could set the appropriate timing bits on the fly, | ||
119 | * but that might be a bit confusing. So, for now we statically | ||
120 | * handle this requirement by looking at our mate drive to see | ||
121 | * what it is capable of, before choosing a mode for our own drive. | ||
122 | * | ||
123 | * Note: This relies on the fact we never fail from UDMA to MWDMA_2 | ||
124 | * but instead drop to PIO | ||
125 | */ | ||
126 | if (mate->present) { | ||
127 | struct hd_driveid *mateid = mate->id; | ||
128 | if (mateid && (mateid->capability & 1) && | ||
129 | !__ide_dma_bad_drive(mate)) { | ||
130 | if ((mateid->field_valid & 4) && | ||
131 | (mateid->dma_ultra & 7)) | ||
132 | udma_ok = 1; | ||
133 | else if ((mateid->field_valid & 2) && | ||
134 | (mateid->dma_mword & 7)) | ||
135 | udma_ok = 0; | ||
136 | else | ||
137 | udma_ok = 1; | ||
138 | } | ||
139 | } | ||
140 | |||
141 | /* | ||
142 | * Now see what the current drive is capable of, | ||
143 | * selecting UDMA only if the mate said it was ok. | ||
144 | */ | ||
145 | if (id && (id->capability & 1) && drive->autodma && | ||
146 | !__ide_dma_bad_drive(drive)) { | ||
147 | if (udma_ok && (id->field_valid & 4) && (id->dma_ultra & 7)) { | ||
148 | if (id->dma_ultra & 4) | ||
149 | mode = XFER_UDMA_2; | ||
150 | else if (id->dma_ultra & 2) | ||
151 | mode = XFER_UDMA_1; | ||
152 | else if (id->dma_ultra & 1) | ||
153 | mode = XFER_UDMA_0; | ||
154 | } | ||
155 | if (!mode && (id->field_valid & 2) && (id->dma_mword & 7)) { | ||
156 | if (id->dma_mword & 4) | ||
157 | mode = XFER_MW_DMA_2; | ||
158 | else if (id->dma_mword & 2) | ||
159 | mode = XFER_MW_DMA_1; | ||
160 | else if (id->dma_mword & 1) | ||
161 | mode = XFER_MW_DMA_0; | ||
162 | } | ||
163 | } | ||
164 | 151 | ||
165 | /* | 152 | /* |
166 | * Tell the drive to switch to the new mode; abort on failure. | 153 | * Tell the drive to switch to the new mode; abort on failure. |
@@ -332,6 +319,7 @@ static void __devinit init_hwif_cs5530 (ide_hwif_t *hwif) | |||
332 | hwif->ultra_mask = 0x07; | 319 | hwif->ultra_mask = 0x07; |
333 | hwif->mwdma_mask = 0x07; | 320 | hwif->mwdma_mask = 0x07; |
334 | 321 | ||
322 | hwif->udma_filter = cs5530_udma_filter; | ||
335 | hwif->ide_dma_check = &cs5530_config_dma; | 323 | hwif->ide_dma_check = &cs5530_config_dma; |
336 | if (!noautodma) | 324 | if (!noautodma) |
337 | hwif->autodma = 1; | 325 | hwif->autodma = 1; |