source: soft/giet_vm/giet_drivers/ioc_driver.c @ 287

Last change on this file since 287 was 279, checked in by cfuguet, 11 years ago

Modifications in the ioc_driver:

  • Introducing uniform interface to access block device controller. All drivers for new disk controllers must respect the interface specified in the ioc_driver header file.
File size: 18.1 KB
RevLine 
[258]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 _ioc_read() and _ioc_write() functions use the _ioc_access() function,
14// that is always blocking, but can be called in 4 modes:
15//
16// - In BOOT_PA mode, the _ioc_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 _ioc_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 _ioc_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 _ioc_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// _ioc_read() and _ioc_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 <utils.h>
75#include <tty_driver.h>
76#include <iob_driver.h>
77#include <ctx_handler.h>
78#include <mmc_driver.h>
79#include <vmem.h>
80
81#if !defined( USE_IOB )
82# error: You must define USE_IOB in the hard_config.h file
83#endif
84
85#if !defined(GIET_USE_IOMMU)
86# error: You must define GIET_USE_IOMMU in the giet_config.h file
87#endif
88
89#define in_unckdata __attribute__((section (".unckdata")))
90
91///////////////////// IOC global variables
92
93in_unckdata unsigned int          _ioc_lock = 0;
94in_unckdata volatile unsigned int _ioc_status = 0;
95in_unckdata volatile unsigned int _ioc_gtid;
96in_unckdata volatile unsigned int _ioc_iommu_ix1 = 0;
97in_unckdata volatile unsigned int _ioc_iommu_npages; 
98
99///////////////////////////////////////////////////////////////////////////////
100//      _ioc_access()
101// This function transfer data between a memory buffer and the block device.
102// The buffer lentgth is (count*block_size) bytes.
103// Arguments are:
104// - to_mem     : from external storage to memory when non 0.
105// - kernel     : kernel buffer with identity mapping when non 0.
106// - lba        : first block index on the external storage.
107// - buf_vaddr  : virtual base address of the memory buffer.
108// - count      : number of blocks to be transfered.
109// Returns 0 if success, > 0 if error.
110///////////////////////////////////////////////////////////////////////////////
111static unsigned int _ioc_access( unsigned int to_mem,
112                                 unsigned int mode,
113                                 unsigned int lba,
114                                 unsigned int buf_vaddr,
115                                 unsigned int count) 
116{
117
118#if GIET_DEBUG_IOC_DRIVER
119_tty_get_lock( 0 );
120_puts("\n[IOC DEBUG] Enter _ioc_access() at cycle ");
121_putd( _get_proctime() );
122_puts(" for processor ");
123_putd( _get_procid() );
124_puts("\n - mode    = ");
125_putd( mode );
126_puts("\n - vaddr   = ");
127_putx( buf_vaddr );
128_puts("\n - sectors = ");
129_putd( count );
130_puts("\n - lba     = ");
131_putx( lba );
132_puts("\n");
133_tty_release_lock( 0 );
134#endif
135
136    unsigned int error;            // return value
137    unsigned int pt_vbase;         // page table vbase address
138    unsigned int vpn_min;          // first virtuel page index covering buffer
139    unsigned int vpn_max;          // last virtual page index covering buffer
140    unsigned int vpn;              // current virtual page index
141    unsigned int ppn;              // physical page number
142    unsigned int flags;            // page protection flags
143    unsigned int ix2;              // page index in IOMMU PT1 page table
144    unsigned int ppn_first;        // first physical page number for user buffer
145    unsigned int buf_xaddr = 0;    // user buffer virtual address in IO space (if IOMMU)
146    paddr_t      buf_paddr = 0;    // user buffer physical address (if no IOMMU),
147
148    // check buffer alignment
149    if ((unsigned int) buf_vaddr & 0x3)
150    {
151        _tty_get_lock( 0 );
152        _puts("\n[GIET ERROR] in _ioc_access() : buffer not word aligned\n");
153        _tty_release_lock( 0 );
154        return 1; 
155    }
156
[275]157    volatile unsigned int * ioc_address = (unsigned int *) &seg_ioc_base ;
[258]158
159    unsigned int length = count << 9;  // count * 512 bytes
160
161    // computing target buffer physical address
162    if ( mode == IOC_BOOT_PA_MODE )                // identity mapping
163    {
164        buf_paddr = (paddr_t)buf_vaddr;
165    }
166    else                                           // V2P translation
167    {
168        // get page table virtual address
169        pt_vbase = _get_context_slot(CTX_PTAB_ID);
170        vpn_min = buf_vaddr >> 12;
171        vpn_max = (buf_vaddr + length - 1) >> 12;
172
173        // loop on all virtual pages covering the user buffer
174        for (vpn = vpn_min, ix2 = 0 ; 
175             vpn <= vpn_max ; 
176             vpn++, ix2++ ) 
177        {
178            // get ppn and flags for each vpn
179            unsigned int ko = _v2p_translate( (page_table_t*)pt_vbase,
180                                              vpn,
181                                              &ppn,
182                                              &flags);
183            // check access rights
184            if ( ko )
185            {
186                _tty_get_lock( 0 );
187                _puts("\n[GIET ERROR] in _ioc_access() : buffer unmapped\n");
188                _tty_release_lock( 0 );
189                return 1; 
190            }
191
192            if ( (mode == IOC_USER_MODE) && ((flags & PTE_U) == 0) )
193            {
194                _tty_get_lock( 0 );
195                _puts("\n[GIET ERROR] in _ioc_access() : buffer not user accessible\n");
196                _tty_release_lock( 0 );
197                return 1; 
198            }
199
200            if ( ((flags & PTE_W) == 0 ) && to_mem )
201            {
202                _tty_get_lock( 0 );
203                _puts("\n[GIET ERROR] in _ioc_access() : buffer not writable\n");
204                _tty_release_lock( 0 );
205                return 1; 
206            }
207
208            // save first ppn value
209            if (ix2 == 0) ppn_first = ppn;
210
211#if GIET_USE_IOMMU
212 
213            // check buffer length < 2 Mbytes
214            if (ix2 > 511) // check buffer length < 2 Mbytes
215            {
216                _tty_get_lock( 0 );
217                _puts("\n[GIET ERROR] in _ioc_access() : user buffer > 2 Mbytes\n");
218                _tty_release_lock( 0 );
219                return 1; 
220            }
221            // map the physical page in IOMMU page table
222            _iommu_add_pte2( _ioc_iommu_ix1,    // PT1 index
223                             ix2,               // PT2 index
224                             ppn,               // Physical page number   
225                             flags );           // Protection flags
226
227            // compute user buffer virtual adress in IO space
228            buf_xaddr = (_ioc_iommu_ix1) << 21 | (buf_vaddr & 0xFFF);
229
230#else
231
232            // check that physical pages are contiguous
233            if ((ppn - ppn_first) != ix2) 
234            {
235                _tty_get_lock( 0 );
236                _puts("[GIET ERROR] in _ioc_access() : split physical buffer\n");
237                _tty_release_lock( 0 );
238                return 1; 
239            }
240
241            // compute user buffer physical adress
242            buf_paddr = (((paddr_t)ppn_first) << 12) | (buf_vaddr & 0xFFF);
243#endif           
244
245        } // end for vpn
246    }
247
248#if GIET_USE_IOMMU
249
250    // register the number of pages to be unmapped in IOMMU
251    _ioc_iommu_npages = (vpn_max - vpn_min) + 1;
252
253#endif
254
255    if ( to_mem ) // memory write : invalidate data caches
256    {
257        // L1 cache
258        if ( GIET_NO_HARD_CC ) _dcache_buf_invalidate((void *) buf_vaddr, length);
259
260        // L2 cache (only if IOB used)
261        if ( USE_IOB ) _memc_inval( buf_paddr, length );
262    }
263    else         // memory read : update data caches
264    {
265        // L1 cache : nothing to do if L1 write-through
266
267        // L2 cache (only if IOB used)
268        if ( USE_IOB ) _memc_sync( buf_paddr, length );
269    }
270
271    // get the lock protecting IOC
272    _get_lock(&_ioc_lock);
273
274    // set the _ioc_status polling variable
275    _ioc_status = BLOCK_DEVICE_BUSY;
276
277#if GIET_DEBUG_IOC_DRIVER
278_tty_get_lock( 0 );
279_puts("\n[IOC DEBUG] _ioc_access() : configure IOC\n");
280_puts(" - buf_paddr = ");
281_putl( buf_paddr );
282_puts("\n");
283_puts(" - count     = ");
284_putd( count );
285_puts("\n");
286_puts(" - lba       = ");
[263]287_putx( lba );
[258]288_puts("\n");
289_tty_release_lock( 0 );
290#endif
291
292    // send command to IOC   
293    if ( GIET_USE_IOMMU ) 
294    {
295        ioc_address[BLOCK_DEVICE_BUFFER] = buf_xaddr;
296        ioc_address[BLOCK_DEVICE_COUNT]  = count;
297        ioc_address[BLOCK_DEVICE_LBA]    = lba;
298    }
299    else
300    {
301        ioc_address[BLOCK_DEVICE_BUFFER]     = (unsigned int)buf_paddr;
302        ioc_address[BLOCK_DEVICE_BUFFER_EXT] = (unsigned int)(buf_paddr>>32);
303        ioc_address[BLOCK_DEVICE_COUNT]      = count;
304        ioc_address[BLOCK_DEVICE_LBA]        = lba;
305    }
306
307    // There is two policies for transfer completion
308        // detection, depending on the mode argument:
309
310    if ( (mode == IOC_BOOT_PA_MODE) ||    // We poll directly the IOC_STATUS register
311         (mode == IOC_BOOT_VA_MODE) )     // as IRQs are masked.
312    {
313        // Launch transfert
314        if (to_mem == 0) ioc_address[BLOCK_DEVICE_OP] = BLOCK_DEVICE_WRITE;
315        else             ioc_address[BLOCK_DEVICE_OP] = BLOCK_DEVICE_READ;
316
[279]317        unsigned int status;
318        if ( _ioc_get_status(0, &status) ) return 1;
319
[258]320        while( (status != BLOCK_DEVICE_READ_SUCCESS)  &&
321               (status != BLOCK_DEVICE_READ_ERROR)    &&
322               (status != BLOCK_DEVICE_WRITE_SUCCESS) &&
323               (status != BLOCK_DEVICE_WRITE_ERROR) ) 
324        {
[279]325            if ( _ioc_get_status(0, &status) ) return 1;
[258]326
327#if GIET_DEBUG_IOC_DRIVER
328_tty_get_lock( 0 );
329_puts("\n[IOC DEBUG] _ioc_access() : ... waiting on IOC_STATUS register ...\n");
330_tty_release_lock( 0 );
331#endif
332
333        }
334        // analyse status
335        error = ( (status == BLOCK_DEVICE_READ_ERROR) ||
336                  (status == BLOCK_DEVICE_WRITE_ERROR) );
337
338        // release lock
339        _release_lock(&_ioc_lock);     
340    }
341    else                           // in USER or KERNEL mode, we deschedule the task.
342                                   // When the task is rescheduled by the ISR, we reset
343                                   // the _ioc_status variable, and release the lock
344    {
345        // We need a critical section, because we must reset the RUN bit
346                // before to launch the transfer, and we want to avoid to be descheduled
347                // between these two operations.
348
349        // Enter critical section
350        _it_disable(); 
351       
352        // set _ioc_gtid and reset runnable
353        unsigned int ltid = _get_proc_task_id();
354        unsigned int pid = _get_procid();
355        _ioc_gtid = (pid<<16) + ltid;
356        _set_task_slot( pid, ltid, CTX_RUN_ID, 0 ); 
357       
358        // Launch transfert
359        if (to_mem == 0) ioc_address[BLOCK_DEVICE_OP] = BLOCK_DEVICE_WRITE;
360        else             ioc_address[BLOCK_DEVICE_OP] = BLOCK_DEVICE_READ;
361
362        // deschedule task
363        _ctx_switch();                     
364
365        // analyse status
366        error = ( (_ioc_status == BLOCK_DEVICE_READ_ERROR) ||
367                  (_ioc_status == BLOCK_DEVICE_WRITE_ERROR) );
368
369        // reset _ioc_status and release lock
370        _ioc_status = BLOCK_DEVICE_IDLE; 
371        _release_lock(&_ioc_lock);     
372    }
373
374#if GIET_DEBUG_IOC_DRIVER
375_tty_get_lock( 0 );
376_puts("\n[IOC DEBUG] _ioc_access completed at cycle ");
377_putd( _get_proctime() );
378_puts(" for processor ");
379_putd( _get_procid() );
[263]380_puts(" : error = ");
381_putd( (unsigned int)error );
[258]382_puts("\n");
383_tty_release_lock( 0 );
384#endif
385
386    return error;
387} // end _ioc_access()
388
389///////////////////////////////////////////////////////////////////////////////
390//       _ioc_init()
391// This function cheks block size, and activates the IOC interrupts.
392// Return 0 for success.
393///////////////////////////////////////////////////////////////////////////////
394unsigned int _ioc_init()
395{
[279]396    volatile unsigned int * ioc_address = (unsigned int *) &seg_ioc_base ;
[258]397   
398    if ( ioc_address[BLOCK_DEVICE_BLOCK_SIZE] != 512 )
399    {
400        _puts("\n[GIET ERROR] in _ioc_init() : block size must be 512 bytes\n");
401        _exit();
402    }
403
404    ioc_address[BLOCK_DEVICE_IRQ_ENABLE] = 1;
405    return 0;
406}
407
408///////////////////////////////////////////////////////////////////////////////
409//     _ioc_read()
410// Transfer data from the block device to a memory buffer.
411// - mode     : BOOT / KERNEL / USER
412// - lba      : first block index on the block device
413// - buffer   : base address of the memory buffer (must be word aligned)
414// - count    : number of blocks to be transfered.
415// Returns 0 if success, > 0 if error.
416///////////////////////////////////////////////////////////////////////////////
417unsigned int _ioc_read( unsigned int mode, 
418                        unsigned int lba, 
419                        void*        buffer, 
420                        unsigned int count) 
421{
422    return _ioc_access( 1,        // read access
423                        mode, 
424                        lba,
425                        (unsigned int) buffer,
426                        count );
427}
428
429///////////////////////////////////////////////////////////////////////////////
430//     _ioc_write()
431// Transfer data from a memory buffer to the block device.
432// - mode     : BOOT / KERNEL / USER
433// - lba      : first block index on the block device
434// - buffer   : base address of the memory buffer (must be word aligned)
435// - count    : number of blocks to be transfered.
436// Returns 0 if success, > 0 if error.
437///////////////////////////////////////////////////////////////////////////////
438unsigned int _ioc_write( unsigned int mode, 
439                         unsigned int lba, 
440                         const void*  buffer, 
441                         unsigned int count ) 
442{
443    return _ioc_access( 0,        // write access
444                        mode, 
445                        lba,
446                        (unsigned int) buffer,
447                        count );
448}
449
450///////////////////////////////////////////////////////////////////////////////
451//     _ioc_get_status()
[279]452// This function returns in the status variable, the transfert status, and
453// acknowledge the IRQ if the IOC controler is not busy.
454// Returns 0 if success, > 0 if error
[258]455///////////////////////////////////////////////////////////////////////////////
[279]456unsigned int _ioc_get_status( unsigned int  channel,
457                              unsigned int* status )
[258]458{
[279]459    if ( channel != 0 )
460    {
461        _tty_get_lock( 0 );
462        _puts("\n[GIET ERROR] in _ioc_get_status : illegal channel\n");
463        _tty_release_lock( 0 );
464
465        return 1;
466    }
467
[258]468    // get IOC base address
[279]469    volatile unsigned int * ioc_address = (unsigned int *) &seg_ioc_base;
470    *status = ioc_address[BLOCK_DEVICE_STATUS];
[258]471
[279]472    return 0;
[258]473}
474
475///////////////////////////////////////////////////////////////////////////////
476//     _ioc_get_block_size()
477// This function returns the block_size with which the IOC has been configured.
478///////////////////////////////////////////////////////////////////////////////
479unsigned int _ioc_get_block_size() 
480{
481    // get IOC base address
[279]482    volatile unsigned int * ioc_address = (unsigned int *) &seg_ioc_base;
[258]483   
484    return  ioc_address[BLOCK_DEVICE_BLOCK_SIZE];
485}
486
487
488// Local Variables:
489// tab-width: 4
490// c-basic-offset: 4
491// c-file-offsets:((innamespace . 0)(inline-open . 0))
492// indent-tabs-mode: nil
493// End:
494// vim: filetype=c:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
495
Note: See TracBrowser for help on using the repository browser.