]> nv-tegra.nvidia Code Review - linux-2.6.git/blob - arch/ppc/syslib/ppc4xx_sgdma.c
939abe3c1f454363c6362656940a398ec0109c47
[linux-2.6.git] / arch / ppc / syslib / ppc4xx_sgdma.c
1 /*
2  * IBM PPC4xx DMA engine scatter/gather library
3  *
4  * Copyright 2002-2003 MontaVista Software Inc.
5  *
6  * Cleaned up and converted to new DCR access
7  * Matt Porter <mporter@kernel.crashing.org>
8  *
9  * Original code by Armin Kuster <akuster@mvista.com>
10  * and Pete Popov <ppopov@mvista.com>
11  *
12  * This program is free software; you can redistribute  it and/or modify it
13  * under  the terms of  the GNU General  Public License as published by the
14  * Free Software Foundation;  either version 2 of the  License, or (at your
15  * option) any later version.
16  *
17  * You should have received a copy of the  GNU General Public License along
18  * with this program; if not, write  to the Free Software Foundation, Inc.,
19  * 675 Mass Ave, Cambridge, MA 02139, USA.
20  */
21
22 #include <linux/kernel.h>
23 #include <linux/mm.h>
24 #include <linux/init.h>
25 #include <linux/module.h>
26 #include <linux/pci.h>
27
28 #include <asm/system.h>
29 #include <asm/io.h>
30 #include <asm/dma-mapping.h>
31 #include <asm/ppc4xx_dma.h>
32
33 void
34 ppc4xx_set_sg_addr(int dmanr, phys_addr_t sg_addr)
35 {
36         if (dmanr >= MAX_PPC4xx_DMA_CHANNELS) {
37                 printk("ppc4xx_set_sg_addr: bad channel: %d\n", dmanr);
38                 return;
39         }
40
41 #ifdef PPC4xx_DMA_64BIT
42         mtdcr(DCRN_ASGH0 + (dmanr * 0x8), (u32)(sg_addr >> 32));
43 #endif
44         mtdcr(DCRN_ASG0 + (dmanr * 0x8), (u32)sg_addr);
45 }
46
47 /*
48  *   Add a new sgl descriptor to the end of a scatter/gather list
49  *   which was created by alloc_dma_handle().
50  *
51  *   For a memory to memory transfer, both dma addresses must be
52  *   valid. For a peripheral to memory transfer, one of the addresses
53  *   must be set to NULL, depending on the direction of the transfer:
54  *   memory to peripheral: set dst_addr to NULL,
55  *   peripheral to memory: set src_addr to NULL.
56  */
57 int
58 ppc4xx_add_dma_sgl(sgl_handle_t handle, phys_addr_t src_addr, phys_addr_t dst_addr,
59                    unsigned int count)
60 {
61         sgl_list_info_t *psgl = (sgl_list_info_t *) handle;
62         ppc_dma_ch_t *p_dma_ch;
63
64         if (!handle) {
65                 printk("ppc4xx_add_dma_sgl: null handle\n");
66                 return DMA_STATUS_BAD_HANDLE;
67         }
68
69         if (psgl->dmanr >= MAX_PPC4xx_DMA_CHANNELS) {
70                 printk("ppc4xx_add_dma_sgl: bad channel: %d\n", psgl->dmanr);
71                 return DMA_STATUS_BAD_CHANNEL;
72         }
73
74         p_dma_ch = &dma_channels[psgl->dmanr];
75
76 #ifdef DEBUG_4xxDMA
77         {
78                 int error = 0;
79                 unsigned int aligned =
80                     (unsigned) src_addr | (unsigned) dst_addr | count;
81                 switch (p_dma_ch->pwidth) {
82                 case PW_8:
83                         break;
84                 case PW_16:
85                         if (aligned & 0x1)
86                                 error = 1;
87                         break;
88                 case PW_32:
89                         if (aligned & 0x3)
90                                 error = 1;
91                         break;
92                 case PW_64:
93                         if (aligned & 0x7)
94                                 error = 1;
95                         break;
96                 default:
97                         printk("ppc4xx_add_dma_sgl: invalid bus width: 0x%x\n",
98                                p_dma_ch->pwidth);
99                         return DMA_STATUS_GENERAL_ERROR;
100                 }
101                 if (error)
102                         printk
103                             ("Alignment warning: ppc4xx_add_dma_sgl src 0x%x dst 0x%x count 0x%x bus width var %d\n",
104                              src_addr, dst_addr, count, p_dma_ch->pwidth);
105
106         }
107 #endif
108
109         if ((unsigned) (psgl->ptail + 1) >= ((unsigned) psgl + SGL_LIST_SIZE)) {
110                 printk("sgl handle out of memory \n");
111                 return DMA_STATUS_OUT_OF_MEMORY;
112         }
113
114         if (!psgl->ptail) {
115                 psgl->phead = (ppc_sgl_t *)
116                     ((unsigned) psgl + sizeof (sgl_list_info_t));
117                 psgl->phead_dma = psgl->dma_addr + sizeof(sgl_list_info_t);
118                 psgl->ptail = psgl->phead;
119                 psgl->ptail_dma = psgl->phead_dma;
120         } else {
121                 if(p_dma_ch->int_on_final_sg) {
122                         /* mask out all dma interrupts, except error, on tail
123                         before adding new tail. */
124                         psgl->ptail->control_count &=
125                                 ~(SG_TCI_ENABLE | SG_ETI_ENABLE);
126                 }
127                 psgl->ptail->next = psgl->ptail_dma + sizeof(ppc_sgl_t);
128                 psgl->ptail++;
129                 psgl->ptail_dma += sizeof(ppc_sgl_t);
130         }
131
132         psgl->ptail->control = psgl->control;
133         psgl->ptail->src_addr = src_addr;
134         psgl->ptail->dst_addr = dst_addr;
135         psgl->ptail->control_count = (count >> p_dma_ch->shift) |
136             psgl->sgl_control;
137         psgl->ptail->next = (uint32_t) NULL;
138
139         return DMA_STATUS_GOOD;
140 }
141
142 /*
143  * Enable (start) the DMA described by the sgl handle.
144  */
145 void
146 ppc4xx_enable_dma_sgl(sgl_handle_t handle)
147 {
148         sgl_list_info_t *psgl = (sgl_list_info_t *) handle;
149         ppc_dma_ch_t *p_dma_ch;
150         uint32_t sg_command;
151
152         if (!handle) {
153                 printk("ppc4xx_enable_dma_sgl: null handle\n");
154                 return;
155         } else if (psgl->dmanr > (MAX_PPC4xx_DMA_CHANNELS - 1)) {
156                 printk("ppc4xx_enable_dma_sgl: bad channel in handle %d\n",
157                        psgl->dmanr);
158                 return;
159         } else if (!psgl->phead) {
160                 printk("ppc4xx_enable_dma_sgl: sg list empty\n");
161                 return;
162         }
163
164         p_dma_ch = &dma_channels[psgl->dmanr];
165         psgl->ptail->control_count &= ~SG_LINK; /* make this the last dscrptr */
166         sg_command = mfdcr(DCRN_ASGC);
167
168         ppc4xx_set_sg_addr(psgl->dmanr, psgl->phead_dma);
169
170         sg_command |= SSG_ENABLE(psgl->dmanr);
171
172         mtdcr(DCRN_ASGC, sg_command);   /* start transfer */
173 }
174
175 /*
176  * Halt an active scatter/gather DMA operation.
177  */
178 void
179 ppc4xx_disable_dma_sgl(sgl_handle_t handle)
180 {
181         sgl_list_info_t *psgl = (sgl_list_info_t *) handle;
182         uint32_t sg_command;
183
184         if (!handle) {
185                 printk("ppc4xx_enable_dma_sgl: null handle\n");
186                 return;
187         } else if (psgl->dmanr > (MAX_PPC4xx_DMA_CHANNELS - 1)) {
188                 printk("ppc4xx_enable_dma_sgl: bad channel in handle %d\n",
189                        psgl->dmanr);
190                 return;
191         }
192
193         sg_command = mfdcr(DCRN_ASGC);
194         sg_command &= ~SSG_ENABLE(psgl->dmanr);
195         mtdcr(DCRN_ASGC, sg_command);   /* stop transfer */
196 }
197
198 /*
199  *  Returns number of bytes left to be transferred from the entire sgl list.
200  *  *src_addr and *dst_addr get set to the source/destination address of
201  *  the sgl descriptor where the DMA stopped.
202  *
203  *  An sgl transfer must NOT be active when this function is called.
204  */
205 int
206 ppc4xx_get_dma_sgl_residue(sgl_handle_t handle, phys_addr_t * src_addr,
207                            phys_addr_t * dst_addr)
208 {
209         sgl_list_info_t *psgl = (sgl_list_info_t *) handle;
210         ppc_dma_ch_t *p_dma_ch;
211         ppc_sgl_t *pnext, *sgl_addr;
212         uint32_t count_left;
213
214         if (!handle) {
215                 printk("ppc4xx_get_dma_sgl_residue: null handle\n");
216                 return DMA_STATUS_BAD_HANDLE;
217         } else if (psgl->dmanr > (MAX_PPC4xx_DMA_CHANNELS - 1)) {
218                 printk("ppc4xx_get_dma_sgl_residue: bad channel in handle %d\n",
219                        psgl->dmanr);
220                 return DMA_STATUS_BAD_CHANNEL;
221         }
222
223         sgl_addr = (ppc_sgl_t *) __va(mfdcr(DCRN_ASG0 + (psgl->dmanr * 0x8)));
224         count_left = mfdcr(DCRN_DMACT0 + (psgl->dmanr * 0x8)) & SG_COUNT_MASK;
225
226         if (!sgl_addr) {
227                 printk("ppc4xx_get_dma_sgl_residue: sgl addr register is null\n");
228                 goto error;
229         }
230
231         pnext = psgl->phead;
232         while (pnext &&
233                ((unsigned) pnext < ((unsigned) psgl + SGL_LIST_SIZE) &&
234                 (pnext != sgl_addr))
235             ) {
236                 pnext++;
237         }
238
239         if (pnext == sgl_addr) {        /* found the sgl descriptor */
240
241                 *src_addr = pnext->src_addr;
242                 *dst_addr = pnext->dst_addr;
243
244                 /*
245                  * Now search the remaining descriptors and add their count.
246                  * We already have the remaining count from this descriptor in
247                  * count_left.
248                  */
249                 pnext++;
250
251                 while ((pnext != psgl->ptail) &&
252                        ((unsigned) pnext < ((unsigned) psgl + SGL_LIST_SIZE))
253                     ) {
254                         count_left += pnext->control_count & SG_COUNT_MASK;
255                 }
256
257                 if (pnext != psgl->ptail) {     /* should never happen */
258                         printk
259                             ("ppc4xx_get_dma_sgl_residue error (1) psgl->ptail 0x%x handle 0x%x\n",
260                              (unsigned int) psgl->ptail, (unsigned int) handle);
261                         goto error;
262                 }
263
264                 /* success */
265                 p_dma_ch = &dma_channels[psgl->dmanr];
266                 return (count_left << p_dma_ch->shift); /* count in bytes */
267
268         } else {
269                 /* this shouldn't happen */
270                 printk
271                     ("get_dma_sgl_residue, unable to match current address 0x%x, handle 0x%x\n",
272                      (unsigned int) sgl_addr, (unsigned int) handle);
273
274         }
275
276       error:
277         *src_addr = (phys_addr_t) NULL;
278         *dst_addr = (phys_addr_t) NULL;
279         return 0;
280 }
281
282 /*
283  * Returns the address(es) of the buffer(s) contained in the head element of
284  * the scatter/gather list.  The element is removed from the scatter/gather
285  * list and the next element becomes the head.
286  *
287  * This function should only be called when the DMA is not active.
288  */
289 int
290 ppc4xx_delete_dma_sgl_element(sgl_handle_t handle, phys_addr_t * src_dma_addr,
291                               phys_addr_t * dst_dma_addr)
292 {
293         sgl_list_info_t *psgl = (sgl_list_info_t *) handle;
294
295         if (!handle) {
296                 printk("ppc4xx_delete_sgl_element: null handle\n");
297                 return DMA_STATUS_BAD_HANDLE;
298         } else if (psgl->dmanr > (MAX_PPC4xx_DMA_CHANNELS - 1)) {
299                 printk("ppc4xx_delete_sgl_element: bad channel in handle %d\n",
300                        psgl->dmanr);
301                 return DMA_STATUS_BAD_CHANNEL;
302         }
303
304         if (!psgl->phead) {
305                 printk("ppc4xx_delete_sgl_element: sgl list empty\n");
306                 *src_dma_addr = (phys_addr_t) NULL;
307                 *dst_dma_addr = (phys_addr_t) NULL;
308                 return DMA_STATUS_SGL_LIST_EMPTY;
309         }
310
311         *src_dma_addr = (phys_addr_t) psgl->phead->src_addr;
312         *dst_dma_addr = (phys_addr_t) psgl->phead->dst_addr;
313
314         if (psgl->phead == psgl->ptail) {
315                 /* last descriptor on the list */
316                 psgl->phead = NULL;
317                 psgl->ptail = NULL;
318         } else {
319                 psgl->phead++;
320                 psgl->phead_dma += sizeof(ppc_sgl_t);
321         }
322
323         return DMA_STATUS_GOOD;
324 }
325
326
327 /*
328  *   Create a scatter/gather list handle.  This is simply a structure which
329  *   describes a scatter/gather list.
330  *
331  *   A handle is returned in "handle" which the driver should save in order to
332  *   be able to access this list later.  A chunk of memory will be allocated
333  *   to be used by the API for internal management purposes, including managing
334  *   the sg list and allocating memory for the sgl descriptors.  One page should
335  *   be more than enough for that purpose.  Perhaps it's a bit wasteful to use
336  *   a whole page for a single sg list, but most likely there will be only one
337  *   sg list per channel.
338  *
339  *   Interrupt notes:
340  *   Each sgl descriptor has a copy of the DMA control word which the DMA engine
341  *   loads in the control register.  The control word has a "global" interrupt
342  *   enable bit for that channel. Interrupts are further qualified by a few bits
343  *   in the sgl descriptor count register.  In order to setup an sgl, we have to
344  *   know ahead of time whether or not interrupts will be enabled at the completion
345  *   of the transfers.  Thus, enable_dma_interrupt()/disable_dma_interrupt() MUST
346  *   be called before calling alloc_dma_handle().  If the interrupt mode will never
347  *   change after powerup, then enable_dma_interrupt()/disable_dma_interrupt()
348  *   do not have to be called -- interrupts will be enabled or disabled based
349  *   on how the channel was configured after powerup by the hw_init_dma_channel()
350  *   function.  Each sgl descriptor will be setup to interrupt if an error occurs;
351  *   however, only the last descriptor will be setup to interrupt. Thus, an
352  *   interrupt will occur (if interrupts are enabled) only after the complete
353  *   sgl transfer is done.
354  */
355 int
356 ppc4xx_alloc_dma_handle(sgl_handle_t * phandle, unsigned int mode, unsigned int dmanr)
357 {
358         sgl_list_info_t *psgl=NULL;
359         dma_addr_t dma_addr;
360         ppc_dma_ch_t *p_dma_ch = &dma_channels[dmanr];
361         uint32_t sg_command;
362         uint32_t ctc_settings;
363         void *ret;
364
365         if (dmanr >= MAX_PPC4xx_DMA_CHANNELS) {
366                 printk("ppc4xx_alloc_dma_handle: invalid channel 0x%x\n", dmanr);
367                 return DMA_STATUS_BAD_CHANNEL;
368         }
369
370         if (!phandle) {
371                 printk("ppc4xx_alloc_dma_handle: null handle pointer\n");
372                 return DMA_STATUS_NULL_POINTER;
373         }
374
375         /* Get a page of memory, which is zeroed out by consistent_alloc() */
376         ret = dma_alloc_coherent(NULL, DMA_PPC4xx_SIZE, &dma_addr, GFP_KERNEL);
377         if (ret != NULL) {
378                 memset(ret, 0, DMA_PPC4xx_SIZE);
379                 psgl = (sgl_list_info_t *) ret;
380         }
381
382         if (psgl == NULL) {
383                 *phandle = (sgl_handle_t) NULL;
384                 return DMA_STATUS_OUT_OF_MEMORY;
385         }
386
387         psgl->dma_addr = dma_addr;
388         psgl->dmanr = dmanr;
389
390         /*
391          * Modify and save the control word. These words will be
392          * written to each sgl descriptor.  The DMA engine then
393          * loads this control word into the control register
394          * every time it reads a new descriptor.
395          */
396         psgl->control = p_dma_ch->control;
397         /* Clear all mode bits */
398         psgl->control &= ~(DMA_TM_MASK | DMA_TD);
399         /* Save control word and mode */
400         psgl->control |= (mode | DMA_CE_ENABLE);
401
402         /* In MM mode, we must set ETD/TCE */
403         if (mode == DMA_MODE_MM)
404                 psgl->control |= DMA_ETD_OUTPUT | DMA_TCE_ENABLE;
405
406         if (p_dma_ch->int_enable) {
407                 /* Enable channel interrupt */
408                 psgl->control |= DMA_CIE_ENABLE;
409         } else {
410                 psgl->control &= ~DMA_CIE_ENABLE;
411         }
412
413         sg_command = mfdcr(DCRN_ASGC);
414         sg_command |= SSG_MASK_ENABLE(dmanr);
415
416         /* Enable SGL control access */
417         mtdcr(DCRN_ASGC, sg_command);
418         psgl->sgl_control = SG_ERI_ENABLE | SG_LINK;
419
420         /* keep control count register settings */
421         ctc_settings = mfdcr(DCRN_DMACT0 + (dmanr * 0x8))
422                 & (DMA_CTC_BSIZ_MSK | DMA_CTC_BTEN); /*burst mode settings*/
423         psgl->sgl_control |= ctc_settings;
424
425         if (p_dma_ch->int_enable) {
426                 if (p_dma_ch->tce_enable)
427                         psgl->sgl_control |= SG_TCI_ENABLE;
428                 else
429                         psgl->sgl_control |= SG_ETI_ENABLE;
430         }
431
432         *phandle = (sgl_handle_t) psgl;
433         return DMA_STATUS_GOOD;
434 }
435
436 /*
437  * Destroy a scatter/gather list handle that was created by alloc_dma_handle().
438  * The list must be empty (contain no elements).
439  */
440 void
441 ppc4xx_free_dma_handle(sgl_handle_t handle)
442 {
443         sgl_list_info_t *psgl = (sgl_list_info_t *) handle;
444
445         if (!handle) {
446                 printk("ppc4xx_free_dma_handle: got NULL\n");
447                 return;
448         } else if (psgl->phead) {
449                 printk("ppc4xx_free_dma_handle: list not empty\n");
450                 return;
451         } else if (!psgl->dma_addr) {   /* should never happen */
452                 printk("ppc4xx_free_dma_handle: no dma address\n");
453                 return;
454         }
455
456         dma_free_coherent(NULL, DMA_PPC4xx_SIZE, (void *) psgl, 0);
457 }
458
459 EXPORT_SYMBOL(ppc4xx_alloc_dma_handle);
460 EXPORT_SYMBOL(ppc4xx_free_dma_handle);
461 EXPORT_SYMBOL(ppc4xx_add_dma_sgl);
462 EXPORT_SYMBOL(ppc4xx_delete_dma_sgl_element);
463 EXPORT_SYMBOL(ppc4xx_enable_dma_sgl);
464 EXPORT_SYMBOL(ppc4xx_disable_dma_sgl);
465 EXPORT_SYMBOL(ppc4xx_get_dma_sgl_residue);