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

Last change on this file since 264 was 263, checked in by alain, 11 years ago

Introducing support for TSAR fixed format cluster index (cluster_xy)
We have now 4 parameters defined in map.xml:

  • X_WIDTH, Y_WIDTH define the fixed format (typically X_WIDTH = 4 / Y_WIDTH = 4)
  • X_SIZE, Y_SIZE define the actual TSAR 2D mesh variable size (from 1 to 16)
File size: 12.3 KB
Line 
1///////////////////////////////////////////////////////////////////////////////////
2// File     : dma_driver.c
3// Date     : 23/11/2013
4// Author   : alain greiner
5// Copyright (c) UPMC-LIP6
6///////////////////////////////////////////////////////////////////////////////////
7// The dma_driver.c and dma_driver.h files are part ot the GIET-VM nano-kernel.
8// This driver supports the SoCLib vci_multi_dma component.
9//
10// It can exist several DMA controlers in the architecture (one per cluster),
11// and each controller can contain several channels.
12//
13// There is  (NB_CLUSTERS * NB_DMA_CHANNELS) channels, indexed by a global index:
14//        dma_id = cluster_xy * NB_DMA_CHANNELS + loc_id
15//
16// A DMA channel is a private ressource allocated to a given processor.
17// It is exclusively used by the kernet to speedup data transfers, and
18// there is no lock protecting exclusive access to the channel.
19// As the kernel uses a polling policy on the DMA_STATUS register to detect
20// transfer completion, the DMA IRQ is not used, and there is no DMA_ISR.
21////////////////////////////////////////////////////////////////////////////////////
22// The virtual base address of the segment associated to a channel is:
23//
24//    seg_dma_base + cluster_xy * vseg_cluster_increment + DMA_SPAN * channel_id
25//
26////////////////////////////////////////////////////////////////////////////////////
27
28#include <giet_config.h>
29#include <dma_driver.h>
30#include <utils.h>
31#include <tty_driver.h>
32#include <vmem.h>
33
34#if !defined(X_SIZE)
35# error: You must define X_SIZE in the hard_config.h file
36#endif
37
38#if !defined(Y_SIZE)
39# error: You must define X_SIZE in the hard_config.h file
40#endif
41
42#if !defined(X_WIDTH)
43# error: You must define X_WIDTH in the hard_config.h file
44#endif
45
46#if !defined(Y_WIDTH)
47# error: You must define X_WIDTH in the hard_config.h file
48#endif
49
50#if !defined(NB_DMA_CHANNELS)
51# error: You must define NB_DMA_CHANNELS in the hard_config.h file
52#endif
53
54extern unsigned int _ptabs_vaddr[];
55
56//////////////////////////////////////////////////////////////////////////////////
57// AS the GIET-VM uses a polling policy to detect transfer completion,
58// The DMA component initialisation must disable interrupts.
59// This function disables interrupts for one DMA channel in one cluster.
60// Returns 0 if success, returns > 0 if error.
61//////////////////////////////////////////////////////////////////////////////////
62unsigned int _dma_init( unsigned int cluster_xy,
63                        unsigned int channel_id )
64{
65#if NB_DMA_CHANNELS > 0
66
67    // parameters checking
68    unsigned int x = cluster_xy >> Y_WIDTH;
69    unsigned int y = cluster_xy & ((1<<Y_WIDTH)-1);
70    if (x >= X_SIZE)                    return 1; 
71    if (y >= Y_SIZE)                    return 1; 
72    if (channel_id >= NB_DMA_CHANNELS)  return 1; 
73
74    // compute DMA base address
75    unsigned int* dma_address = (unsigned int*) ((unsigned int)&seg_dma_base + 
76                                (cluster_xy * (unsigned int)&vseg_cluster_increment));
77
78    // disable interrupt for selected channel
79    dma_address[channel_id * DMA_SPAN + DMA_IRQ_DISABLE] = 1;           
80    return 0;
81#else
82    return 1;
83#endif
84}
85
86//////////////////////////////////////////////////////////////////////////////////
87// This function re-initialises one DMA channel in one cluster after a transfer
88// completion. It actually forces the channel to return in iDLE state.
89//////////////////////////////////////////////////////////////////////////////////
90unsigned int _dma_reset( unsigned int cluster_xy, 
91                         unsigned int channel_id ) 
92{
93#if NB_DMA_CHANNELS > 0
94
95    // parameters checking
96    unsigned int x = cluster_xy >> Y_WIDTH;
97    unsigned int y = cluster_xy & ((1<<Y_WIDTH)-1);
98    if (x >= X_SIZE)                    return 1; 
99    if (y >= Y_SIZE)                    return 1; 
100    if (channel_id >= NB_DMA_CHANNELS)  return 1; 
101
102    // compute DMA base address
103    unsigned int* dma_address = (unsigned int*) ((unsigned int)&seg_dma_base + 
104                                (cluster_xy * (unsigned int)&vseg_cluster_increment));
105
106    // reset selected channel
107    dma_address[channel_id * DMA_SPAN + DMA_RESET] = 0;           
108    return 0;
109#else
110    return 1;
111#endif
112}
113
114//////////////////////////////////////////////////////////////////////////////////
115// This function returns the status of a DMA channel in a given cluster
116//////////////////////////////////////////////////////////////////////////////////
117unsigned int _dma_get_status( unsigned int cluster_xy, 
118                              unsigned int channel_id ) 
119{
120#if NB_DMA_CHANNELS > 0
121
122    // parameters checking
123    unsigned int x = cluster_xy >> Y_WIDTH;
124    unsigned int y = cluster_xy & ((1<<Y_WIDTH)-1);
125    if (x >= X_SIZE)                    return 1; 
126    if (y >= Y_SIZE)                    return 1; 
127    if (channel_id >= NB_DMA_CHANNELS)  return 1;
128
129    // compute DMA base address
130    unsigned int * dma_address = (unsigned int *) ((unsigned int)&seg_dma_base + 
131                                 (cluster_xy * (unsigned int)&vseg_cluster_increment));
132
133    // get selected channel status
134    return dma_address[channel_id * DMA_SPAN + DMA_LEN];
135#else
136    return DMA_ERROR;
137#endif
138}
139
140//////////////////////////////////////////////////////////////////////////////////
141// This function sets the physical address (including 64 bits extension)
142// for the source and destination buffers in a DMA channel in a given cluster
143// and sets the transfer size to lauch the transfer.
144//////////////////////////////////////////////////////////////////////////////////
145unsigned int _dma_start_transfer( unsigned int       cluster_xy,
146                                  unsigned int       channel_id,
147                                  unsigned long long dst_paddr,   // physical address
148                                  unsigned long long src_paddr,   // physical address
149                                  unsigned int       size )       // bytes
150{
151#if NB_DMA_CHANNELS > 0
152
153    // parameters checking
154    unsigned int x = cluster_xy >> Y_WIDTH;
155    unsigned int y = cluster_xy & ((1<<Y_WIDTH)-1);
156    if (x >= X_SIZE)                    return 1; 
157    if (y >= Y_SIZE)                    return 1; 
158    if (channel_id >= NB_DMA_CHANNELS)  return 1;
159
160    // compute DMA base address
161    unsigned int * dma_address = (unsigned int *) ((unsigned int)&seg_dma_base + 
162                                 (cluster_xy * (unsigned int)&vseg_cluster_increment));
163
164    // selected channel configuration and lauching
165    dma_address[channel_id * DMA_SPAN + DMA_SRC]     = (unsigned int)(src_paddr);
166    dma_address[channel_id * DMA_SPAN + DMA_SRC_EXT] = (unsigned int)(src_paddr>>32);
167    dma_address[channel_id * DMA_SPAN + DMA_DST]     = (unsigned int)(dst_paddr);
168    dma_address[channel_id * DMA_SPAN + DMA_DST_EXT] = (unsigned int)(dst_paddr>>32);
169    dma_address[channel_id * DMA_SPAN + DMA_LEN]     = (unsigned int)size;
170    return 0;
171#else
172    return 1;
173#endif
174}
175///////////////////////////////////////////////////////////////////////////////////
176// This function copies a source memory buffer to a destnation memory buffer,
177// using the distributed DMA. As it makes virtual to physical address translation,
178// the MMU should be activated. As there is one DMA channel per processor,
179// the DMA cluster and channel indexes are obtained from the processor index.
180// The source and destination buffers base addresses must be word aligned,
181// and the buffer's size must be multiple of 4.
182// In case of error (buffer unmapped, unaligned, or DMA_STATUS error), an error
183// message is displayed on TTY0, and the system crash.
184///////////////////////////////////////////////////////////////////////////////////
185// Note: this blocking function is supposed to be used by the kernel only,
186// and uses a polling policy on DMA_STATUS register to detect completion.
187// Therefore, the DMA_IRQ is NOT used.
188///////////////////////////////////////////////////////////////////////////////////
189inline void  _dma_copy( unsigned int vspace_id, // vspace index for V2P
190                        void*        dest,      // dest buffer vbase
191                        const void*  source,    // source buffer vbase
192                        unsigned int size )     // bytes
193{
194#if NB_DMA_CHANNELS > 0
195
196    unsigned int procid    = _get_procid();
197    unsigned int cluster_xy = procid/NB_PROCS_MAX;
198    unsigned int channel_id = procid%NB_PROCS_MAX;
199
200    unsigned int ko;
201    unsigned int ppn;
202    unsigned int flags;
203
204#if GIET_DEBUG_DMA_DRIVER
205_tty_get_lock( 0 );
206_puts("\n[DMA DEBUG] Enter _dma_copy() at cycle ");
207_putd( _get_proctime() );
208_puts("\n - vspace_id  = ");
209_putx( vspace_id );
210_puts("\n - cluster_xy = ");
211_putx( cluster_xy );
212_puts("\n - channel_id = ");
213_putx( channel_id );
214_puts("\n - dest       = ");
215_putx( (unsigned int)dest );
216_puts("\n - source     = ");
217_putx( (unsigned int)source );
218_puts("\n - bytes      = ");
219_putd( size );
220_tty_release_lock( 0 );
221#endif
222
223    // checking alignment constraints
224    if ( (((unsigned int)dest) & 0x3)   ||
225         (((unsigned int)source) & 0x3) ||
226         (size & 0x3) )
227    {
228        _tty_get_lock( 0 );
229        _puts("\n[GIET ERROR] in _dma_copy() : buffer unaligned\n");
230        _tty_release_lock( 0 );
231        _exit();
232    }
233
234    // get vspace 0 page table pointer
235    unsigned int pt =  _ptabs_vaddr[vspace_id];
236
237    // get source buffer physical addresse
238    ko = _v2p_translate( (page_table_t*)pt,              // page table pointer
239                         ((unsigned int)source)>>12,     // vpn
240                         &ppn,                           // ppn
241                         &flags );                       // flags
242    if ( ko ) 
243    {
244        _tty_get_lock( 0 );
245        _puts("\n[GIET ERROR] in _dma_copy() : source buffer unmapped\n");
246        _tty_release_lock( 0 );
247        _exit();
248    }
249    unsigned long long src_paddr = (((unsigned long long)ppn) << 12) | 
250                                   ((unsigned int)source & 0x00000FFF);
251
252    // get dest buffer physical addresse
253    ko = _v2p_translate( (page_table_t*)pt,              // page table pointer
254                         ((unsigned int)dest)>>12,       // vpn
255                         &ppn,                           // ppn
256                         &flags );                       // flags
257    if ( ko ) 
258    {
259        _tty_get_lock( 0 );
260        _puts("\n[GIET ERROR] in _dma_copy() : dest buffer unmapped\n");
261        _tty_release_lock( 0 );
262        _exit();
263    }
264    unsigned long long dst_paddr = (((unsigned long long)ppn) << 12) | 
265                                   ((unsigned int)dest & 0x00000FFF);
266
267#if GIET_DEBUG_DMA_DRIVER
268_tty_get_lock( 0 );
269_puts("\n - src_paddr  = ");
270_putl( src_paddr );
271_puts("\n - dst_paddr  = ");
272_putl( dst_paddr );
273_puts("\n");
274_tty_release_lock( 0 );
275#endif
276
277    // invalidate L1 cache if no hardware cache coherence
278    if ( GIET_NO_HARD_CC ) _dcache_buf_invalidate( dest, size );
279
280    // dma channel configuration & lauching
281    ko = _dma_start_transfer(  cluster_xy, channel_id, dst_paddr, src_paddr, size ); 
282    if ( ko ) 
283    {
284        _tty_get_lock( 0 );
285        _puts("\n[GIET ERROR] in _dma_copy() : cannot start transfer\n");
286        _tty_release_lock( 0 );
287        _exit();
288    }
289
290    // scan dma channel status
291    unsigned int status = _dma_get_status( cluster_xy, channel_id );
292    while( (status != DMA_SUCCESS) && 
293           (status != DMA_READ_ERROR) &&
294           (status != DMA_WRITE_ERROR) )
295    {
296        status = _dma_get_status( cluster_xy, channel_id );
297
298#if GIET_DEBUG_DMA_DRIVER
299_tty_get_lock( 0 );
300_puts("\n[DMA DEBUG] _dma_copy() : ... waiting on DMA_STATUS register ...\n");
301_tty_release_lock( 0 );
302#endif
303
304    }
305   
306    // analyse status
307    if( status != DMA_SUCCESS )
308    {
309        _tty_get_lock( 0 );
310        _puts("\n[GIET ERROR] in _dma_copy() : DMA_STATUS error = ");
311        _putd( status );
312        _puts("\n");
313        _tty_release_lock( 0 );
314        _exit();
315    }
316    // reset dma channel
317    _dma_reset( cluster_xy, channel_id );
318
319#if GIET_DEBUG_DMA_DRIVER
320_tty_get_lock( 0 );
321_puts("\n[DMA DEBUG] _dma_copy() completed at cycle ");
322_putd( _get_proctime() );
323_puts("\n");
324_tty_release_lock( 0 );
325#endif
326
327#else // NB_DMA_CHANNELS == 0
328    _tty_get_lock( 0 );
329    _puts("\n[GIET ERROR] in _dma_copy() : NB_DMA_CHANNELS = 0 !\n");
330    _tty_release_lock( 0 );
331    _exit();
332#endif
333} // end _dma_copy
334
335
336
337
338// tab-width: 4
339// c-basic-offset: 4
340// c-file-offsets:((innamespace . 0)(inline-open . 0))
341// indent-tabs-mode: nil
342// End:
343// vim: filetype=c:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
344
Note: See TracBrowser for help on using the repository browser.