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

Last change on this file since 292 was 289, checked in by cfuguet, 11 years ago

Modifications on GIET-VM IOC driver:

  • Introducing new layer on the IOC driver. Every call to ioc_read, ioc_write, ioc_get_block_size or ioc_init

functions will call the specific driver of the used IOC
controller. Supported IOC controllers are (for now) :

  1. BDV (Soclib Block Device)
  2. HBA
  3. SPI (SDCARD - SPI controller)
  • All functions of IOC controllers drivers respect the same interface.
  • To specify the used IOC controller of the platform, a subtype field has been introduced on the map.xml file. This subtype field must be declared on the IOC periph instantiation. Available subtypes (for now) : BDV, HBA or SPI.
File size: 14.4 KB
Line 
1///////////////////////////////////////////////////////////////////////////////////
2// File       : ioc_driver.c
3// Date       : 23/05/2013
4// Author     : alain greiner
5// Maintainer : cesar fuguet
6// Copyright (c) UPMC-LIP6
7///////////////////////////////////////////////////////////////////////////////////
8// The ioc_driver.c and ioc_driver.h files are part ot the GIET-VM kernel.
9// This driver supports the SocLib vci_block_device component, that is
10// a single channel, block oriented, external storage contrÃŽler.
11//
12// It can exist only one block-device controler in the architecture.
13//
14// The _ioc_read() and _ioc_write() functions use the _ioc_access() function,
15// that is always blocking. The _ioc_access function will call the read or
16// write function in the driver of the choosen IOC peripheral, which can be for
17// now: BDV, HBA and SPI. This function can be called in 4 modes:
18//
19// - In BOOT_PA mode, the _ioc_access() function use the buffer virtual address
20//   as a physical address (as the page tables are not build). This mode is
21//   used by the boot code to load the map.bin file into memory.
22//
23// - In BOOT_VA mode, the _ioc_access() function makes a V2P translation to
24//   compute the buffer physical address. This mode is used by the boot code to
25//   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. There is no checking of user access
29//   right to the memory buffer.  This mode must be used to access IOC, for an
30//   "open" system call.
31//
32// - In USER mode, the _ioc_access() function makes a V2P translation to
33//   compute the buffer physical address. The user access right to the memory
34//   buffer must be checked.  This mode must be used to access IOC, for a
35//   "read/write" system call.
36//
37// The IOMMU can be activated or not:
38//
39// 1) When the IOMMU is used, a fixed size 2Mbytes vseg is allocated to
40// the IOC peripheral, in the I/O virtual space, and the user buffer is
41// dynamically remapped in the IOMMU page table. The corresponding entry
42// in the IOMMU PT1 is defined by the kernel _ioc_iommu_ix1 variable.
43// The number of pages to be unmapped is stored in the _ioc_npages variable.
44// The number of PT2 entries is dynamically computed and stored in the
45// kernel _ioc_iommu_npages variable. It cannot be larger than 512.
46// The user buffer is unmapped by the _ioc_completed() function when
47// the transfer is completed.
48//
49// 2/ If the IOMMU is not used, we check that  the user buffer is mapped to a
50// contiguous physical buffer (this is generally true because the user space
51// page tables are statically constructed to use contiguous physical memory).
52//
53// Finally, the memory buffer must fulfill the following conditions:
54// - The buffer must be word aligned,
55// - The buffer must be mapped in user space for an user access,
56// - The buffer must be writable in case of (to_mem) access,
57// - The total number of physical pages occupied by the user buffer cannot
58//   be larger than 512 pages if the IOMMU is activated,
59// - All physical pages occupied by the user buffer must be contiguous
60//   if the IOMMU is not activated.
61// An error code is returned if these conditions are not verified.
62///////////////////////////////////////////////////////////////////////////////////
63// The seg_ioc_base virtual base addresses must be defined in giet_vsegs.ld file.
64///////////////////////////////////////////////////////////////////////////////////
65
66#include <giet_config.h>
67#include <ioc_driver.h>
68#include <utils.h>
69#include <tty_driver.h>
70#include <iob_driver.h>
71#include <ctx_handler.h>
72#include <mmc_driver.h>
73#include <vmem.h>
74
75#if !defined( USE_IOB )
76# error: You must define USE_IOB in the hard_config.h file
77#endif
78
79#if !defined(GIET_USE_IOMMU)
80# error: You must define GIET_USE_IOMMU in the giet_config.h file
81#endif
82
83#if (USE_BDV + USE_SPI + USE_HBA) != 1
84# error: You must use only one IOC controller (BDV or SPI or HBA)
85#endif
86
87#if USE_BDV
88# include <bdv_driver.h>
89#endif
90
91#if USE_SPI
92# include <sdc_driver.h>
93#endif
94
95#if USE_HBA
96# include <hba_driver.h>
97#endif
98
99
100#define in_unckdata __attribute__((section (".unckdata")))
101
102///////////////////// IOC global variables
103
104in_unckdata unsigned int _ioc_lock = 0;
105in_unckdata unsigned int _ioc_status = 0;
106in_unckdata volatile unsigned int _ioc_gtid;
107in_unckdata volatile unsigned int _ioc_iommu_ix1 = 0;
108in_unckdata volatile unsigned int _ioc_iommu_npages; 
109
110///////////////////////////////////////////////////////////////////////////////
111//      _ioc_access()
112// This function transfer data between a memory buffer and the block device.
113// The buffer lentgth is (count*block_size) bytes.
114// Arguments are:
115// - to_mem     : from external storage to memory when non 0.
116// - kernel     : kernel buffer with identity mapping when non 0.
117// - lba        : first block index on the external storage.
118// - buf_vaddr  : virtual base address of the memory buffer.
119// - count      : number of blocks to be transfered.
120// Returns 0 if success, > 0 if error.
121///////////////////////////////////////////////////////////////////////////////
122static unsigned int _ioc_access( unsigned int to_mem,
123                                 unsigned int mode,
124                                 unsigned int lba,
125                                 unsigned int buf_vaddr,
126                                 unsigned int count) 
127{
128
129#if GIET_DEBUG_IOC_DRIVER
130_tty_get_lock( 0 );
131_puts("\n[IOC DEBUG] Enter _ioc_access() at cycle ");
132_putd( _get_proctime() );
133_puts(" for processor ");
134_putd( _get_procid() );
135_puts("\n - mode    = ");
136_putd( mode );
137_puts("\n - vaddr   = ");
138_putx( buf_vaddr );
139_puts("\n - sectors = ");
140_putd( count );
141_puts("\n - lba     = ");
142_putx( lba );
143_puts("\n");
144_tty_release_lock( 0 );
145#endif
146
147    unsigned int error;            // return value
148    unsigned int pt_vbase;         // page table vbase address
149    unsigned int vpn_min;          // first virtuel page index covering buffer
150    unsigned int vpn_max;          // last virtual page index covering buffer
151    unsigned int vpn;              // current virtual page index
152    unsigned int ppn;              // physical page number
153    unsigned int flags;            // page protection flags
154    unsigned int ix2;              // page index in IOMMU PT1 page table
155    unsigned int ppn_first;        // first physical page number for user buffer
156    unsigned int buf_xaddr = 0;    // user buffer virtual address in IO space (if IOMMU)
157    paddr_t      buf_paddr = 0;    // user buffer physical address (if no IOMMU),
158
159    // check buffer alignment
160    if ((unsigned int) buf_vaddr & 0x3)
161    {
162        _tty_get_lock( 0 );
163        _puts("\n[GIET ERROR] in _ioc_access() : buffer not word aligned\n");
164        _tty_release_lock( 0 );
165        return 1; 
166    }
167
168    unsigned int length = count << 9;  // count * 512 bytes
169
170    // computing target buffer physical address
171    if ( mode == IOC_BOOT_PA_MODE )                // identity mapping
172    {
173        buf_paddr = (paddr_t)buf_vaddr;
174    }
175    else                                           // V2P translation
176    {
177        // get page table virtual address
178        pt_vbase = _get_context_slot(CTX_PTAB_ID);
179        vpn_min = buf_vaddr >> 12;
180        vpn_max = (buf_vaddr + length - 1) >> 12;
181
182        // loop on all virtual pages covering the user buffer
183        for (vpn = vpn_min, ix2 = 0 ; 
184             vpn <= vpn_max ; 
185             vpn++, ix2++ ) 
186        {
187            // get ppn and flags for each vpn
188            unsigned int ko = _v2p_translate( (page_table_t*)pt_vbase,
189                                              vpn,
190                                              &ppn,
191                                              &flags);
192            // check access rights
193            if ( ko )
194            {
195                _tty_get_lock( 0 );
196                _puts("\n[GIET ERROR] in _ioc_access() : buffer unmapped\n");
197                _tty_release_lock( 0 );
198                return 1; 
199            }
200
201            if ( (mode == IOC_USER_MODE) && ((flags & PTE_U) == 0) )
202            {
203                _tty_get_lock( 0 );
204                _puts("\n[GIET ERROR] in _ioc_access() : buffer not user accessible\n");
205                _tty_release_lock( 0 );
206                return 1; 
207            }
208
209            if ( ((flags & PTE_W) == 0 ) && to_mem )
210            {
211                _tty_get_lock( 0 );
212                _puts("\n[GIET ERROR] in _ioc_access() : buffer not writable\n");
213                _tty_release_lock( 0 );
214                return 1; 
215            }
216
217            // save first ppn value
218            if (ix2 == 0) ppn_first = ppn;
219
220#if GIET_USE_IOMMU
221 
222            // check buffer length < 2 Mbytes
223            if (ix2 > 511) // check buffer length < 2 Mbytes
224            {
225                _tty_get_lock( 0 );
226                _puts("\n[GIET ERROR] in _ioc_access() : user buffer > 2 Mbytes\n");
227                _tty_release_lock( 0 );
228                return 1; 
229            }
230            // map the physical page in IOMMU page table
231            _iommu_add_pte2( _ioc_iommu_ix1,    // PT1 index
232                             ix2,               // PT2 index
233                             ppn,               // Physical page number   
234                             flags );           // Protection flags
235
236            // compute user buffer virtual adress in IO space
237            buf_xaddr = (_ioc_iommu_ix1) << 21 | (buf_vaddr & 0xFFF);
238
239#else
240
241            // check that physical pages are contiguous
242            if ((ppn - ppn_first) != ix2) 
243            {
244                _tty_get_lock( 0 );
245                _puts("[GIET ERROR] in _ioc_access() : split physical buffer\n");
246                _tty_release_lock( 0 );
247                return 1; 
248            }
249
250            // compute user buffer physical adress
251            buf_paddr = (((paddr_t)ppn_first) << 12) | (buf_vaddr & 0xFFF);
252#endif           
253
254        } // end for vpn
255    }
256
257#if GIET_USE_IOMMU
258
259    // register the number of pages to be unmapped in IOMMU
260    _ioc_iommu_npages = (vpn_max - vpn_min) + 1;
261
262#endif
263
264    if ( to_mem ) // memory write : invalidate data caches
265    {
266        // L1 cache
267        if ( GIET_NO_HARD_CC ) _dcache_buf_invalidate((void *) buf_vaddr, length);
268
269        // L2 cache (only if IOB used)
270        if ( USE_IOB ) _memc_inval( buf_paddr, length );
271    }
272    else         // memory read : update data caches
273    {
274        // L1 cache : nothing to do if L1 write-through
275
276        // L2 cache (only if IOB used)
277        if ( USE_IOB ) _memc_sync( buf_paddr, length );
278    }
279
280    if ( GIET_USE_IOMMU ) buf_paddr = (paddr_t) buf_xaddr;
281
282#if   USE_BDV
283    if (to_mem) error = _bdv_read (mode, lba, buf_paddr, count);
284    else        error = _bdv_write(mode, lba, buf_paddr, count);
285#elif USE_SPI
286    if (to_mem) error = _sdc_read (mode, lba, buf_paddr, count);
287    else        error = _sdc_write(mode, lba, buf_paddr, count);
288#elif USE_HBA
289    if (to_mem) error = _hba_read (mode, lba, buf_paddr, count);
290    else        error = _hba_write(mode, lba, buf_paddr, count);
291#endif
292
293    return error;
294} // end _ioc_access()
295
296///////////////////////////////////////////////////////////////////////////////
297//       _ioc_init()
298// This function cheks block size, and activates the IOC interrupts.
299// Return 0 for success.
300///////////////////////////////////////////////////////////////////////////////
301unsigned int _ioc_init( unsigned int channel )
302{
303#if   USE_BDV
304    return _bdv_init( channel );
305#elif USE_SPI
306    return _sdc_init( channel );
307#elif USE_HBA
308    return _hba_init( channel );
309#endif
310}
311
312///////////////////////////////////////////////////////////////////////////////
313//     _ioc_read()
314// Transfer data from the block device to a memory buffer.
315// - mode     : BOOT / KERNEL / USER
316// - lba      : first block index on the block device
317// - buffer   : base address of the memory buffer (must be word aligned)
318// - count    : number of blocks to be transfered.
319// Returns 0 if success, > 0 if error.
320///////////////////////////////////////////////////////////////////////////////
321unsigned int _ioc_read( unsigned int mode, 
322                        unsigned int lba, 
323                        void*        buffer, 
324                        unsigned int count) 
325{
326    return _ioc_access( 1,        // read access
327                        mode, 
328                        lba,
329                        (unsigned int) buffer,
330                        count );
331}
332
333///////////////////////////////////////////////////////////////////////////////
334//     _ioc_write()
335// Transfer data from a memory buffer to the block device.
336// - mode     : BOOT / KERNEL / USER
337// - lba      : first block index on the block device
338// - buffer   : base address of the memory buffer (must be word aligned)
339// - count    : number of blocks to be transfered.
340// Returns 0 if success, > 0 if error.
341///////////////////////////////////////////////////////////////////////////////
342unsigned int _ioc_write( unsigned int mode, 
343                         unsigned int lba, 
344                         const void*  buffer, 
345                         unsigned int count ) 
346{
347    return _ioc_access( 0,        // write access
348                        mode, 
349                        lba,
350                        (unsigned int) buffer,
351                        count );
352}
353
354///////////////////////////////////////////////////////////////////////////////
355//     _ioc_get_status()
356// This function returns in the status variable, the transfert status, and
357// acknowledge the IRQ if the IOC controler is not busy.
358// Returns 0 if success, > 0 if error
359///////////////////////////////////////////////////////////////////////////////
360unsigned int _ioc_get_status( unsigned int  channel,
361                              unsigned int* status )
362{
363#if   USE_BDV
364    return _bdv_get_status(channel, status);
365#elif USE_SPI
366    return _sdc_get_status(channel, status);
367#elif USE_HBA
368    return _hba_get_status(channel, status);
369#endif
370}
371
372///////////////////////////////////////////////////////////////////////////////
373//     _ioc_get_block_size()
374// This function returns the block_size with which the IOC has been configured.
375///////////////////////////////////////////////////////////////////////////////
376unsigned int _ioc_get_block_size() 
377{
378#if   USE_BDV
379    return _bdv_get_block_size();
380#elif USE_SPI
381    return _sdc_get_block_size();
382#elif USE_HBA
383    return _hba_get_block_size();
384#endif
385}
386
387
388// Local Variables:
389// tab-width: 4
390// c-basic-offset: 4
391// c-file-offsets:((innamespace . 0)(inline-open . 0))
392// indent-tabs-mode: nil
393// End:
394// vim: filetype=c:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
395
Note: See TracBrowser for help on using the repository browser.