]>
Commit | Line | Data |
---|---|---|
00e5a55c BS |
1 | Subject: Efika ATA DMA |
2 | From: Matt Sealey <matt@genesi-usa.com> | |
3 | References: 445856 | |
4 | ||
5 | Enables UDMA operation for ATA disks on Efika, meaning faster (up to | |
6 | ~33MB/s, from ~1.2MB/s) access and lower (5-10% from 40-80%) CPU usage. | |
7 | ||
8 | Signed-off-by: Olaf Hering <olh@suse.de> | |
9 | ||
10 | --- | |
11 | arch/powerpc/sysdev/bestcomm/ata.c | 3 | |
12 | arch/powerpc/sysdev/bestcomm/ata.h | 2 | |
13 | arch/powerpc/sysdev/bestcomm/bestcomm.c | 7 | |
14 | arch/powerpc/sysdev/bestcomm/bestcomm.h | 33 +- | |
15 | arch/powerpc/sysdev/bestcomm/bestcomm_priv.h | 20 + | |
16 | drivers/ata/pata_mpc52xx.c | 440 +++++++++++++++++++++++++-- | |
17 | 6 files changed, 473 insertions(+), 32 deletions(-) | |
18 | ||
19 | --- a/arch/powerpc/sysdev/bestcomm/ata.c | |
20 | +++ b/arch/powerpc/sysdev/bestcomm/ata.c | |
21 | @@ -61,6 +61,9 @@ bcom_ata_init(int queue_len, int maxbufs | |
22 | struct bcom_ata_var *var; | |
23 | struct bcom_ata_inc *inc; | |
24 | ||
25 | + /* Prefetch breaks ATA DMA. Turn it off for ATA DMA */ | |
26 | + bcom_disable_prefetch(); | |
27 | + | |
28 | tsk = bcom_task_alloc(queue_len, sizeof(struct bcom_ata_bd), 0); | |
29 | if (!tsk) | |
30 | return NULL; | |
31 | --- a/arch/powerpc/sysdev/bestcomm/ata.h | |
32 | +++ b/arch/powerpc/sysdev/bestcomm/ata.h | |
33 | @@ -16,8 +16,8 @@ | |
34 | ||
35 | struct bcom_ata_bd { | |
36 | u32 status; | |
37 | - u32 dst_pa; | |
38 | u32 src_pa; | |
39 | + u32 dst_pa; | |
40 | }; | |
41 | ||
42 | extern struct bcom_task * | |
43 | --- a/arch/powerpc/sysdev/bestcomm/bestcomm.c | |
44 | +++ b/arch/powerpc/sysdev/bestcomm/bestcomm.c | |
45 | @@ -279,7 +279,6 @@ bcom_engine_init(void) | |
46 | int task; | |
47 | phys_addr_t tdt_pa, ctx_pa, var_pa, fdt_pa; | |
48 | unsigned int tdt_size, ctx_size, var_size, fdt_size; | |
49 | - u16 regval; | |
50 | ||
51 | /* Allocate & clear SRAM zones for FDT, TDTs, contexts and vars/incs */ | |
52 | tdt_size = BCOM_MAX_TASKS * sizeof(struct bcom_tdt); | |
53 | @@ -331,10 +330,8 @@ bcom_engine_init(void) | |
54 | out_8(&bcom_eng->regs->ipr[BCOM_INITIATOR_ALWAYS], BCOM_IPR_ALWAYS); | |
55 | ||
56 | /* Disable COMM Bus Prefetch on the original 5200; it's broken */ | |
57 | - if ((mfspr(SPRN_SVR) & MPC5200_SVR_MASK) == MPC5200_SVR) { | |
58 | - regval = in_be16(&bcom_eng->regs->PtdCntrl); | |
59 | - out_be16(&bcom_eng->regs->PtdCntrl, regval | 1); | |
60 | - } | |
61 | + if ((mfspr(SPRN_SVR) & MPC5200_SVR_MASK) == MPC5200_SVR) | |
62 | + bcom_disable_prefetch(); | |
63 | ||
64 | /* Init lock */ | |
65 | spin_lock_init(&bcom_eng->lock); | |
66 | --- a/arch/powerpc/sysdev/bestcomm/bestcomm.h | |
67 | +++ b/arch/powerpc/sysdev/bestcomm/bestcomm.h | |
68 | @@ -140,15 +140,29 @@ bcom_queue_full(struct bcom_task *tsk) | |
69 | } | |
70 | ||
71 | /** | |
72 | + * bcom_get_bd - Get a BD from the queue | |
73 | + * @tsk: The BestComm task structure | |
74 | + * index: Index of the BD to fetch | |
75 | + */ | |
76 | +static inline struct bcom_bd | |
77 | +*bcom_get_bd(struct bcom_task *tsk, unsigned int index) | |
78 | +{ | |
79 | + return tsk->bd + index * tsk->bd_size; | |
80 | +} | |
81 | + | |
82 | +/** | |
83 | * bcom_buffer_done - Checks if a BestComm | |
84 | * @tsk: The BestComm task structure | |
85 | */ | |
86 | static inline int | |
87 | bcom_buffer_done(struct bcom_task *tsk) | |
88 | { | |
89 | + struct bcom_bd *bd; | |
90 | if (bcom_queue_empty(tsk)) | |
91 | return 0; | |
92 | - return !(tsk->bd[tsk->outdex].status & BCOM_BD_READY); | |
93 | + | |
94 | + bd = bcom_get_bd(tsk, tsk->outdex); | |
95 | + return !(bd->status & BCOM_BD_READY); | |
96 | } | |
97 | ||
98 | /** | |
99 | @@ -160,16 +174,21 @@ bcom_buffer_done(struct bcom_task *tsk) | |
100 | static inline struct bcom_bd * | |
101 | bcom_prepare_next_buffer(struct bcom_task *tsk) | |
102 | { | |
103 | - tsk->bd[tsk->index].status = 0; /* cleanup last status */ | |
104 | - return &tsk->bd[tsk->index]; | |
105 | + struct bcom_bd *bd; | |
106 | + | |
107 | + bd = bcom_get_bd(tsk, tsk->index); | |
108 | + bd->status = 0; /* cleanup last status */ | |
109 | + return bd; | |
110 | } | |
111 | ||
112 | static inline void | |
113 | bcom_submit_next_buffer(struct bcom_task *tsk, void *cookie) | |
114 | { | |
115 | + struct bcom_bd *bd = bcom_get_bd(tsk, tsk->index); | |
116 | + | |
117 | tsk->cookie[tsk->index] = cookie; | |
118 | mb(); /* ensure the bd is really up-to-date */ | |
119 | - tsk->bd[tsk->index].status |= BCOM_BD_READY; | |
120 | + bd->status |= BCOM_BD_READY; | |
121 | tsk->index = _bcom_next_index(tsk); | |
122 | if (tsk->flags & BCOM_FLAGS_ENABLE_TASK) | |
123 | bcom_enable(tsk); | |
124 | @@ -179,10 +198,12 @@ static inline void * | |
125 | bcom_retrieve_buffer(struct bcom_task *tsk, u32 *p_status, struct bcom_bd **p_bd) | |
126 | { | |
127 | void *cookie = tsk->cookie[tsk->outdex]; | |
128 | + struct bcom_bd *bd = bcom_get_bd(tsk, tsk->outdex); | |
129 | + | |
130 | if (p_status) | |
131 | - *p_status = tsk->bd[tsk->outdex].status; | |
132 | + *p_status = bd->status; | |
133 | if (p_bd) | |
134 | - *p_bd = &tsk->bd[tsk->outdex]; | |
135 | + *p_bd = bd; | |
136 | tsk->outdex = _bcom_next_outdex(tsk); | |
137 | return cookie; | |
138 | } | |
139 | --- a/arch/powerpc/sysdev/bestcomm/bestcomm_priv.h | |
140 | +++ b/arch/powerpc/sysdev/bestcomm/bestcomm_priv.h | |
141 | @@ -198,8 +198,8 @@ struct bcom_task_header { | |
142 | #define BCOM_IPR_SCTMR_1 2 | |
143 | #define BCOM_IPR_FEC_RX 6 | |
144 | #define BCOM_IPR_FEC_TX 5 | |
145 | -#define BCOM_IPR_ATA_RX 4 | |
146 | -#define BCOM_IPR_ATA_TX 3 | |
147 | +#define BCOM_IPR_ATA_RX 7 | |
148 | +#define BCOM_IPR_ATA_TX 7 | |
149 | #define BCOM_IPR_SCPCI_RX 2 | |
150 | #define BCOM_IPR_SCPCI_TX 2 | |
151 | #define BCOM_IPR_PSC3_RX 2 | |
152 | @@ -241,6 +241,22 @@ extern void bcom_set_initiator(int task, | |
153 | ||
154 | #define TASK_ENABLE 0x8000 | |
155 | ||
156 | +/** | |
157 | + * bcom_disable_prefetch - Hook to disable bus prefetching | |
158 | + * | |
159 | + * ATA DMA and the original MPC5200 need this due to silicon bugs. At the | |
160 | + * moment disabling prefetch is a one-way street. There is no mechanism | |
161 | + * in place to turn prefetch back on after it has been disabled. There is | |
162 | + * no reason it couldn't be done, it would just be more complex to implement. | |
163 | + */ | |
164 | +static inline void bcom_disable_prefetch(void) | |
165 | +{ | |
166 | + u16 regval; | |
167 | + | |
168 | + regval = in_be16(&bcom_eng->regs->PtdCntrl); | |
169 | + out_be16(&bcom_eng->regs->PtdCntrl, regval | 1); | |
170 | +}; | |
171 | + | |
172 | static inline void | |
173 | bcom_enable_task(int task) | |
174 | { | |
175 | --- a/drivers/ata/pata_mpc52xx.c | |
176 | +++ b/drivers/ata/pata_mpc52xx.c | |
177 | @@ -6,6 +6,9 @@ | |
178 | * Copyright (C) 2006 Sylvain Munaut <tnt@246tNt.com> | |
179 | * Copyright (C) 2003 Mipsys - Benjamin Herrenschmidt | |
180 | * | |
181 | + * UDMA support based on patches by Freescale (Bernard Kuhn, John Rigby), | |
182 | + * Domen Puncer and Tim Yamin. | |
183 | + * | |
184 | * This file is licensed under the terms of the GNU General Public License | |
185 | * version 2. This program is licensed "as is" without any warranty of any | |
186 | * kind, whether express or implied. | |
187 | @@ -18,27 +21,46 @@ | |
188 | #include <linux/libata.h> | |
189 | #include <linux/of_platform.h> | |
190 | ||
191 | +#include <asm/cacheflush.h> | |
192 | #include <asm/types.h> | |
193 | #include <asm/prom.h> | |
194 | #include <asm/mpc52xx.h> | |
195 | ||
196 | +#include <sysdev/bestcomm/bestcomm.h> | |
197 | +#include <sysdev/bestcomm/bestcomm_priv.h> | |
198 | +#include <sysdev/bestcomm/ata.h> | |
199 | ||
200 | #define DRV_NAME "mpc52xx_ata" | |
201 | #define DRV_VERSION "0.1.2" | |
202 | ||
203 | - | |
204 | /* Private structures used by the driver */ | |
205 | struct mpc52xx_ata_timings { | |
206 | u32 pio1; | |
207 | u32 pio2; | |
208 | + u32 mdma1; | |
209 | + u32 mdma2; | |
210 | + u32 udma1; | |
211 | + u32 udma2; | |
212 | + u32 udma3; | |
213 | + u32 udma4; | |
214 | + u32 udma5; | |
215 | + int using_udma; | |
216 | }; | |
217 | ||
218 | struct mpc52xx_ata_priv { | |
219 | unsigned int ipb_period; | |
220 | struct mpc52xx_ata __iomem * ata_regs; | |
221 | + phys_addr_t ata_regs_pa; | |
222 | int ata_irq; | |
223 | struct mpc52xx_ata_timings timings[2]; | |
224 | int csel; | |
225 | + | |
226 | + /* DMA */ | |
227 | + struct bcom_task *dmatsk; | |
228 | + const struct udmaspec *udmaspec; | |
229 | + const struct mdmaspec *mdmaspec; | |
230 | + int mpc52xx_ata_dma_last_write; | |
231 | + int waiting_for_dma; | |
232 | }; | |
233 | ||
234 | ||
235 | @@ -53,6 +75,107 @@ static const int ataspec_ta[5] = { 35 | |
236 | ||
237 | #define CALC_CLKCYC(c,v) ((((v)+(c)-1)/(c))) | |
238 | ||
239 | +/* ======================================================================== */ | |
240 | + | |
241 | +/* ATAPI-4 MDMA specs (in clocks) */ | |
242 | +struct mdmaspec { | |
243 | + u32 t0M; | |
244 | + u32 td; | |
245 | + u32 th; | |
246 | + u32 tj; | |
247 | + u32 tkw; | |
248 | + u32 tm; | |
249 | + u32 tn; | |
250 | +}; | |
251 | + | |
252 | +static const struct mdmaspec mdmaspec66[3] = { | |
253 | + { .t0M = 32, .td = 15, .th = 2, .tj = 2, .tkw = 15, .tm = 4, .tn = 1 }, | |
254 | + { .t0M = 10, .td = 6, .th = 1, .tj = 1, .tkw = 4, .tm = 2, .tn = 1 }, | |
255 | + { .t0M = 8, .td = 5, .th = 1, .tj = 1, .tkw = 2, .tm = 2, .tn = 1 }, | |
256 | +}; | |
257 | + | |
258 | +static const struct mdmaspec mdmaspec132[3] = { | |
259 | + { .t0M = 64, .td = 29, .th = 3, .tj = 3, .tkw = 29, .tm = 7, .tn = 2 }, | |
260 | + { .t0M = 20, .td = 11, .th = 2, .tj = 1, .tkw = 7, .tm = 4, .tn = 1 }, | |
261 | + { .t0M = 16, .td = 10, .th = 2, .tj = 1, .tkw = 4, .tm = 4, .tn = 1 }, | |
262 | +}; | |
263 | + | |
264 | +/* ATAPI-4 UDMA specs (in clocks) */ | |
265 | +struct udmaspec { | |
266 | + u32 tcyc; | |
267 | + u32 t2cyc; | |
268 | + u32 tds; | |
269 | + u32 tdh; | |
270 | + u32 tdvs; | |
271 | + u32 tdvh; | |
272 | + u32 tfs; | |
273 | + u32 tli; | |
274 | + u32 tmli; | |
275 | + u32 taz; | |
276 | + u32 tzah; | |
277 | + u32 tenv; | |
278 | + u32 tsr; | |
279 | + u32 trfs; | |
280 | + u32 trp; | |
281 | + u32 tack; | |
282 | + u32 tss; | |
283 | +}; | |
284 | + | |
285 | +static const struct udmaspec udmaspec66[6] = { | |
286 | + { .tcyc = 8, .t2cyc = 16, .tds = 1, .tdh = 1, .tdvs = 5, .tdvh = 1, | |
287 | + .tfs = 16, .tli = 10, .tmli = 2, .taz = 1, .tzah = 2, .tenv = 2, | |
288 | + .tsr = 3, .trfs = 5, .trp = 11, .tack = 2, .tss = 4, | |
289 | + }, | |
290 | + { .tcyc = 5, .t2cyc = 11, .tds = 1, .tdh = 1, .tdvs = 4, .tdvh = 1, | |
291 | + .tfs = 14, .tli = 10, .tmli = 2, .taz = 1, .tzah = 2, .tenv = 2, | |
292 | + .tsr = 2, .trfs = 5, .trp = 9, .tack = 2, .tss = 4, | |
293 | + }, | |
294 | + { .tcyc = 4, .t2cyc = 8, .tds = 1, .tdh = 1, .tdvs = 3, .tdvh = 1, | |
295 | + .tfs = 12, .tli = 10, .tmli = 2, .taz = 1, .tzah = 2, .tenv = 2, | |
296 | + .tsr = 2, .trfs = 4, .trp = 7, .tack = 2, .tss = 4, | |
297 | + }, | |
298 | + { .tcyc = 3, .t2cyc = 6, .tds = 1, .tdh = 1, .tdvs = 2, .tdvh = 1, | |
299 | + .tfs = 9, .tli = 7, .tmli = 2, .taz = 1, .tzah = 2, .tenv = 2, | |
300 | + .tsr = 2, .trfs = 4, .trp = 7, .tack = 2, .tss = 4, | |
301 | + }, | |
302 | + { .tcyc = 2, .t2cyc = 4, .tds = 1, .tdh = 1, .tdvs = 1, .tdvh = 1, | |
303 | + .tfs = 8, .tli = 8, .tmli = 2, .taz = 1, .tzah = 2, .tenv = 2, | |
304 | + .tsr = 2, .trfs = 4, .trp = 7, .tack = 2, .tss = 4, | |
305 | + }, | |
306 | + { .tcyc = 2, .t2cyc = 2, .tds = 1, .tdh = 1, .tdvs = 1, .tdvh = 1, | |
307 | + .tfs = 6, .tli = 5, .tmli = 2, .taz = 1, .tzah = 2, .tenv = 2, | |
308 | + .tsr = 2, .trfs = 4, .trp = 6, .tack = 2, .tss = 4, | |
309 | + }, | |
310 | +}; | |
311 | + | |
312 | +static const struct udmaspec udmaspec132[6] = { | |
313 | + { .tcyc = 15, .t2cyc = 31, .tds = 2, .tdh = 1, .tdvs = 10, .tdvh = 1, | |
314 | + .tfs = 30, .tli = 20, .tmli = 3, .taz = 2, .tzah = 3, .tenv = 3, | |
315 | + .tsr = 7, .trfs = 10, .trp = 22, .tack = 3, .tss = 7, | |
316 | + }, | |
317 | + { .tcyc = 10, .t2cyc = 21, .tds = 2, .tdh = 1, .tdvs = 7, .tdvh = 1, | |
318 | + .tfs = 27, .tli = 20, .tmli = 3, .taz = 2, .tzah = 3, .tenv = 3, | |
319 | + .tsr = 4, .trfs = 10, .trp = 17, .tack = 3, .tss = 7, | |
320 | + }, | |
321 | + { .tcyc = 6, .t2cyc = 12, .tds = 1, .tdh = 1, .tdvs = 5, .tdvh = 1, | |
322 | + .tfs = 23, .tli = 20, .tmli = 3, .taz = 2, .tzah = 3, .tenv = 3, | |
323 | + .tsr = 3, .trfs = 8, .trp = 14, .tack = 3, .tss = 7, | |
324 | + }, | |
325 | + { .tcyc = 7, .t2cyc = 12, .tds = 1, .tdh = 1, .tdvs = 3, .tdvh = 1, | |
326 | + .tfs = 15, .tli = 13, .tmli = 3, .taz = 2, .tzah = 3, .tenv = 3, | |
327 | + .tsr = 3, .trfs = 8, .trp = 14, .tack = 3, .tss = 7, | |
328 | + }, | |
329 | + { .tcyc = 2, .t2cyc = 5, .tds = 0, .tdh = 0, .tdvs = 1, .tdvh = 1, | |
330 | + .tfs = 16, .tli = 14, .tmli = 2, .taz = 1, .tzah = 2, .tenv = 2, | |
331 | + .tsr = 2, .trfs = 7, .trp = 13, .tack = 2, .tss = 6, | |
332 | + }, | |
333 | + { .tcyc = 3, .t2cyc = 6, .tds = 1, .tdh = 1, .tdvs = 1, .tdvh = 1, | |
334 | + .tfs = 12, .tli = 10, .tmli = 3, .taz = 2, .tzah = 3, .tenv = 3, | |
335 | + .tsr = 3, .trfs = 7, .trp = 12, .tack = 3, .tss = 7, | |
336 | + }, | |
337 | +}; | |
338 | + | |
339 | +/* ======================================================================== */ | |
340 | ||
341 | /* Bit definitions inside the registers */ | |
342 | #define MPC52xx_ATA_HOSTCONF_SMR 0x80000000UL /* State machine reset */ | |
343 | @@ -66,6 +189,7 @@ static const int ataspec_ta[5] = { 35 | |
344 | #define MPC52xx_ATA_HOSTSTAT_WERR 0x01000000UL /* Write Error */ | |
345 | ||
346 | #define MPC52xx_ATA_FIFOSTAT_EMPTY 0x01 /* FIFO Empty */ | |
347 | +#define MPC52xx_ATA_FIFOSTAT_ERROR 0x40 /* FIFO Error */ | |
348 | ||
349 | #define MPC52xx_ATA_DMAMODE_WRITE 0x01 /* Write DMA */ | |
350 | #define MPC52xx_ATA_DMAMODE_READ 0x02 /* Read DMA */ | |
351 | @@ -75,6 +199,8 @@ static const int ataspec_ta[5] = { 35 | |
352 | #define MPC52xx_ATA_DMAMODE_FR 0x20 /* FIFO Reset */ | |
353 | #define MPC52xx_ATA_DMAMODE_HUT 0x40 /* Host UDMA burst terminate */ | |
354 | ||
355 | +#define MAX_DMA_BUFFERS 128 | |
356 | +#define MAX_DMA_BUFFER_SIZE 0x20000u | |
357 | ||
358 | /* Structure of the hardware registers */ | |
359 | struct mpc52xx_ata { | |
360 | @@ -140,7 +266,6 @@ struct mpc52xx_ata { | |
361 | ||
362 | ||
363 | /* MPC52xx low level hw control */ | |
364 | - | |
365 | static int | |
366 | mpc52xx_ata_compute_pio_timings(struct mpc52xx_ata_priv *priv, int dev, int pio) | |
367 | { | |
368 | @@ -165,6 +290,42 @@ mpc52xx_ata_compute_pio_timings(struct m | |
369 | return 0; | |
370 | } | |
371 | ||
372 | +static int | |
373 | +mpc52xx_ata_compute_mdma_timings(struct mpc52xx_ata_priv *priv, int dev, | |
374 | + int speed) | |
375 | +{ | |
376 | + struct mpc52xx_ata_timings *t = &priv->timings[dev]; | |
377 | + const struct mdmaspec *s = &priv->mdmaspec[speed]; | |
378 | + | |
379 | + if (speed < 0 || speed > 2) | |
380 | + return -EINVAL; | |
381 | + | |
382 | + t->mdma1 = (s->t0M << 24) | (s->td << 16) | (s->tkw << 8) | (s->tm); | |
383 | + t->mdma2 = (s->th << 24) | (s->tj << 16) | (s->tn << 8); | |
384 | + t->using_udma = 0; | |
385 | + | |
386 | + return 0; | |
387 | +} | |
388 | + | |
389 | +static int | |
390 | +mpc52xx_ata_compute_udma_timings(struct mpc52xx_ata_priv *priv, int dev, int speed) | |
391 | +{ | |
392 | + struct mpc52xx_ata_timings *t = &priv->timings[dev]; | |
393 | + const struct udmaspec *s = &priv->udmaspec[speed]; | |
394 | + | |
395 | + if (speed < 0 || speed > 2) | |
396 | + return -EINVAL; | |
397 | + | |
398 | + t->udma1 = (s->t2cyc << 24) | (s->tcyc << 16) | (s->tds << 8) | s->tdh; | |
399 | + t->udma2 = (s->tdvs << 24) | (s->tdvh << 16) | (s->tfs << 8) | s->tli; | |
400 | + t->udma3 = (s->tmli << 24) | (s->taz << 16) | (s->tenv << 8) | s->tsr; | |
401 | + t->udma4 = (s->tss << 24) | (s->trfs << 16) | (s->trp << 8) | s->tack; | |
402 | + t->udma5 = (s->tzah << 24); | |
403 | + t->using_udma = 1; | |
404 | + | |
405 | + return 0; | |
406 | +} | |
407 | + | |
408 | static void | |
409 | mpc52xx_ata_apply_timings(struct mpc52xx_ata_priv *priv, int device) | |
410 | { | |
411 | @@ -173,14 +334,13 @@ mpc52xx_ata_apply_timings(struct mpc52xx | |
412 | ||
413 | out_be32(®s->pio1, timing->pio1); | |
414 | out_be32(®s->pio2, timing->pio2); | |
415 | - out_be32(®s->mdma1, 0); | |
416 | - out_be32(®s->mdma2, 0); | |
417 | - out_be32(®s->udma1, 0); | |
418 | - out_be32(®s->udma2, 0); | |
419 | - out_be32(®s->udma3, 0); | |
420 | - out_be32(®s->udma4, 0); | |
421 | - out_be32(®s->udma5, 0); | |
422 | - | |
423 | + out_be32(®s->mdma1, timing->mdma1); | |
424 | + out_be32(®s->mdma2, timing->mdma2); | |
425 | + out_be32(®s->udma1, timing->udma1); | |
426 | + out_be32(®s->udma2, timing->udma2); | |
427 | + out_be32(®s->udma3, timing->udma3); | |
428 | + out_be32(®s->udma4, timing->udma4); | |
429 | + out_be32(®s->udma5, timing->udma5); | |
430 | priv->csel = device; | |
431 | } | |
432 | ||
433 | @@ -244,6 +404,31 @@ mpc52xx_ata_set_piomode(struct ata_port | |
434 | ||
435 | mpc52xx_ata_apply_timings(priv, adev->devno); | |
436 | } | |
437 | + | |
438 | +static void | |
439 | +mpc52xx_ata_set_dmamode(struct ata_port *ap, struct ata_device *adev) | |
440 | +{ | |
441 | + struct mpc52xx_ata_priv *priv = ap->host->private_data; | |
442 | + int rv; | |
443 | + | |
444 | + if (adev->dma_mode >= XFER_UDMA_0) { | |
445 | + int dma = adev->dma_mode - XFER_UDMA_0; | |
446 | + rv = mpc52xx_ata_compute_udma_timings(priv, adev->devno, dma); | |
447 | + } else { | |
448 | + int dma = adev->dma_mode - XFER_MW_DMA_0; | |
449 | + rv = mpc52xx_ata_compute_mdma_timings(priv, adev->devno, dma); | |
450 | + } | |
451 | + | |
452 | + if (rv) { | |
453 | + dev_alert(ap->dev, | |
454 | + "Trying to select invalid DMA mode %d\n", | |
455 | + adev->dma_mode); | |
456 | + return; | |
457 | + } | |
458 | + | |
459 | + mpc52xx_ata_apply_timings(priv, adev->devno); | |
460 | +} | |
461 | + | |
462 | static void | |
463 | mpc52xx_ata_dev_select(struct ata_port *ap, unsigned int device) | |
464 | { | |
465 | @@ -255,6 +440,172 @@ mpc52xx_ata_dev_select(struct ata_port * | |
466 | ata_sff_dev_select(ap,device); | |
467 | } | |
468 | ||
469 | +static int | |
470 | +mpc52xx_ata_build_dmatable(struct ata_queued_cmd *qc) | |
471 | +{ | |
472 | + struct ata_port *ap = qc->ap; | |
473 | + struct mpc52xx_ata_priv *priv = ap->host->private_data; | |
474 | + struct bcom_ata_bd *bd; | |
475 | + unsigned int read = !(qc->tf.flags & ATA_TFLAG_WRITE), si; | |
476 | + struct scatterlist *sg; | |
477 | + int count = 0; | |
478 | + | |
479 | + if (read) | |
480 | + bcom_ata_rx_prepare(priv->dmatsk); | |
481 | + else | |
482 | + bcom_ata_tx_prepare(priv->dmatsk); | |
483 | + | |
484 | + for_each_sg(qc->sg, sg, qc->n_elem, si) { | |
485 | + dma_addr_t cur_addr = sg_dma_address(sg); | |
486 | + u32 cur_len = sg_dma_len(sg); | |
487 | + | |
488 | + while (cur_len) { | |
489 | + unsigned int tc = min(cur_len, MAX_DMA_BUFFER_SIZE); | |
490 | + bd = (struct bcom_ata_bd *) | |
491 | + bcom_prepare_next_buffer(priv->dmatsk); | |
492 | + | |
493 | + if (read) { | |
494 | + bd->status = tc; | |
495 | + bd->src_pa = (__force u32) priv->ata_regs_pa + | |
496 | + offsetof(struct mpc52xx_ata, fifo_data); | |
497 | + bd->dst_pa = (__force u32) cur_addr; | |
498 | + } else { | |
499 | + bd->status = tc; | |
500 | + bd->src_pa = (__force u32) cur_addr; | |
501 | + bd->dst_pa = (__force u32) priv->ata_regs_pa + | |
502 | + offsetof(struct mpc52xx_ata, fifo_data); | |
503 | + } | |
504 | + | |
505 | + bcom_submit_next_buffer(priv->dmatsk, NULL); | |
506 | + | |
507 | + cur_addr += tc; | |
508 | + cur_len -= tc; | |
509 | + count++; | |
510 | + | |
511 | + if (count > MAX_DMA_BUFFERS) { | |
512 | + dev_alert(ap->dev, "dma table" | |
513 | + "too small\n"); | |
514 | + goto use_pio_instead; | |
515 | + } | |
516 | + } | |
517 | + } | |
518 | + return 1; | |
519 | + | |
520 | + use_pio_instead: | |
521 | + bcom_ata_reset_bd(priv->dmatsk); | |
522 | + return 0; | |
523 | +} | |
524 | + | |
525 | +static void | |
526 | +mpc52xx_bmdma_setup(struct ata_queued_cmd *qc) | |
527 | +{ | |
528 | + struct ata_port *ap = qc->ap; | |
529 | + struct mpc52xx_ata_priv *priv = ap->host->private_data; | |
530 | + struct mpc52xx_ata __iomem *regs = priv->ata_regs; | |
531 | + | |
532 | + unsigned int read = !(qc->tf.flags & ATA_TFLAG_WRITE); | |
533 | + u8 dma_mode; | |
534 | + | |
535 | + if (!mpc52xx_ata_build_dmatable(qc)) | |
536 | + dev_alert(ap->dev, "%s: %i, return 1?\n", | |
537 | + __func__, __LINE__); | |
538 | + | |
539 | + /* Check FIFO is OK... */ | |
540 | + if (in_8(&priv->ata_regs->fifo_status) & MPC52xx_ATA_FIFOSTAT_ERROR) | |
541 | + dev_alert(ap->dev, "%s: FIFO error detected: 0x%02x!\n", | |
542 | + __func__, in_8(&priv->ata_regs->fifo_status)); | |
543 | + | |
544 | + if (read) { | |
545 | + dma_mode = MPC52xx_ATA_DMAMODE_IE | MPC52xx_ATA_DMAMODE_READ | | |
546 | + MPC52xx_ATA_DMAMODE_FE; | |
547 | + | |
548 | + /* Setup FIFO if direction changed */ | |
549 | + if (priv->mpc52xx_ata_dma_last_write != 0) { | |
550 | + priv->mpc52xx_ata_dma_last_write = 0; | |
551 | + | |
552 | + /* Configure FIFO with granularity to 7 */ | |
553 | + out_8(®s->fifo_control, 7); | |
554 | + out_be16(®s->fifo_alarm, 128); | |
555 | + | |
556 | + /* Set FIFO Reset bit (FR) */ | |
557 | + out_8(®s->dma_mode, MPC52xx_ATA_DMAMODE_FR); | |
558 | + } | |
559 | + } else { | |
560 | + dma_mode = MPC52xx_ATA_DMAMODE_IE | MPC52xx_ATA_DMAMODE_WRITE; | |
561 | + | |
562 | + /* Setup FIFO if direction changed */ | |
563 | + if (priv->mpc52xx_ata_dma_last_write != 1) { | |
564 | + priv->mpc52xx_ata_dma_last_write = 1; | |
565 | + | |
566 | + /* Configure FIFO with granularity to 4 */ | |
567 | + out_8(®s->fifo_control, 4); | |
568 | + out_be16(®s->fifo_alarm, 128); | |
569 | + } | |
570 | + } | |
571 | + | |
572 | + if (priv->timings[qc->dev->devno].using_udma) | |
573 | + dma_mode |= MPC52xx_ATA_DMAMODE_UDMA; | |
574 | + | |
575 | + out_8(®s->dma_mode, dma_mode); | |
576 | + priv->waiting_for_dma = ATA_DMA_ACTIVE; | |
577 | + | |
578 | + ata_wait_idle(ap); | |
579 | + ap->ops->sff_exec_command(ap, &qc->tf); | |
580 | +} | |
581 | + | |
582 | +static void | |
583 | +mpc52xx_bmdma_start(struct ata_queued_cmd *qc) | |
584 | +{ | |
585 | + struct ata_port *ap = qc->ap; | |
586 | + struct mpc52xx_ata_priv *priv = ap->host->private_data; | |
587 | + | |
588 | + bcom_set_task_auto_start(priv->dmatsk->tasknum, priv->dmatsk->tasknum); | |
589 | + bcom_enable(priv->dmatsk); | |
590 | +} | |
591 | + | |
592 | +static void | |
593 | +mpc52xx_bmdma_stop(struct ata_queued_cmd *qc) | |
594 | +{ | |
595 | + struct ata_port *ap = qc->ap; | |
596 | + struct mpc52xx_ata_priv *priv = ap->host->private_data; | |
597 | + | |
598 | + bcom_disable(priv->dmatsk); | |
599 | + bcom_ata_reset_bd(priv->dmatsk); | |
600 | + priv->waiting_for_dma = 0; | |
601 | + | |
602 | + /* Check FIFO is OK... */ | |
603 | + if (in_8(&priv->ata_regs->fifo_status) & MPC52xx_ATA_FIFOSTAT_ERROR) | |
604 | + dev_alert(ap->dev, "%s: FIFO error detected: 0x%02x!\n", | |
605 | + __func__, in_8(&priv->ata_regs->fifo_status)); | |
606 | +} | |
607 | + | |
608 | +static u8 | |
609 | +mpc52xx_bmdma_status(struct ata_port *ap) | |
610 | +{ | |
611 | + struct mpc52xx_ata_priv *priv = ap->host->private_data; | |
612 | + | |
613 | + /* Check FIFO is OK... */ | |
614 | + if (in_8(&priv->ata_regs->fifo_status) & MPC52xx_ATA_FIFOSTAT_ERROR) { | |
615 | + dev_alert(ap->dev, "%s: FIFO error detected: 0x%02x!\n", | |
616 | + __func__, in_8(&priv->ata_regs->fifo_status)); | |
617 | + return priv->waiting_for_dma | ATA_DMA_ERR; | |
618 | + } | |
619 | + | |
620 | + return priv->waiting_for_dma; | |
621 | +} | |
622 | + | |
623 | +static irqreturn_t | |
624 | +mpc52xx_ata_task_irq(int irq, void *vpriv) | |
625 | +{ | |
626 | + struct mpc52xx_ata_priv *priv = vpriv; | |
627 | + while (bcom_buffer_done(priv->dmatsk)) | |
628 | + bcom_retrieve_buffer(priv->dmatsk, NULL, NULL); | |
629 | + | |
630 | + priv->waiting_for_dma |= ATA_DMA_INTR; | |
631 | + | |
632 | + return IRQ_HANDLED; | |
633 | +} | |
634 | + | |
635 | static struct scsi_host_template mpc52xx_ata_sht = { | |
636 | ATA_PIO_SHT(DRV_NAME), | |
637 | }; | |
638 | @@ -262,14 +613,18 @@ static struct scsi_host_template mpc52xx | |
639 | static struct ata_port_operations mpc52xx_ata_port_ops = { | |
640 | .inherits = &ata_sff_port_ops, | |
641 | .sff_dev_select = mpc52xx_ata_dev_select, | |
642 | - .cable_detect = ata_cable_40wire, | |
643 | .set_piomode = mpc52xx_ata_set_piomode, | |
644 | - .post_internal_cmd = ATA_OP_NULL, | |
645 | + .set_dmamode = mpc52xx_ata_set_dmamode, | |
646 | + .bmdma_setup = mpc52xx_bmdma_setup, | |
647 | + .bmdma_start = mpc52xx_bmdma_start, | |
648 | + .bmdma_stop = mpc52xx_bmdma_stop, | |
649 | + .bmdma_status = mpc52xx_bmdma_status, | |
650 | + .qc_prep = ata_noop_qc_prep, | |
651 | }; | |
652 | ||
653 | static int __devinit | |
654 | mpc52xx_ata_init_one(struct device *dev, struct mpc52xx_ata_priv *priv, | |
655 | - unsigned long raw_ata_regs) | |
656 | + unsigned long raw_ata_regs, int mwdma_mask, int udma_mask) | |
657 | { | |
658 | struct ata_host *host; | |
659 | struct ata_port *ap; | |
660 | @@ -281,9 +636,9 @@ mpc52xx_ata_init_one(struct device *dev, | |
661 | ||
662 | ap = host->ports[0]; | |
663 | ap->flags |= ATA_FLAG_SLAVE_POSS; | |
664 | - ap->pio_mask = 0x1f; /* Up to PIO4 */ | |
665 | - ap->mwdma_mask = 0x00; /* No MWDMA */ | |
666 | - ap->udma_mask = 0x00; /* No UDMA */ | |
667 | + ap->pio_mask = ATA_PIO4; | |
668 | + ap->mwdma_mask = mwdma_mask; | |
669 | + ap->udma_mask = udma_mask; | |
670 | ap->ops = &mpc52xx_ata_port_ops; | |
671 | host->private_data = priv; | |
672 | ||
673 | @@ -333,7 +688,10 @@ mpc52xx_ata_probe(struct of_device *op, | |
674 | int ata_irq; | |
675 | struct mpc52xx_ata __iomem *ata_regs; | |
676 | struct mpc52xx_ata_priv *priv; | |
677 | - int rv; | |
678 | + int rv, ret, task_irq; | |
679 | + int mwdma_mask = 0, udma_mask = 0; | |
680 | + const __be32 *prop; | |
681 | + int proplen; | |
682 | ||
683 | /* Get ipb frequency */ | |
684 | ipb_freq = mpc52xx_find_ipb_freq(op->node); | |
685 | @@ -351,6 +709,27 @@ mpc52xx_ata_probe(struct of_device *op, | |
686 | return rv; | |
687 | } | |
688 | ||
689 | + /* | |
690 | + * By default, all DMA modes are disabled for the MPC5200. Some | |
691 | + * boards don't have the required signals routed to make DMA work. | |
692 | + * Also, the MPC5200B has a silicon bug that causes data corruption | |
693 | + * with UDMA if it is used at the same time as the LocalPlus bus. | |
694 | + * | |
695 | + * Instead of trying to guess what modes are usable, check the | |
696 | + * ATA device tree node to find out what DMA modes work on the board. | |
697 | + * UDMA/MWDMA modes can also be forced by adding "libata.force=<mode>" | |
698 | + * to the kernel boot parameters. | |
699 | + * | |
700 | + * The MPC5200 ATA controller supports MWDMA modes 0, 1 and 2 and | |
701 | + * UDMA modes 0, 1 and 2. | |
702 | + */ | |
703 | + prop = of_get_property(op->node, "mwdma-mode", &proplen); | |
704 | + if ((prop) && (proplen >= 4)) | |
705 | + mwdma_mask = 0x7 & ((1 << (*prop + 1)) - 1); | |
706 | + prop = of_get_property(op->node, "udma-mode", &proplen); | |
707 | + if ((prop) && (proplen >= 4)) | |
708 | + udma_mask = 0x7 & ((1 << (*prop + 1)) - 1); | |
709 | + | |
710 | ata_irq = irq_of_parse_and_map(op->node, 0); | |
711 | if (ata_irq == NO_IRQ) { | |
712 | printk(KERN_ERR DRV_NAME ": " | |
713 | @@ -389,8 +768,32 @@ mpc52xx_ata_probe(struct of_device *op, | |
714 | ||
715 | priv->ipb_period = 1000000000 / (ipb_freq / 1000); | |
716 | priv->ata_regs = ata_regs; | |
717 | + priv->ata_regs_pa = res_mem.start; | |
718 | priv->ata_irq = ata_irq; | |
719 | priv->csel = -1; | |
720 | + priv->mpc52xx_ata_dma_last_write = -1; | |
721 | + | |
722 | + if (ipb_freq/1000000 == 66) { | |
723 | + priv->mdmaspec = mdmaspec66; | |
724 | + priv->udmaspec = udmaspec66; | |
725 | + } else { | |
726 | + priv->mdmaspec = mdmaspec132; | |
727 | + priv->udmaspec = udmaspec132; | |
728 | + } | |
729 | + | |
730 | + priv->dmatsk = bcom_ata_init(MAX_DMA_BUFFERS, MAX_DMA_BUFFER_SIZE); | |
731 | + if (!priv->dmatsk) { | |
732 | + dev_err(&op->dev, "bestcomm initialization failed\n"); | |
733 | + rv = -ENOMEM; | |
734 | + goto err; | |
735 | + } | |
736 | + | |
737 | + task_irq = bcom_get_task_irq(priv->dmatsk); | |
738 | + ret = request_irq(task_irq, &mpc52xx_ata_task_irq, IRQF_DISABLED, | |
739 | + "ATA task", priv); | |
740 | + if (ret) | |
741 | + dev_alert(&op->dev, "request_irq failed with: " | |
742 | + "%i\n", ret); | |
743 | ||
744 | /* Init the hw */ | |
745 | rv = mpc52xx_ata_hw_init(priv); | |
746 | @@ -400,7 +803,8 @@ mpc52xx_ata_probe(struct of_device *op, | |
747 | } | |
748 | ||
749 | /* Register ourselves to libata */ | |
750 | - rv = mpc52xx_ata_init_one(&op->dev, priv, res_mem.start); | |
751 | + rv = mpc52xx_ata_init_one(&op->dev, priv, res_mem.start, | |
752 | + mwdma_mask, udma_mask); | |
753 | if (rv) { | |
754 | printk(KERN_ERR DRV_NAME ": " | |
755 | "Error while registering to ATA layer\n"); |