source: soft/giet_vm/giet_drivers/hba_driver.c @ 271

Last change on this file since 271 was 258, checked in by alain, 11 years ago

This is a major release, including a deep restructuration of code.
The main evolutions are

  • use of the Tsar preloader to load the GIET boot-loader from disk
  • introduction of a FAT32 file system library,
  • use of this fat32 library by the boot-loader to load the map.bin data structure, and the various .elf files
  • reorganisation of drivers (one file per peripheral).
  • introduction of drivers for new peripherals: vci_chbuf_dma and vci_multi_ahci.
  • introduction of a new physical memory allocator in the boot code.

This release has been tested on the tsar_generic_iob architecture,
for the two following mappings: 4c_1p_iob_four.xml and 4c_1p_iob_sort.xml

File size: 18.5 KB
Line 
1///////////////////////////////////////////////////////////////////////////////////
2// File     : hba_driver.c
3// Date     : 23/11/2013
4// Author   : alain greiner and zhang
5// Copyright (c) UPMC-LIP6
6///////////////////////////////////////////////////////////////////////////////////
7// The hba_driver.c and hba_driver.h files are part ot the GIET-VM kernel.
8// This driver supports the SocLib VciMultiAhci component, that is a multi-channels,
9// block oriented, external storage contrÃŽler, respecting the AHCI standard.
10//
11// It can exist only one ahci-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( NB_HBA_CHANNELS )
82# error: You must define NB_HBA_CHANNELS in the hard_config.h file
83#endif
84
85#if ( NB_HBA_CHANNELS > 8 )
86# error: NB_HBA_CHANNELS cannot be larger than 8
87#endif
88
89#if !defined( USE_IOB )
90# error: You must define USE_IOB in the hard_config.h file
91#endif
92
93#if !defined(GIET_USE_IOMMU)
94# error: You must define GIET_USE_IOMMU in the giet_config.h file
95#endif
96
97#define in_unckdata __attribute__((section (".unckdata")))
98
99//////////////////////////////////////////////////////////////////
100//  Global variables
101//////////////////////////////////////////////////////////////////
102
103// command list array (one per channel)
104hba_cmd_list_t   hba_cmd_list[NB_HBA_CHANNELS] __attribute__((aligned(0x1000)));   
105
106// command tables array (32 command tables per channel)
107hba_cmd_table_t  hba_cmd_table[NB_HBA_CHANNELS][32] __attribute__((aligned(0x1000))); 
108
109// command list physical addresses array (one per channel)
110paddr_t          hba_cmd_list_paddr[NB_HBA_CHANNELS];
111
112// command tables physical addresses array (32 command tables per channel)
113paddr_t          hba_cmd_table_paddr[NB_HBA_CHANNELS][32];
114
115// command list pointer array (one per channel)
116unsigned int     hba_cmd_slot[NB_HBA_CHANNELS];
117
118//////////////////////////////////////////////////////////////////
119// This function returns the status of a given channel.
120// return 0 if success, >0 if error
121//////////////////////////////////////////////////////////////////
122unsigned int _hba_get_status( unsigned int   channel, 
123                              unsigned int*  status )
124{
125    volatile unsigned int* hba_address;
126    hba_address = (unsigned int*)(&seg_hba_base) + (HBA_SPAN*channel);
127
128    if( channel >= NB_HBA_CHANNELS )
129    {
130        _get_lock(&_tty_put_lock);
131        _puts("\n[GIET ERROR] in _hba_get_status() : illegal channel\n");
132        _release_lock(&_tty_put_lock);
133        return 1;
134    }
135    else
136    {
137        *status = hba_address[HBA_PXIS];
138        return 0;
139    }
140}
141//////////////////////////////////////////////////////////////////
142// This function reset the status resgister for a given channel.
143// return 0 if success, >0 if error
144//////////////////////////////////////////////////////////////////
145unsigned int _hba_reset_status( unsigned int channel )
146{
147    volatile unsigned int* hba_address;
148    hba_address = (unsigned int*)(&seg_hba_base) + (HBA_SPAN*channel);
149
150    if( channel >= NB_HBA_CHANNELS )
151    {   
152        _get_lock(&_tty_put_lock);
153        _puts("\n[GIET ERROR] in _hba_reset_status() : illegal channel\n");
154        _release_lock(&_tty_put_lock);
155        return 1;
156    }
157    else
158    {
159        hba_address[HBA_PXIS] = 0;
160        return 0;
161    }
162}
163///////////////////////////////////////////////////////////////////////////////
164// This function register a command in both the command list
165// and the command table, and updates the HBA_PXCI register.
166// It uses the AHCI Scatter/Gather mechanisme to split the user
167// buffer in several physical buffers, with the constraint that each physical
168// buffer must be an integer number of blocks entirely contained in a single
169// page frame.
170// return 0 if success, > 0 if error
171///////////////////////////////////////////////////////////////////////////////
172unsigned int _hba_cmd_set( unsigned int  is_read,     // to memory
173                           unsigned int  lba,         // logic block address
174                           unsigned int  buf_vaddr,   // buffer virtual address
175                           unsigned int  count )      // number of blocks
176{
177    volatile unsigned int *hba_address;
178
179    unsigned int       block_size;     // defined by the block device (bytes)
180    unsigned int       channel_id;     // channel index
181    unsigned int       pxci;           // command list status
182    unsigned int       cmd_id;         // command index in command list
183    unsigned int       buf_id;         // for physical buffers covering user buffer
184    unsigned int       user_pt_vbase;  // user page table virtual base address
185    unsigned int       vpn;            // for all pages covering the userbuffer
186    unsigned int       vpn_min;        // first virtual page index for user buffer
187    unsigned int       vpn_max;        // last  virtual page index for user buffer
188    unsigned int       offset;         // unaligned bytes in page frame: buf_vaddr & 0xFFF
189    unsigned int       offset_last;    // unaligned bytes in last frame
190    hba_cmd_desc_t*    cmd_desc;       // command descriptor pointer   
191    hba_cmd_table_t*   cmd_table;      // command table pointer
192
193    // TODO The block size must be obtained from the hardware...
194    block_size = 512;
195
196    // check buffer alignment
197    if( buf_vaddr & (block_size-1) )
198    {
199        _get_lock(&_tty_put_lock);
200        _puts("\n[GIET ERROR] in _hba_set_cmd() : user buffer not block aligned\n");
201        _release_lock(&_tty_put_lock);
202        return 1;
203    }
204
205    // get channel index
206    channel_id = _get_context_slot(CTX_HBA_ID);
207    if ( channel_id == 0xFFFFFFFF )
208    {
209        _get_lock(&_tty_put_lock);
210        _puts("\n[GIET ERROR] in _hba_set_cmd() : no HBA channel allocated\n");
211        _release_lock(&_tty_put_lock);
212        return 1;
213    }
214
215    // get hba device address
216    hba_address = (unsigned int*)(&seg_hba_base) + (HBA_SPAN * channel_id);
217
218    // get command list status
219    pxci = hba_address[HBA_PXCI];
220
221    // get command index and return error if command list full
222    cmd_id = hba_cmd_slot[channel_id];
223    if( pxci & (1<<cmd_id ) ) 
224    {
225        _get_lock(&_tty_put_lock);
226        _puts("\n[GIET ERROR] in _hba_set_cmd() : command list full in channel \n");
227        _putd( channel_id );
228        _puts("\n");
229        _release_lock(&_tty_put_lock);
230        return 1;
231    }
232
233    // compute pointers on command descriptor and command table   
234    cmd_desc  = (hba_cmd_desc_t*)(&(hba_cmd_list[channel_id].desc[cmd_id]));
235    cmd_table = (hba_cmd_table_t*)(&(hba_cmd_table[channel_id][cmd_id]));
236
237    // get user space page table virtual address
238    user_pt_vbase     = _get_context_slot(CTX_PTAB_ID);
239    vpn_min           = buf_vaddr >> 12;
240    vpn_max           = (buf_vaddr + (block_size*count) - 1) >> 12;
241    offset            = buf_vaddr & 0xFFF;
242    offset_last       = (buf_vaddr + (block_size*count) - 1) & 0xFFF;
243
244    // initialize all buffer descriptors in command table
245    // (loop on all virtual pages covering the user buffer)
246    for( vpn = vpn_min, buf_id = 0 ; vpn <= vpn_max ; vpn++ )
247    {
248        paddr_t      paddr;
249        unsigned int count;
250        unsigned int ppn;
251        unsigned int flags;
252        unsigned int ko;
253        unsigned int buf_id = 0;
254
255        // get ppn and flags
256        ko = _v2p_translate( (page_table_t*)user_pt_vbase,
257                              vpn,
258                              &ppn,
259                              &flags );
260
261        // check access rights
262        if ( ko )
263        {
264            _get_lock(&_tty_put_lock);
265            _puts("[GIET ERROR] in _hba_set_cmd() : user buffer unmapped\n");
266            _release_lock(&_tty_put_lock);
267            return 1;
268        }
269        if ((flags & PTE_U) == 0)
270        {
271            _get_lock(&_tty_put_lock);
272            _puts("[GIET ERROR] in _hba_set_cmd() : user buffer not in user space\n");
273            _release_lock(&_tty_put_lock);
274            return 1;
275        }
276        if (((flags & PTE_W) == 0 ) && (is_read == 0) )
277        {
278            _get_lock(&_tty_put_lock);
279            _puts("[GIET ERROR] in _hba_set_cmd() : user buffer not writable\n");
280            _release_lock(&_tty_put_lock);
281            return 1;
282        }
283
284        // check buffer index overflow
285        if( buf_id > 245 )
286        {
287            _get_lock(&_tty_put_lock);
288            _puts("[GIET ERROR] in _hba_set_cmd() : max number of buffers is 248\n");
289            _release_lock(&_tty_put_lock);
290            return 1;
291        }
292
293        // buffer allocation
294        if( vpn == vpn_min )       // first page: one single buffer
295        {
296            paddr = (((paddr_t)ppn) << 12) + offset;
297            count = 0x1000 - offset;
298            cmd_table->entry[buf_id].dba  = (unsigned int)(paddr);
299            cmd_table->entry[buf_id].dbau = (unsigned int)(paddr >> 32);
300            cmd_table->entry[buf_id].dbc  = count;
301
302#if GIET_DEBUG_HBA_DRIVER
303_puts("\n- buf_index = ");
304_putd( buf_id );
305_puts(" / paddr = ");
306_putl( paddr );
307_puts(" / count = ");
308_putd( count );
309_puts("\n");
310#endif
311            buf_id++;
312        }
313        else if( vpn == vpn_max )  // last page: one single buffer
314        {
315            paddr = (((paddr_t)ppn) << 12);
316            count = offset_last;
317            cmd_table->entry[buf_id].dba  = (unsigned int)(paddr);
318            cmd_table->entry[buf_id].dbau = (unsigned int)(paddr >> 32);
319            cmd_table->entry[buf_id].dbc  = count;
320
321#if GIET_DEBUG_HBA_DRIVER
322_puts("\n- buf_index = ");
323_putd( buf_id );
324_puts(" / paddr = ");
325_putl( paddr );
326_puts(" / count = ");
327_putd( count );
328_puts("\n");
329#endif
330            buf_id++;
331        }
332        else if( offset )          // midle page and offset != 0: two buffers 
333        {
334            paddr = (((paddr_t)ppn) << 12);
335           
336            count = offset;
337            cmd_table->entry[buf_id].dba  = (unsigned int)(paddr);
338            cmd_table->entry[buf_id].dbau = (unsigned int)(paddr >> 32);
339            cmd_table->entry[buf_id].dbc  = count;
340
341#if GIET_DEBUG_HBA_DRIVER
342_puts("\n- buf_index = ");
343_putd( buf_id );
344_puts(" / paddr = ");
345_putl( paddr );
346_puts(" / count = ");
347_putd( count );
348_puts("\n");
349#endif
350            buf_id++;
351
352            paddr = (((paddr_t)ppn) << 12) + offset;
353            count = 0x1000 - offset; 
354            cmd_table->entry[buf_id].dba  = (unsigned int)(paddr);
355            cmd_table->entry[buf_id].dbau = (unsigned int)(paddr >> 32);
356            cmd_table->entry[buf_id].dbc  = count;
357
358#if GIET_DEBUG_HBA_DRIVER
359_puts("\n- buf_index = ");
360_putd( buf_id );
361_puts(" / paddr = ");
362_putl( paddr );
363_puts(" / count = ");
364_putd( count );
365_puts("\n");
366#endif
367            buf_id++;
368        }
369        else                      // middle page and offset == 0: one buffer
370        {
371            paddr = (((paddr_t)ppn) << 12);
372            count = 0x1000; 
373            cmd_table->entry[buf_id].dba  = (unsigned int)(paddr);
374            cmd_table->entry[buf_id].dbau = (unsigned int)(paddr >> 32);
375            cmd_table->entry[buf_id].dbc  = count;
376
377#if GIET_DEBUG_HBA_DRIVER
378_puts("\n- buf_index = ");
379_putd( buf_id );
380_puts(" / paddr = ");
381_putl( paddr );
382_puts(" / count = ");
383_putd( count );
384_puts("\n");
385#endif
386            buf_id++;
387        }
388    }
389
390    // initialize command table header
391    cmd_table->header.lba0 = (char)lba;
392    cmd_table->header.lba1 = (char)(lba>>8);
393    cmd_table->header.lba2 = (char)(lba>>16);
394    cmd_table->header.lba3 = (char)(lba>>24);
395
396    // initialise command descriptor
397    cmd_desc->prdtl[0] = (unsigned char)(buf_id);
398    cmd_desc->prdtl[1] = (unsigned char)(buf_id>>8);
399    cmd_desc->ctba     = (unsigned int)(hba_cmd_table_paddr[channel_id][cmd_id]);
400    cmd_desc->ctbau    = (unsigned int)(hba_cmd_table_paddr[channel_id][cmd_id]>>32);
401    if( is_read ) cmd_desc->flag[0] = 0x00;
402    else          cmd_desc->flag[0] = 0x40;     
403   
404    // update PXCI register
405    hba_address[HBA_PXCI] = (1<<cmd_id);
406
407    // update command pointer
408    hba_cmd_slot[channel_id] = (cmd_id + 1)%32;
409
410    return  0;
411} 
412///////////////////////////////////////////////////////////////////
413// Register a write command in Command List and Command Table
414// for a single buffer.
415// Returns 0 if success, > 0 if error.
416///////////////////////////////////////////////////////////////////
417unsigned int _hba_write( unsigned int  lba,
418                         void*         buffer, 
419                         unsigned int  count )
420{
421    return _hba_cmd_set( 0, lba, (unsigned int)buffer, count );
422}
423
424///////////////////////////////////////////////////////////////////
425// Register a read command in Command List and Command Table
426// for a single buffer.
427// Returns 0 if success, > 0 if error.
428///////////////////////////////////////////////////////////////////
429unsigned int _hba_read( unsigned int  lba, 
430                        void*         buffer, 
431                        unsigned int  count )
432{
433    return _hba_cmd_set( 1, lba, (unsigned int)buffer, count );
434}
435//////////////////////////////////////////////////////////////////
436// This function initializes for a given channel (k)
437// - the HBA hardware registers,
438// - the command list pointer,
439// - the command lists physical addresse,
440// - the command tables physical addresses array,
441//////////////////////////////////////////////////////////////////
442void _hba_init( unsigned int k )  // k == channel_index
443{
444    unsigned int ppn;
445    unsigned int flags;
446    unsigned int fail;
447    unsigned int vbase;
448    unsigned int c;               // c == command index
449
450    // get page_table pointer
451    unsigned int pt = _get_context_slot(CTX_PTAB_ID);
452
453    // HBA registers
454    unsigned int*  hba_address = (unsigned int*)(&seg_hba_base) + (HBA_SPAN*k);
455    hba_address = (unsigned int*)&seg_hba_base + HBA_SPAN * k;
456
457    hba_address[HBA_PXCLB]  = (unsigned int)(&hba_cmd_list[k]);
458    hba_address[HBA_PXCLBU] = 0;
459    hba_address[HBA_PXIE]   = 0x40000001;
460    hba_address[HBA_PXIS]   = 0;
461    hba_address[HBA_PXCI]   = 0;
462    hba_address[HBA_PXCMD]  = 1;
463
464    // command list pointer       
465    hba_cmd_slot[k] = 0;
466
467    // Command list physical addresse
468    vbase = (unsigned int)(&hba_cmd_list[k]);
469    fail = _v2p_translate( (page_table_t*)pt,
470                           vbase>>12,
471                           &ppn,
472                           &flags );
473    if ( fail )
474    {
475        _get_lock(&_tty_put_lock);
476        _puts("[GIET ERROR] in _hba_init() : command list unmapped\n");
477        _release_lock(&_tty_put_lock);
478        _exit();
479    }
480    hba_cmd_list_paddr[k] = ((paddr_t)ppn) | (vbase & 0xFFF);
481
482    // Command tables physical addresses
483    for( c=0 ; c<32 ; c++ )
484    {
485        vbase = (unsigned int)(&hba_cmd_table[k][c]);
486        fail = _v2p_translate( (page_table_t*)pt,
487                               vbase>>12,
488                               &ppn,
489                               &flags );
490        if ( fail )
491        {
492            _get_lock(&_tty_put_lock);
493            _puts("[GIET ERROR] in _hba_init() : command table unmapped\n");
494            _release_lock(&_tty_put_lock);
495            _exit();
496        }
497        hba_cmd_table_paddr[k][c] = ((paddr_t)ppn) | (vbase & 0xFFF);
498    }
499}
500
501
502
503// Local Variables:
504// tab-width: 4
505// c-basic-offset: 4
506// c-file-offsets:((innamespace . 0)(inline-open . 0))
507// indent-tabs-mode: nil
508// End:
509// vim: filetype=c:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
510
Note: See TracBrowser for help on using the repository browser.