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

Last change on this file since 304 was 298, checked in by alain, 11 years ago

Introducing pic driver and rdk driver

File size: 11.9 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 destination memory buffer,
177// using the distributed DMA. As it makes virtual to physical address translation,
178// the MMU should be activated.
179// This driver makes the assumption that each processor has a private DMA channel:
180// the DMA cluster and channel indexes are obtained from the processor index.
181// The source and destination buffers base addresses must be word aligned,
182// and the buffer's size must be multiple of 4.
183// In case of error (buffer unmapped, unaligned, or DMA_STATUS error), an error
184// message is displayed on TTY0, and the system crash.
185///////////////////////////////////////////////////////////////////////////////////
186// Note: this blocking function is supposed to be used by the kernel only,
187// and uses a polling policy on DMA_STATUS register to detect completion.
188// Therefore, the DMA_IRQ is NOT used.
189///////////////////////////////////////////////////////////////////////////////////
190inline void  _dma_copy( unsigned int vspace_id, // vspace index for V2P
191                        void*        dest,      // dest buffer vbase
192                        const void*  source,    // source buffer vbase
193                        unsigned int size )     // bytes
194{
195#if NB_DMA_CHANNELS > 0
196
197    unsigned int procid    = _get_procid();
198    unsigned int cluster_xy = procid/NB_PROCS_MAX;
199    unsigned int channel_id = procid%NB_PROCS_MAX;
200
201    unsigned int ko;
202    unsigned int ppn;
203    unsigned int flags;
204
205#if GIET_DEBUG_DMA_DRIVER
206unsigned int x          = cluster_xy >> Y_WIDTH;
207unsigned int y          = cluster_xy & ((1<<Y_WIDTH)-1);
208
209_printf("\n[DMA DEBUG] Processor[%d,%d,%d] enters _dma_copy() at cycle %d\n"
210        " - vspace_id  = %d\n"
211        " - cluster_xy = %x\n"
212        " - channel_id = %d\n"
213        " - dest       = %x\n"
214        " - source     = %x\n"
215        " - bytes      = %x\n",
216        x, y, channel_id, _get_proctime(), vspace_id, cluster_xy,
217        (unsigned int)dest, (unsigned int)source, size );
218#endif
219
220    // checking alignment constraints
221    if ( (((unsigned int)dest) & 0x3)   ||
222         (((unsigned int)source) & 0x3) ||
223         (size & 0x3) )
224    {
225        _printf("\n[GIET ERROR] in _dma_copy() : buffer unaligned\n");
226        _exit();
227    }
228
229    // get vspace 0 page table pointer
230    unsigned int pt =  _ptabs_vaddr[vspace_id];
231
232    // get source buffer physical addresse
233    ko = _v2p_translate( (page_table_t*)pt,              // page table pointer
234                         ((unsigned int)source)>>12,     // vpn
235                         &ppn,                           // ppn
236                         &flags );                       // flags
237    if ( ko ) 
238    {
239        _printf("\n[GIET ERROR] in _dma_copy() : source buffer unmapped\n");
240        _exit();
241    }
242    unsigned long long src_paddr = (((unsigned long long)ppn) << 12) | 
243                                   ((unsigned int)source & 0x00000FFF);
244
245    // get dest buffer physical addresse
246    ko = _v2p_translate( (page_table_t*)pt,              // page table pointer
247                         ((unsigned int)dest)>>12,       // vpn
248                         &ppn,                           // ppn
249                         &flags );                       // flags
250    if ( ko ) 
251    {
252        _printf("\n[GIET ERROR] in _dma_copy() : dest buffer unmapped\n");
253        _exit();
254    }
255    unsigned long long dst_paddr = (((unsigned long long)ppn) << 12) | 
256                                   ((unsigned int)dest & 0x00000FFF);
257
258#if GIET_DEBUG_DMA_DRIVER
259_printf(" - src_paddr  = %llx\n"
260        " - dst_paddr  = %llx\n",
261        src_paddr, dst_paddr );
262#endif
263
264    // invalidate L1 cache if no hardware cache coherence
265    if ( GIET_NO_HARD_CC ) _dcache_buf_invalidate( dest, size );
266
267    // dma channel configuration & lauching
268    ko = _dma_start_transfer(  cluster_xy, channel_id, dst_paddr, src_paddr, size ); 
269    if ( ko ) 
270    {
271        _printf("\n[GIET ERROR] in _dma_copy() : cannot start transfer\n");
272        _exit();
273    }
274
275    // scan dma channel status
276    unsigned int status = _dma_get_status( cluster_xy, channel_id );
277    while( (status != DMA_SUCCESS) && 
278           (status != DMA_READ_ERROR) &&
279           (status != DMA_WRITE_ERROR) )
280    {
281        status = _dma_get_status( cluster_xy, channel_id );
282
283#if GIET_DEBUG_DMA_DRIVER
284_printf("\n[DMA DEBUG] _dma_copy() : ... waiting on DMA_STATUS register ...\n");
285#endif
286
287    }
288   
289    // analyse status
290    if( status != DMA_SUCCESS )
291    {
292        _printf("\n[GIET ERROR] in _dma_copy() : DMA_STATUS = %x\n", status );
293        _exit();
294    }
295    // reset dma channel
296    _dma_reset( cluster_xy, channel_id );
297
298#if GIET_DEBUG_DMA_DRIVER
299_printf("\n[DMA DEBUG] _dma_copy() completed at cycle %d\n", _get_proctime() );
300#endif
301
302#else // NB_DMA_CHANNELS == 0
303    _printf("\n[GIET ERROR] in _dma_copy() : NB_DMA_CHANNELS = 0 !\n");
304    _exit();
305#endif
306} // end _dma_copy
307
308
309
310
311// tab-width: 4
312// c-basic-offset: 4
313// c-file-offsets:((innamespace . 0)(inline-open . 0))
314// indent-tabs-mode: nil
315// End:
316// vim: filetype=c:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
317
Note: See TracBrowser for help on using the repository browser.