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

Last change on this file since 474 was 456, checked in by alain, 10 years ago

Defining the NIC and CMA drivers (validated by the classif application).
Updating other drivers to comply with the new tty0 common file.

File size: 12.1 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 ko;
281    unsigned int ppn;
282    unsigned int flags;
283
284#if GIET_DEBUG_DMA_DRIVER
285_puts("\n[DMA DEBUG] enter _dma_copy() for channel[");
286_putd( x );
287_puts(",");
288_putd( y );
289_puts(",");
290_putd( channel_id );
291_puts("] at cycle ");
292_putd( _get_proctime() );
293_puts("\n - src_vaddr   = ");
294_putx( src_vaddr );
295_puts("\n - dst_vaddr   = ");
296_putx( dst_vaddr );
297_puts("\n - bytes       = ");
298_putd( size );
299_puts("\n");
300#endif
301
302    // checking alignment constraints
303    if ( (((unsigned int)dst_vaddr) & 0x3) ||
304         (((unsigned int)src_vaddr) & 0x3) ||
305         (size & 0x3) )
306    {
307        _puts("\n[DMA ERROR] in _dma_copy() : buffer unaligned\n");
308        _exit();
309    }
310
311    // get vspace page table pointer
312    unsigned int pt = _ptabs_vaddr[vspace_id];
313
314    // get src_paddr buffer physical addresse
315    ko = _v2p_translate( (page_table_t*)pt,              // page table pointer
316                         src_vaddr>>12,                  // vpn
317                         &ppn,                           // ppn
318                         &flags );                       // flags
319    if ( ko ) 
320    {
321        _puts("\n[DMA ERROR] in _dma_copy() : source buffer unmapped\n");
322        _exit();
323    }
324    unsigned long long src_paddr = (((unsigned long long)ppn) << 12) | 
325                                   (unsigned long long)(src_vaddr & 0x00000FFF);
326
327    // get dst_paddr buffer physical addresse
328    ko = _v2p_translate( (page_table_t*)pt,              // page table pointer
329                         dst_vaddr>>12,                  // vpn
330                         &ppn,                           // ppn
331                         &flags );                       // flags
332    if ( ko ) 
333    {
334        _puts("\n[DMA ERROR] in _dma_copy() : dest buffer unmapped\n");
335        _exit();
336    }
337    unsigned long long dst_paddr = (((unsigned long long)ppn) << 12) | 
338                                   (unsigned long long)(dst_vaddr & 0x00000FFF);
339
340#if GIET_DEBUG_DMA_DRIVER
341_puts("\n - src_paddr   = ");
342_putl( src_paddr );
343_puts("\n - dst_paddr   = ");
344_putl( dst_paddr );
345_puts("\n");
346#endif
347
348    // dma channel configuration & lauching
349    _dma_start_transfer(  cluster_xy, channel_id, dst_paddr, src_paddr, size ); 
350
351    // scan dma channel status
352    unsigned int status = _dma_get_status( cluster_xy, channel_id );
353    while( (status != DMA_SUCCESS) && 
354           (status != DMA_READ_ERROR) &&
355           (status != DMA_WRITE_ERROR) )
356    {
357        status = _dma_get_status( cluster_xy, channel_id );
358
359#if GIET_DEBUG_DMA_DRIVER
360_puts("\n[DMA DEBUG] _dma_copy() : ... waiting on DMA_STATUS register\n");
361#endif
362
363    }
364   
365    // analyse status
366    if( status != DMA_SUCCESS )
367    {
368        _puts("\n[DMA ERROR] in _dma_copy() : bad DMA_STATUS\n");
369        _exit();
370    }
371    // reset dma channel
372    _dma_reset( cluster_xy, channel_id );
373
374#if GIET_DEBUG_DMA_DRIVER
375_puts("\n[DMA DEBUG] exit _dma_copy() at cycle ");
376_putd( _get_proctime() );
377_puts("\n");
378#endif
379
380#else // NB_DMA_CHANNELS == 0
381
382    _puts("\n[DMA ERROR] in _dma_copy() : NB_DMA_CHANNELS == 0\n");
383    _exit();
384
385#endif
386} // end _dma_copy
387
388/////////////////////////////////////
389void _dma_isr( unsigned int irq_type,
390               unsigned int irq_id,
391               unsigned int channel )
392{
393    _puts("\n[DMA ERROR] _dma_isr() not implemented\n");
394    _exit();
395}
396
397
398
399
400// tab-width: 4
401// c-basic-offset: 4
402// c-file-offsets:((innamespace . 0)(inline-open . 0))
403// indent-tabs-mode: nil
404// End:
405// vim: filetype=c:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
406
Note: See TracBrowser for help on using the repository browser.