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

Last change on this file since 276 was 267, checked in by cfuguet, 11 years ago
  • Adding new task context information: THREAD INDEX.

This value can be accessed by USER applications to get the
thread index of the current task. This thread index
corresponds to the index in a vspace.

The value of this index can be forced in the vspace part
of the XML description file using the trdid field in the
task description. When this value is missing, for each
task, a value from 0 to N-1 will be assigned, where N is
the number of task in the vspace.

The user application access this value through the
giet_thread_id() function defined in the stdio library
which uses the SYSCALL_THREAD_ID to access the task
context information.

  • Supporting mono TTY platforms

When the GIET_MONO_TTY constant defined in the giet_config
file, contains a value different than 0, all tasks will
share the TTY[0]. If this is the case, in the stdio
library, the giet_tty_printf() function will take the TTY
hardware lock before writing

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_IDLE;
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.