source: branch/giet_vm_ioc_drivers/giet_drivers/ioc_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: 14.8 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 _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#if (USE_BDV + USE_SPI + USE_HBA) != 1
90# error: You must use only one IOC controller (BDV or SPI or HBA)
91#endif
92
93#if USE_BDV
94# include <bdv_driver.h>
95#endif
96
97#if USE_SPI
98# include <sdc_driver.h>
99#endif
100
101#if USE_HBA
102# include <hba_driver.h>
103#endif
104
105
106#define in_unckdata __attribute__((section (".unckdata")))
107
108///////////////////// IOC global variables
109
110in_unckdata unsigned int _ioc_lock = 0;
111in_unckdata unsigned int _ioc_status = 0;
112in_unckdata volatile unsigned int _ioc_gtid;
113in_unckdata volatile unsigned int _ioc_iommu_ix1 = 0;
114in_unckdata volatile unsigned int _ioc_iommu_npages; 
115
116///////////////////////////////////////////////////////////////////////////////
117//      _ioc_access()
118// This function transfer data between a memory buffer and the block device.
119// The buffer lentgth is (count*block_size) bytes.
120// Arguments are:
121// - to_mem     : from external storage to memory when non 0.
122// - kernel     : kernel buffer with identity mapping when non 0.
123// - lba        : first block index on the external storage.
124// - buf_vaddr  : virtual base address of the memory buffer.
125// - count      : number of blocks to be transfered.
126// Returns 0 if success, > 0 if error.
127///////////////////////////////////////////////////////////////////////////////
128static unsigned int _ioc_access( unsigned int to_mem,
129                                 unsigned int mode,
130                                 unsigned int lba,
131                                 unsigned int buf_vaddr,
132                                 unsigned int count) 
133{
134
135#if GIET_DEBUG_IOC_DRIVER
136_tty_get_lock( 0 );
137_puts("\n[IOC DEBUG] Enter _ioc_access() at cycle ");
138_putd( _get_proctime() );
139_puts(" for processor ");
140_putd( _get_procid() );
141_puts("\n - mode    = ");
142_putd( mode );
143_puts("\n - vaddr   = ");
144_putx( buf_vaddr );
145_puts("\n - sectors = ");
146_putd( count );
147_puts("\n - lba     = ");
148_putx( lba );
149_puts("\n");
150_tty_release_lock( 0 );
151#endif
152
153    unsigned int error;            // return value
154    unsigned int pt_vbase;         // page table vbase address
155    unsigned int vpn_min;          // first virtuel page index covering buffer
156    unsigned int vpn_max;          // last virtual page index covering buffer
157    unsigned int vpn;              // current virtual page index
158    unsigned int ppn;              // physical page number
159    unsigned int flags;            // page protection flags
160    unsigned int ix2;              // page index in IOMMU PT1 page table
161    unsigned int ppn_first;        // first physical page number for user buffer
162    unsigned int buf_xaddr = 0;    // user buffer virtual address in IO space (if IOMMU)
163    paddr_t      buf_paddr = 0;    // user buffer physical address (if no IOMMU),
164
165    // check buffer alignment
166    if ((unsigned int) buf_vaddr & 0x3)
167    {
168        _tty_get_lock( 0 );
169        _puts("\n[GIET ERROR] in _ioc_access() : buffer not word aligned\n");
170        _tty_release_lock( 0 );
171        return 1; 
172    }
173
174    unsigned int length = count << 9;  // count * 512 bytes
175
176    // computing target buffer physical address
177    if ( mode == IOC_BOOT_PA_MODE )                // identity mapping
178    {
179        buf_paddr = (paddr_t)buf_vaddr;
180    }
181    else                                           // V2P translation
182    {
183        // get page table virtual address
184        pt_vbase = _get_context_slot(CTX_PTAB_ID);
185        vpn_min = buf_vaddr >> 12;
186        vpn_max = (buf_vaddr + length - 1) >> 12;
187
188        // loop on all virtual pages covering the user buffer
189        for (vpn = vpn_min, ix2 = 0 ; 
190             vpn <= vpn_max ; 
191             vpn++, ix2++ ) 
192        {
193            // get ppn and flags for each vpn
194            unsigned int ko = _v2p_translate( (page_table_t*)pt_vbase,
195                                              vpn,
196                                              &ppn,
197                                              &flags);
198            // check access rights
199            if ( ko )
200            {
201                _tty_get_lock( 0 );
202                _puts("\n[GIET ERROR] in _ioc_access() : buffer unmapped\n");
203                _tty_release_lock( 0 );
204                return 1; 
205            }
206
207            if ( (mode == IOC_USER_MODE) && ((flags & PTE_U) == 0) )
208            {
209                _tty_get_lock( 0 );
210                _puts("\n[GIET ERROR] in _ioc_access() : buffer not user accessible\n");
211                _tty_release_lock( 0 );
212                return 1; 
213            }
214
215            if ( ((flags & PTE_W) == 0 ) && to_mem )
216            {
217                _tty_get_lock( 0 );
218                _puts("\n[GIET ERROR] in _ioc_access() : buffer not writable\n");
219                _tty_release_lock( 0 );
220                return 1; 
221            }
222
223            // save first ppn value
224            if (ix2 == 0) ppn_first = ppn;
225
226#if GIET_USE_IOMMU
227 
228            // check buffer length < 2 Mbytes
229            if (ix2 > 511) // check buffer length < 2 Mbytes
230            {
231                _tty_get_lock( 0 );
232                _puts("\n[GIET ERROR] in _ioc_access() : user buffer > 2 Mbytes\n");
233                _tty_release_lock( 0 );
234                return 1; 
235            }
236            // map the physical page in IOMMU page table
237            _iommu_add_pte2( _ioc_iommu_ix1,    // PT1 index
238                             ix2,               // PT2 index
239                             ppn,               // Physical page number   
240                             flags );           // Protection flags
241
242            // compute user buffer virtual adress in IO space
243            buf_xaddr = (_ioc_iommu_ix1) << 21 | (buf_vaddr & 0xFFF);
244
245#else
246
247            // check that physical pages are contiguous
248            if ((ppn - ppn_first) != ix2) 
249            {
250                _tty_get_lock( 0 );
251                _puts("[GIET ERROR] in _ioc_access() : split physical buffer\n");
252                _tty_release_lock( 0 );
253                return 1; 
254            }
255
256            // compute user buffer physical adress
257            buf_paddr = (((paddr_t)ppn_first) << 12) | (buf_vaddr & 0xFFF);
258#endif           
259
260        } // end for vpn
261    }
262
263#if GIET_USE_IOMMU
264
265    // register the number of pages to be unmapped in IOMMU
266    _ioc_iommu_npages = (vpn_max - vpn_min) + 1;
267
268#endif
269
270    if ( to_mem ) // memory write : invalidate data caches
271    {
272        // L1 cache
273        if ( GIET_NO_HARD_CC ) _dcache_buf_invalidate((void *) buf_vaddr, length);
274
275        // L2 cache (only if IOB used)
276        if ( USE_IOB ) _memc_inval( buf_paddr, length );
277    }
278    else         // memory read : update data caches
279    {
280        // L1 cache : nothing to do if L1 write-through
281
282        // L2 cache (only if IOB used)
283        if ( USE_IOB ) _memc_sync( buf_paddr, length );
284    }
285
286    if ( GIET_USE_IOMMU ) buf_paddr = (paddr_t) buf_xaddr;
287
288#if   USE_BDV
289    if (to_mem) error = _bdv_read (mode, lba, buf_paddr, count);
290    else        error = _bdv_write(mode, lba, buf_paddr, count);
291#elif USE_SPI
292    if (to_mem) error = _sdc_read (mode, lba, buf_paddr, count);
293    else        error = _sdc_write(mode, lba, buf_paddr, count);
294#elif USE_HBA
295    if (to_mem) error = _hba_read (mode, lba, buf_paddr, count);
296    else        error = _hba_write(mode, lba, buf_paddr, count);
297#endif
298
299    return error;
300} // end _ioc_access()
301
302///////////////////////////////////////////////////////////////////////////////
303//       _ioc_init()
304// This function cheks block size, and activates the IOC interrupts.
305// Return 0 for success.
306///////////////////////////////////////////////////////////////////////////////
307unsigned int _ioc_init( unsigned int channel )
308{
309#if   USE_BDV
310    return _bdv_init( channel );
311#elif USE_SPI
312    return _sdc_init( channel );
313#elif USE_HBA
314    return _hba_init( channel );
315#endif
316}
317
318///////////////////////////////////////////////////////////////////////////////
319//     _ioc_read()
320// Transfer data from the block device to a memory buffer.
321// - mode     : BOOT / KERNEL / USER
322// - lba      : first block index on the block device
323// - buffer   : base address of the memory buffer (must be word aligned)
324// - count    : number of blocks to be transfered.
325// Returns 0 if success, > 0 if error.
326///////////////////////////////////////////////////////////////////////////////
327unsigned int _ioc_read( unsigned int mode, 
328                        unsigned int lba, 
329                        void*        buffer, 
330                        unsigned int count) 
331{
332    return _ioc_access( 1,        // read access
333                        mode, 
334                        lba,
335                        (unsigned int) buffer,
336                        count );
337}
338
339///////////////////////////////////////////////////////////////////////////////
340//     _ioc_write()
341// Transfer data from a memory buffer to the block device.
342// - mode     : BOOT / KERNEL / USER
343// - lba      : first block index on the block device
344// - buffer   : base address of the memory buffer (must be word aligned)
345// - count    : number of blocks to be transfered.
346// Returns 0 if success, > 0 if error.
347///////////////////////////////////////////////////////////////////////////////
348unsigned int _ioc_write( unsigned int mode, 
349                         unsigned int lba, 
350                         const void*  buffer, 
351                         unsigned int count ) 
352{
353    return _ioc_access( 0,        // write access
354                        mode, 
355                        lba,
356                        (unsigned int) buffer,
357                        count );
358}
359
360///////////////////////////////////////////////////////////////////////////////
361//     _ioc_get_status()
362// This function returns in the status variable, the transfert status, and
363// acknowledge the IRQ if the IOC controler is not busy.
364// Returns 0 if success, > 0 if error
365///////////////////////////////////////////////////////////////////////////////
366unsigned int _ioc_get_status( unsigned int  channel,
367                              unsigned int* status )
368{
369#if   USE_BDV
370    return _bdv_get_status(channel, status);
371#elif USE_SPI
372    return _sdc_get_status(channel, status);
373#elif USE_HBA
374    return _hba_get_status(channel, status);
375#endif
376}
377
378///////////////////////////////////////////////////////////////////////////////
379//     _ioc_get_block_size()
380// This function returns the block_size with which the IOC has been configured.
381///////////////////////////////////////////////////////////////////////////////
382unsigned int _ioc_get_block_size() 
383{
384#if   USE_BDV
385    return _bdv_get_block_size();
386#elif USE_SPI
387    return _sdc_get_block_size();
388#elif USE_HBA
389    return _hba_get_block_size();
390#endif
391}
392
393
394// Local Variables:
395// tab-width: 4
396// c-basic-offset: 4
397// c-file-offsets:((innamespace . 0)(inline-open . 0))
398// indent-tabs-mode: nil
399// End:
400// vim: filetype=c:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
401
Note: See TracBrowser for help on using the repository browser.