source: branch/giet_vm_ioc_drivers/giet_drivers/bdv_driver.c @ 283

Last change on this file since 283 was 283, checked in by cfuguet, 10 years ago

Introducing branch to test ioc drivers before merging on trunk

File size: 12.6 KB
Line 
1///////////////////////////////////////////////////////////////////////////////////
2// File     : ioc_driver.c
3// Date     : 23/05/2013
4// Author   : alain greiner
5// Copyright (c) UPMC-LIP6
6///////////////////////////////////////////////////////////////////////////////////
7// The ioc_driver.c and ioc_driver.h files are part ot the GIET-VM kernel.
8// This driver supports the SocLib vci_block_device component, that is
9// a single channel, block oriented, external storage contrÃŽler.
10//
11// It can exist only one block-device controler in the architecture.
12//
13// The _bdv_read() and _bdv_write() functions use the _bdv_access() function,
14// that is always blocking, but can be called in 4 modes:
15//
16// - In BOOT_PA mode, the _bdv_access() function use the buffer virtual address
17//   as a physical address (as the page tables are not build) and use a polling
18//   policy on the IOC_STATUS register to detect transfer completion, as
19//   hardware interrupts are not activated. This mode is used by the
20//   boot code to load the map.bin file into memory.
21//
22// - In BOOT_VA mode, the _bdv_access() function makes a V2P translation to
23//   compute the buffer physical address, and use a polling policy on IOC_STATUS
24//   register to detect transfer completion. This mode is used by the boot code
25//   to load the various .elf files into memory.
26//
27// - In KERNEL mode, the _bdv_access() function makes a V2P translation to
28//   compute the buffer physical address, and use a descheduling strategy:
29//   The ISR executed when transfer completes should restart the calling task.
30//   There is no checking of user access right to the memory buffer.
31//   This mode must be used to access IOC, for an "open" system call.
32//
33// - In USER mode, the _bdv_access() function makes a V2P translation to
34//   compute the buffer physical address, and use a descheduling strategy:
35//   The ISR executed when transfer completes should restart the calling task,
36//   The user access right to the memory buffer must be checked.
37//   This mode must be used to access IOC, for a "read/write" system call.
38//
39// As the IOC component can be used by several programs running in parallel,
40// the _ioc_lock variable guaranties exclusive access to the device.  The
41// _bdv_read() and _bdv_write() functions use atomic LL/SC to get the lock.
42//
43// The IOMMU can be activated or not:
44//
45// 1) When the IOMMU is used, a fixed size 2Mbytes vseg is allocated to
46// the IOC peripheral, in the I/O virtual space, and the user buffer is
47// dynamically remapped in the IOMMU page table. The corresponding entry
48// in the IOMMU PT1 is defined by the kernel _ioc_iommu_ix1 variable.
49// The number of pages to be unmapped is stored in the _ioc_npages variable.
50// The number of PT2 entries is dynamically computed and stored in the
51// kernel _ioc_iommu_npages variable. It cannot be larger than 512.
52// The user buffer is unmapped by the _ioc_completed() function when
53// the transfer is completed.
54//
55// 2/ If the IOMMU is not used, we check that  the user buffer is mapped to a
56// contiguous physical buffer (this is generally true because the user space
57// page tables are statically constructed to use contiguous physical memory).
58//
59// Finally, the memory buffer must fulfill the following conditions:
60// - The buffer must be word aligned,
61// - The buffer must be mapped in user space for an user access,
62// - The buffer must be writable in case of (to_mem) access,
63// - The total number of physical pages occupied by the user buffer cannot
64//   be larger than 512 pages if the IOMMU is activated,
65// - All physical pages occupied by the user buffer must be contiguous
66//   if the IOMMU is not activated.
67// An error code is returned if these conditions are not verified.
68///////////////////////////////////////////////////////////////////////////////////
69// The seg_ioc_base virtual base addresses must be defined in giet_vsegs.ld file.
70///////////////////////////////////////////////////////////////////////////////////
71
72#include <giet_config.h>
73#include <ioc_driver.h>
74#include <bdv_driver.h>
75#include <utils.h>
76#include <tty_driver.h>
77#include <ctx_handler.h>
78
79///////////////////////////////////////////////////////////////////////////////
80//      _bdv_access()
81// This function transfer data between a memory buffer and the block device.
82// The buffer lentgth is (count*block_size) bytes.
83// Arguments are:
84// - to_mem     : from external storage to memory when non 0.
85// - kernel     : kernel buffer with identity mapping when non 0.
86// - lba        : first block index on the external storage.
87// - buf_vaddr  : virtual base address of the memory buffer.
88// - count      : number of blocks to be transfered.
89// Returns 0 if success, > 0 if error.
90///////////////////////////////////////////////////////////////////////////////
91static unsigned int _bdv_access( unsigned int to_mem,
92                                 unsigned int mode,
93                                 unsigned int lba,
94                                 paddr_t buf_paddr,
95                                 unsigned int count) 
96{
97
98#if GIET_DEBUG_IOC_DRIVER
99_tty_get_lock( 0 );
100_puts("\n[IOC DEBUG] Enter _bdv_access() at cycle ");
101_putd( _get_proctime() );
102_puts(" for processor ");
103_putd( _get_procid() );
104_puts("\n - mode    = ");
105_putd( mode );
106_puts("\n - paddr   = ");
107_putx( buf_paddr );
108_puts("\n - sectors = ");
109_putd( count );
110_puts("\n - lba     = ");
111_putx( lba );
112_puts("\n");
113_tty_release_lock( 0 );
114#endif
115
116    volatile unsigned int * ioc_address = (unsigned int *) &seg_ioc_base ;
117    unsigned int error = 0;
118
119    // get the lock protecting IOC
120    _get_lock(&_ioc_lock);
121
122    // set the _ioc_status polling variable
123    _ioc_status = BLOCK_DEVICE_BUSY;
124
125    ioc_address[BLOCK_DEVICE_BUFFER]     = (unsigned int)buf_paddr;
126    ioc_address[BLOCK_DEVICE_BUFFER_EXT] = (unsigned int)(buf_paddr>>32);
127    ioc_address[BLOCK_DEVICE_COUNT]      = count;
128    ioc_address[BLOCK_DEVICE_LBA]        = lba;
129
130    // There is two policies for transfer completion
131        // detection, depending on the mode argument:
132
133    if ( (mode == IOC_BOOT_PA_MODE) ||    // We poll directly the IOC_STATUS register
134         (mode == IOC_BOOT_VA_MODE) )     // as IRQs are masked.
135    {
136        // Launch transfert
137        if (to_mem == 0) ioc_address[BLOCK_DEVICE_OP] = BLOCK_DEVICE_WRITE;
138        else             ioc_address[BLOCK_DEVICE_OP] = BLOCK_DEVICE_READ;
139
140        unsigned int status;
141        if ( _bdv_get_status(0, &status) ) return 1;
142
143        while( (status != BLOCK_DEVICE_READ_SUCCESS)  &&
144               (status != BLOCK_DEVICE_READ_ERROR)    &&
145               (status != BLOCK_DEVICE_WRITE_SUCCESS) &&
146               (status != BLOCK_DEVICE_WRITE_ERROR) ) 
147        {
148            if ( _bdv_get_status(0, &status) ) return 1;
149
150#if GIET_DEBUG_IOC_DRIVER
151_tty_get_lock( 0 );
152_puts("\n[IOC DEBUG] _bdv_access() : ... waiting on IOC_STATUS register ...\n");
153_tty_release_lock( 0 );
154#endif
155
156        }
157        // analyse status
158        error = ( (status == BLOCK_DEVICE_READ_ERROR) ||
159                  (status == BLOCK_DEVICE_WRITE_ERROR) );
160
161        // release lock
162        _release_lock(&_ioc_lock);     
163    }
164    else                           // in USER or KERNEL mode, we deschedule the task.
165                                   // When the task is rescheduled by the ISR, we reset
166                                   // the _ioc_status variable, and release the lock
167    {
168        // We need a critical section, because we must reset the RUN bit
169                // before to launch the transfer, and we want to avoid to be descheduled
170                // between these two operations.
171
172        // Enter critical section
173        _it_disable(); 
174       
175        // set _ioc_gtid and reset runnable
176        unsigned int ltid = _get_proc_task_id();
177        unsigned int pid = _get_procid();
178        _ioc_gtid = (pid<<16) + ltid;
179        _set_task_slot( pid, ltid, CTX_RUN_ID, 0 ); 
180       
181        // Launch transfert
182        if (to_mem == 0) ioc_address[BLOCK_DEVICE_OP] = BLOCK_DEVICE_WRITE;
183        else             ioc_address[BLOCK_DEVICE_OP] = BLOCK_DEVICE_READ;
184
185        // deschedule task
186        _ctx_switch();                     
187
188        // analyse status
189        error = ( (_ioc_status == BLOCK_DEVICE_READ_ERROR) ||
190                  (_ioc_status == BLOCK_DEVICE_WRITE_ERROR) );
191
192        // reset _ioc_status and release lock
193        _ioc_status = BLOCK_DEVICE_IDLE; 
194        _release_lock(&_ioc_lock);     
195    }
196
197#if GIET_DEBUG_IOC_DRIVER
198_tty_get_lock( 0 );
199_puts("\n[IOC DEBUG] _bdv_access completed at cycle ");
200_putd( _get_proctime() );
201_puts(" for processor ");
202_putd( _get_procid() );
203_puts(" : error = ");
204_putd( (unsigned int)error );
205_puts("\n");
206_tty_release_lock( 0 );
207#endif
208
209    return error;
210} // end _bdv_access()
211
212///////////////////////////////////////////////////////////////////////////////
213//       _bdv_init()
214// This function cheks block size, and activates the IOC interrupts.
215// Return 0 for success, > 0 if error
216///////////////////////////////////////////////////////////////////////////////
217unsigned int _bdv_init( unsigned int channel )
218{
219    volatile unsigned int * ioc_address = (unsigned int *) &seg_ioc_base ;
220   
221    if ( ioc_address[BLOCK_DEVICE_BLOCK_SIZE] != 512 )
222    {
223        _tty_get_lock( 0 );
224        _puts("\n[GIET ERROR] in _bdv_init() : block size must be 512 bytes\n");
225        _tty_release_lock( 0 );
226        return 1; 
227    }
228
229    if ( channel != 0 )
230    {
231        _tty_get_lock( 0 );
232        _puts("\n[GIET ERROR] in _bdv_init() : illegal channel\n");
233        _tty_release_lock( 0 );
234
235        return 1;
236    }
237
238    ioc_address[BLOCK_DEVICE_IRQ_ENABLE] = 1;
239    return 0;
240}
241
242///////////////////////////////////////////////////////////////////////////////
243//     _bdv_read()
244// Transfer data from the block device to a memory buffer.
245// - mode     : BOOT / KERNEL / USER
246// - lba      : first block index on the block device
247// - buffer   : base address of the memory buffer (must be word aligned)
248// - count    : number of blocks to be transfered.
249// Returns 0 if success, > 0 if error.
250///////////////////////////////////////////////////////////////////////////////
251unsigned int _bdv_read( unsigned int mode, 
252                        unsigned int lba, 
253                        paddr_t      buffer, 
254                        unsigned int count) 
255{
256    return _bdv_access( 1,        // read access
257                        mode, 
258                        lba,
259                        buffer,
260                        count );
261}
262
263///////////////////////////////////////////////////////////////////////////////
264//     _bdv_write()
265// Transfer data from a memory buffer to the block device.
266// - mode     : BOOT / KERNEL / USER
267// - lba      : first block index on the block device
268// - buffer   : base address of the memory buffer (must be word aligned)
269// - count    : number of blocks to be transfered.
270// Returns 0 if success, > 0 if error.
271///////////////////////////////////////////////////////////////////////////////
272unsigned int _bdv_write( unsigned int mode, 
273                         unsigned int lba, 
274                         paddr_t  buffer, 
275                         unsigned int count ) 
276{
277    return _bdv_access( 0,        // write access
278                        mode, 
279                        lba,
280                        buffer,
281                        count );
282}
283
284///////////////////////////////////////////////////////////////////////////////
285//     _bdv_get_status()
286// This function returns in the status variable, the transfert status, and
287// acknowledge the IRQ if the IOC controler is not busy.
288// Returns 0 if success, > 0 if error
289///////////////////////////////////////////////////////////////////////////////
290unsigned int _bdv_get_status( unsigned int  channel,
291                              unsigned int* status )
292{
293    if ( channel != 0 )
294    {
295        _tty_get_lock( 0 );
296        _puts("\n[GIET ERROR] in _bdv_get_status() : illegal channel\n");
297        _tty_release_lock( 0 );
298
299        return 1;
300    }
301
302    // get IOC base address
303    volatile unsigned int * ioc_address = (unsigned int *) &seg_ioc_base;
304    *status = ioc_address[BLOCK_DEVICE_STATUS];
305
306    return 0;
307}
308
309///////////////////////////////////////////////////////////////////////////////
310//     _bdv_get_block_size()
311// This function returns the block_size with which the IOC has been configured.
312///////////////////////////////////////////////////////////////////////////////
313unsigned int _bdv_get_block_size() 
314{
315    // get IOC base address
316    volatile unsigned int * ioc_address = (unsigned int *) &seg_ioc_base;
317   
318    return  ioc_address[BLOCK_DEVICE_BLOCK_SIZE];
319}
320
321
322// Local Variables:
323// tab-width: 4
324// c-basic-offset: 4
325// c-file-offsets:((innamespace . 0)(inline-open . 0))
326// indent-tabs-mode: nil
327// End:
328// vim: filetype=c:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
329
Note: See TracBrowser for help on using the repository browser.