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

Last change on this file since 487 was 481, checked in by alain, 10 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.