source: soft/giet_vm/giet_drivers/dma_driver.c @ 481

Last change on this file since 481 was 481, checked in by alain, 9 years ago

1) The NIC, IOC, DMA and HBA drivers have been adapted to support the new _v2p_translate() function prototype (returns void).
2) The _mmc_inval() and _mmc_sync() functions does not use anymore the hard lock in the MMC, but use a soft spin_lock.
3) The NIC driver does not use anymore the GIET_NIC_BUFSIZE, GIET_NIC_NBUFS, and GIET_NIC_TIMEOUT parameters (removed from giet_config.h file).
4) The NIC driver registers map has been modified to support 64 bytes buffer descriptors for chained buffers.

File size: 11.8 KB
Line 
1///////////////////////////////////////////////////////////////////////////////////
2// File     : dma_driver.c
3// Date     : 23/11/2013
4// Author   : alain greiner
5// Copyright (c) UPMC-LIP6
6///////////////////////////////////////////////////////////////////////////////////
7
8#include <giet_config.h>
9#include <hard_config.h>
10#include <dma_driver.h>
11#include <tty0.h>
12#include <vmem.h>
13#include <utils.h>
14#include <io.h>
15
16#if !defined(X_SIZE)
17# error: You must define X_SIZE in the hard_config.h file
18#endif
19
20#if !defined(Y_SIZE)
21# error: You must define X_SIZE in the hard_config.h file
22#endif
23
24#if !defined(X_WIDTH)
25# error: You must define X_WIDTH in the hard_config.h file
26#endif
27
28#if !defined(Y_WIDTH)
29# error: You must define X_WIDTH in the hard_config.h file
30#endif
31
32#if !defined(NB_DMA_CHANNELS)
33# error: You must define NB_DMA_CHANNELS in the hard_config.h file
34#endif
35
36#if !defined(SEG_DMA_BASE)
37# error: You must define SEG_DMA_BASE in the hard_config.h file
38#endif
39
40#if !defined(PERI_CLUSTER_INCREMENT)
41# error: You must define PERI_CLUSTER_INCREMENT in the hard_config.h file
42#endif
43
44extern volatile unsigned int _ptabs_vaddr[];
45
46///////////////////////////////////////////////////////////////////////////////
47// This low level function returns the value contained in register "index"
48// in the DMA component contained in cluster "cluster_xy"
49///////////////////////////////////////////////////////////////////////////////
50static
51unsigned int _dma_get_register( unsigned int cluster_xy, // cluster index
52                                unsigned int channel_id, // channel index
53                                unsigned int index )     // register index
54{
55    unsigned int vaddr =
56        SEG_DMA_BASE + 
57        (cluster_xy * PERI_CLUSTER_INCREMENT) +
58        (channel_id * DMA_SPAN) +
59        (index << 2);
60
61    return ioread32( (void*)vaddr );
62}
63
64///////////////////////////////////////////////////////////////////////////////
65// This low level function sets a new value in register "index"
66// in the DMA component contained in cluster "cluster_xy"
67///////////////////////////////////////////////////////////////////////////////
68static
69void _dma_set_register( unsigned int cluster_xy,       // cluster index
70                        unsigned int channel_id,       // channel index
71                        unsigned int index,            // register index
72                        unsigned int value )           // value to be written
73{
74    unsigned int vaddr =
75        SEG_DMA_BASE + 
76        (cluster_xy * PERI_CLUSTER_INCREMENT) +
77        (channel_id * DMA_SPAN) +
78        (index << 2);
79
80    iowrite32( (void*)vaddr, value );
81}
82
83////////////////////////////////////////////////
84unsigned int _dma_init( unsigned int cluster_xy,
85                        unsigned int channel_id )
86{
87#if NB_DMA_CHANNELS > 0
88
89    // parameters checking
90    unsigned int x = cluster_xy >> Y_WIDTH;
91    unsigned int y = cluster_xy & ((1<<Y_WIDTH)-1);
92    if (x >= X_SIZE)                    return 1; 
93    if (y >= Y_SIZE)                    return 1; 
94    if (channel_id >= NB_DMA_CHANNELS)  return 1; 
95
96    // disable interrupt for selected channel
97    _dma_set_register(cluster_xy, channel_id, DMA_IRQ_DISABLE, 1);
98    return 0;
99#else
100    return 1;
101#endif
102}
103
104//////////////////////////////////////////////////
105unsigned int _dma_reset( unsigned int cluster_xy, 
106                         unsigned int channel_id ) 
107{
108#if NB_DMA_CHANNELS > 0
109
110    // parameters checking
111    unsigned int x = cluster_xy >> Y_WIDTH;
112    unsigned int y = cluster_xy & ((1<<Y_WIDTH)-1);
113    if (x >= X_SIZE)                    return 1; 
114    if (y >= Y_SIZE)                    return 1; 
115    if (channel_id >= NB_DMA_CHANNELS)  return 1; 
116
117    // reset selected channel
118    _dma_set_register(cluster_xy, channel_id, DMA_RESET, 0);
119    return 0;
120#else
121    return 1;
122#endif
123}
124
125//////////////////////////////////////////////////////
126unsigned int _dma_get_status( unsigned int cluster_xy, 
127                              unsigned int channel_id ) 
128{
129#if NB_DMA_CHANNELS > 0
130
131    // parameters checking
132    unsigned int x = cluster_xy >> Y_WIDTH;
133    unsigned int y = cluster_xy & ((1<<Y_WIDTH)-1);
134    if (x >= X_SIZE)                    return 1; 
135    if (y >= Y_SIZE)                    return 1; 
136    if (channel_id >= NB_DMA_CHANNELS)  return 1;
137
138    // get selected channel status
139    return _dma_get_register(cluster_xy, channel_id, DMA_LEN);
140#else
141    return DMA_IDLE;
142#endif
143}
144
145////////////////////////////////////////////////////////
146void _dma_start_transfer( unsigned int       cluster_xy,  // DMA cluster
147                          unsigned int       channel_id,  // DMA channel
148                          unsigned long long dst_paddr,   // physical address
149                          unsigned long long src_paddr,   // physical address
150                          unsigned int       size )       // bytes
151{
152#if NB_DMA_CHANNELS > 0
153
154    // selected channel configuration and lauching
155    _dma_set_register(cluster_xy, channel_id, DMA_SRC,
156            (unsigned int)(src_paddr));
157    _dma_set_register(cluster_xy, channel_id, DMA_SRC_EXT,
158            (unsigned int)(src_paddr>>32));
159    _dma_set_register(cluster_xy, channel_id, DMA_DST,
160            (unsigned int)(dst_paddr));
161    _dma_set_register(cluster_xy, channel_id, DMA_DST_EXT,
162            (unsigned int)(dst_paddr>>32));
163    _dma_set_register(cluster_xy, channel_id, DMA_LEN,
164            (unsigned int)size);
165
166#endif
167}
168
169///////////////////////////////////////////////////////
170void _dma_physical_copy( unsigned int       cluster_xy,  // DMA cluster
171                         unsigned int       channel_id,  // DMA channel
172                         unsigned long long dst_paddr,   // destination physical address
173                         unsigned long long src_paddr,   // source physical address
174                         unsigned int       size )       // bytes
175{
176#if NB_DMA_CHANNELS > 0
177
178    // check DMA channel parameters
179    unsigned int x = cluster_xy >> Y_WIDTH;
180    unsigned int y = cluster_xy & ((1<<Y_WIDTH)-1);
181    if ( (x >= X_SIZE) || (y >= Y_SIZE) || (channel_id >= NB_DMA_CHANNELS) )
182    {
183        _puts("\n[DMA ERROR] in _dma_physical_copy() : illegal DMA channel ");
184        _exit();
185    }
186
187    // check buffers alignment constraints
188    if ( (dst_paddr & 0x3)   || (src_paddr & 0x3) || (size & 0x3) )
189    {
190        _puts("\n[DMA ERROR] in _dma_physical_copy() : buffer unaligned\n");
191        _exit();
192    }
193
194#if GIET_DEBUG_DMA_DRIVER
195_puts("\n[DMA DEBUG] enter _dma_physical_copy() for channel[");
196_putd( x );
197_puts(",");
198_putd( y );
199_puts(",");
200_putd( channel_id );
201_puts("] at cycle ");
202_putd( _get_proctime() );
203_puts("\n - src_paddr   = ");
204_putl( src_paddr );
205_puts("\n - dst_paddr   = ");
206_putl( dst_paddr );
207_puts("\n - bytes       = ");
208_putd( size );
209_puts("\n");
210#endif
211
212    // dma channel configuration & lauching
213    _dma_start_transfer( cluster_xy, channel_id, dst_paddr, src_paddr, size ); 
214
215    // scan dma channel status
216    unsigned int status = _dma_get_status( cluster_xy, channel_id );
217    while( (status != DMA_SUCCESS) && 
218           (status != DMA_READ_ERROR) &&
219           (status != DMA_WRITE_ERROR) )
220    {
221        status = _dma_get_status( cluster_xy, channel_id );
222
223#if GIET_DEBUG_DMA_DRIVER
224_puts("\n[DMA DEBUG] _dma_physical_copy() : ... waiting on DMA_STATUS register\n");
225#endif
226
227    }
228   
229    // analyse status
230    if( status != DMA_SUCCESS )
231    {
232        _puts("\n[DMA ERROR] in _dma_physical_copy() : bad DMA_STATUS");
233        _exit();
234    }
235
236    // reset dma channel
237    _dma_reset( cluster_xy, channel_id );
238
239#if GIET_DEBUG_DMA_DRIVER
240_puts("\n[DMA DEBUG] exit _dma_physical_copy() at cycle ");
241_putd( _get_proctime() );
242_puts("\n");
243#endif
244
245#else // NB_DMA_CHANNELS == 0
246
247    _puts("\n[DMA ERROR] in _dma_physical_copy() : NB_DMA_CHANNELS == 0\n");
248    _exit();
249
250#endif
251}
252
253
254////////////////////////////////////////
255void  _dma_copy( unsigned int cluster_xy,    // DMA cluster
256                 unsigned int channel_id,    // DMA channel
257                 unsigned int vspace_id,     // vspace index for v2p translation
258                 unsigned int dst_vaddr,     // dst_vaddr buffer vbase
259                 unsigned int src_vaddr,     // src_vaddr buffer vbase
260                 unsigned int size )         // bytes
261{
262#if NB_DMA_CHANNELS > 0
263
264    // check DMA channel parameters
265    unsigned int x = cluster_xy >> Y_WIDTH;
266    unsigned int y = cluster_xy & ((1<<Y_WIDTH)-1);
267    if ( (x >= X_SIZE) || (y >= Y_SIZE) || (channel_id >= NB_DMA_CHANNELS) )
268    {
269        _puts("\n[DMA ERROR] in _dma_copy() : illegal DMA channel ");
270        _exit();
271    }
272
273    // check buffers alignment constraints
274    if ( (dst_vaddr & 0x3)   || (src_vaddr & 0x3) || (size & 0x3) )
275    {
276        _puts("\n[DMA ERROR] in _dma_copy() : buffer unaligned\n");
277        _exit();
278    }
279
280    unsigned int ppn;
281    unsigned int flags;
282
283#if GIET_DEBUG_DMA_DRIVER
284_puts("\n[DMA DEBUG] enter _dma_copy() for channel[");
285_putd( x );
286_puts(",");
287_putd( y );
288_puts(",");
289_putd( channel_id );
290_puts("] at cycle ");
291_putd( _get_proctime() );
292_puts("\n - src_vaddr   = ");
293_putx( src_vaddr );
294_puts("\n - dst_vaddr   = ");
295_putx( dst_vaddr );
296_puts("\n - bytes       = ");
297_putd( size );
298_puts("\n");
299#endif
300
301    // checking alignment constraints
302    if ( (((unsigned int)dst_vaddr) & 0x3) ||
303         (((unsigned int)src_vaddr) & 0x3) ||
304         (size & 0x3) )
305    {
306        _puts("\n[DMA ERROR] in _dma_copy() : buffer unaligned\n");
307        _exit();
308    }
309
310    // get vspace page table pointer
311    unsigned int pt = _ptabs_vaddr[vspace_id];
312
313    // get src_paddr buffer physical addresse
314    _v2p_translate( (page_table_t*)pt,              // page table pointer
315                     src_vaddr>>12,                  // vpn
316                     &ppn,                           // ppn
317                     &flags );                       // flags
318    unsigned long long src_paddr = (((unsigned long long)ppn) << 12) | 
319                                   (unsigned long long)(src_vaddr & 0x00000FFF);
320
321    // get dst_paddr buffer physical addresse
322    _v2p_translate( (page_table_t*)pt,              // page table pointer
323                     dst_vaddr>>12,                  // vpn
324                     &ppn,                           // ppn
325                     &flags );                       // flags
326    unsigned long long dst_paddr = (((unsigned long long)ppn) << 12) | 
327                                   (unsigned long long)(dst_vaddr & 0x00000FFF);
328
329#if GIET_DEBUG_DMA_DRIVER
330_puts("\n - src_paddr   = ");
331_putl( src_paddr );
332_puts("\n - dst_paddr   = ");
333_putl( dst_paddr );
334_puts("\n");
335#endif
336
337    // dma channel configuration & lauching
338    _dma_start_transfer(  cluster_xy, channel_id, dst_paddr, src_paddr, size ); 
339
340    // scan dma channel status
341    unsigned int status = _dma_get_status( cluster_xy, channel_id );
342    while( (status != DMA_SUCCESS) && 
343           (status != DMA_READ_ERROR) &&
344           (status != DMA_WRITE_ERROR) )
345    {
346        status = _dma_get_status( cluster_xy, channel_id );
347
348#if GIET_DEBUG_DMA_DRIVER
349_puts("\n[DMA DEBUG] _dma_copy() : ... waiting on DMA_STATUS register\n");
350#endif
351
352    }
353   
354    // analyse status
355    if( status != DMA_SUCCESS )
356    {
357        _puts("\n[DMA ERROR] in _dma_copy() : bad DMA_STATUS\n");
358        _exit();
359    }
360    // reset dma channel
361    _dma_reset( cluster_xy, channel_id );
362
363#if GIET_DEBUG_DMA_DRIVER
364_puts("\n[DMA DEBUG] exit _dma_copy() at cycle ");
365_putd( _get_proctime() );
366_puts("\n");
367#endif
368
369#else // NB_DMA_CHANNELS == 0
370
371    _puts("\n[DMA ERROR] in _dma_copy() : NB_DMA_CHANNELS == 0\n");
372    _exit();
373
374#endif
375} // end _dma_copy
376
377/////////////////////////////////////
378void _dma_isr( unsigned int irq_type,
379               unsigned int irq_id,
380               unsigned int channel )
381{
382    _puts("\n[DMA ERROR] _dma_isr() not implemented\n");
383    _exit();
384}
385
386
387
388
389// tab-width: 4
390// c-basic-offset: 4
391// c-file-offsets:((innamespace . 0)(inline-open . 0))
392// indent-tabs-mode: nil
393// End:
394// vim: filetype=c:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
395
Note: See TracBrowser for help on using the repository browser.