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

Last change on this file since 496 was 481, checked in by alain, 9 years ago

1) The NIC, IOC, DMA and HBA drivers have been adapted to support the new _v2p_translate() function prototype (returns void).
2) The _mmc_inval() and _mmc_sync() functions does not use anymore the hard lock in the MMC, but use a soft spin_lock.
3) The NIC driver does not use anymore the GIET_NIC_BUFSIZE, GIET_NIC_NBUFS, and GIET_NIC_TIMEOUT parameters (removed from giet_config.h file).
4) The NIC driver registers map has been modified to support 64 bytes buffer descriptors for chained buffers.

File size: 12.3 KB
Line 
1///////////////////////////////////////////////////////////////////////////////////
2// File     : hba_driver.c
3// Date     : 23/11/2013
4// Author   : alain greiner
5// Copyright (c) UPMC-LIP6
6///////////////////////////////////////////////////////////////////////////////////
7// Implementation notes:
8// 1. In order to share code, the two _hba_read() and _hba_write() functions
9//    call the same _hba_set_cmd() function.
10// 2. All accesses to HBA registers are done by the two
11//    _hba_set_register() and _hba_get_register() low-level functions,
12//    that are handling virtual / physical extended addressing.
13///////////////////////////////////////////////////////////////////////////////////
14
15#include <giet_config.h>
16#include <ioc_driver.h>
17#include <utils.h>
18#include <tty0.h>
19#include <iob_driver.h>
20#include <ctx_handler.h>
21#include <mmc_driver.h>
22#include <hba_driver.h>
23#include <vmem.h>
24
25#if !defined( NB_IOC_CHANNELS )
26# error: You must define NB_IOC_CHANNELS in the hard_config.h file
27#endif
28
29#if ( NB_IOC_CHANNELS > 8 )
30# error: NB_IOC_CHANNELS cannot be larger than 8
31#endif
32
33#define in_unckdata __attribute__((section (".unckdata")))
34
35//////////////////////////////////////////////////////////////////
36//               Global variables
37//////////////////////////////////////////////////////////////////
38
39// command list array (one per channel)
40hba_cmd_list_t   hba_cmd_list[NB_IOC_CHANNELS] __attribute__((aligned(0x1000)));   
41
42// command tables array (32 command tables per channel)
43hba_cmd_table_t  hba_cmd_table[NB_IOC_CHANNELS][32] __attribute__((aligned(0x1000))); 
44
45// command list physical addresses array (one per channel)
46paddr_t          hba_cmd_list_paddr[NB_IOC_CHANNELS];
47
48// command tables physical addresses array (32 command tables per channel)
49paddr_t          hba_cmd_table_paddr[NB_IOC_CHANNELS][32];
50
51// command list pointer array (one per channel)
52unsigned int     hba_cmd_slot[NB_IOC_CHANNELS];
53
54//////////////////////////////////////////////////////////////////////////////
55// This low level function returns the value of register (channel / index)
56//////////////////////////////////////////////////////////////////////////////
57unsigned int _hba_get_register( unsigned int channel,
58                                unsigned int index )
59{
60    unsigned int* vaddr = (unsigned int*)SEG_IOC_BASE + channel*HBA_SPAN + index;
61    return _io_extended_read( vaddr );
62}
63
64//////////////////////////////////////////////////////////////////////////////
65// This low level function set a new value in register (channel / index) 
66//////////////////////////////////////////////////////////////////////////////
67void _hba_set_register( unsigned int channel,
68                        unsigned int index,
69                        unsigned int value )
70{
71    unsigned int* vaddr = (unsigned int*)SEG_IOC_BASE + channel*HBA_SPAN + index;
72    _io_extended_write( vaddr, value );
73}
74
75
76///////////////////////////////////////////////////////////////////////////////
77// This function register a command in both the command list
78// and the command table, and updates the HBA_PXCI register.
79// It uses the AHCI Scatter/Gather mechanisme to split the user
80// buffer in several physical buffers, with the constraint that each physical
81// buffer must be an integer number of blocks entirely contained in a single
82// page frame.
83// return 0 if success, -1 if error
84///////////////////////////////////////////////////////////////////////////////
85unsigned int _hba_cmd_set( unsigned int  channel,     // channel index
86                           unsigned int  is_read,     // to memory
87                           unsigned int  lba,         // logic block address
88                           paddr_t       buffer,      // buffer physical address
89                           unsigned int  count )      // number of blocks
90{
91    unsigned int       block_size;     // defined by the block device (bytes)
92    unsigned int       pxci;           // command list status
93    unsigned int       cmd_id;         // command index in command list
94
95    hba_cmd_desc_t*    cmd_desc;       // command descriptor pointer   
96    hba_cmd_table_t*   cmd_table;      // command table pointer
97
98    block_size = _hba_get_block_size();
99
100    // check buffer alignment
101    if( buffer & (block_size-1) )
102    {
103        _puts("\n[GIET ERROR] in _hba_set_cmd() : user buffer not block aligned\n");
104        return -1;
105    }
106
107    // get command list status from PXCI register
108    pxci = _hba_get_register( channel, HBA_PXCI );
109
110    // get command index and return error if command list full
111    cmd_id = hba_cmd_slot[channel];
112    if( pxci & (1<<cmd_id ) ) 
113    {
114        _puts("\n[GIET ERROR] in _hba_set_cmd() : command list full for channel ");
115        _putd( channel );
116        _puts("\n");
117        return -1;
118    }
119
120    // compute pointers on command descriptor and command table   
121    cmd_desc  = (hba_cmd_desc_t*)(&(hba_cmd_list[channel].desc[cmd_id]));
122    cmd_table = (hba_cmd_table_t*)(&(hba_cmd_table[channel][cmd_id]));
123
124    // set  buffer descriptor in command table
125    cmd_table->entry[0].dba  = (unsigned int)(buffer);
126    cmd_table->entry[0].dbau = (unsigned int)(buffer >> 32);
127    cmd_table->entry[0].dbc  = count * block_size;
128
129    // initialize command table header
130    cmd_table->header.lba0 = (char)lba;
131    cmd_table->header.lba1 = (char)(lba>>8);
132    cmd_table->header.lba2 = (char)(lba>>16);
133    cmd_table->header.lba3 = (char)(lba>>24);
134    cmd_table->header.lba4 = 0;
135    cmd_table->header.lba5 = 0;
136
137    // initialise command descriptor
138    cmd_desc->prdtl[0] = 1;
139    cmd_desc->prdtl[1] = 0;
140    cmd_desc->ctba     = (unsigned int)(hba_cmd_table_paddr[channel][cmd_id]);
141    cmd_desc->ctbau    = (unsigned int)(hba_cmd_table_paddr[channel][cmd_id]>>32);
142    if( is_read ) cmd_desc->flag[0] = 0x00;
143    else          cmd_desc->flag[0] = 0x40;     
144   
145    // update PXCI register
146    _hba_set_register( channel, HBA_PXCI, (1<<cmd_id) );
147
148    // update command pointer
149    hba_cmd_slot[channel] = (cmd_id + 1)%32;
150
151    return  0;
152} 
153
154/* This can be used for a future use with buffer in virtual space
155
156    // get user space page table virtual address
157    user_pt_vbase     = _get_context_slot(CTX_PTAB_ID);
158    vpn_min           = buf_vaddr >> 12;
159    vpn_max           = (buf_vaddr + (block_size*count) - 1) >> 12;
160    offset            = buf_vaddr & 0xFFF;
161    offset_last       = (buf_vaddr + (block_size*count) - 1) & 0xFFF;
162
163    // initialize all buffer descriptors in command table
164    // (loop on all virtual pages covering the user buffer)
165    for( vpn = vpn_min, buf_id = 0 ; vpn <= vpn_max ; vpn++ )
166    {
167        paddr_t      paddr;
168        unsigned int count;
169        unsigned int ppn;
170        unsigned int flags;
171        unsigned int ko;
172        unsigned int buf_id = 0;
173
174        // get ppn and flags
175        _v2p_translate( (page_table_t*)user_pt_vbase,
176                        vpn,
177                        &ppn,
178                        &flags );
179
180        // check access rights
181        if ((flags & PTE_U) == 0)
182        {
183            _puts("[GIET ERROR] in _hba_set_cmd() : user buffer not in user space\n");
184            return -1;
185        }
186        if (((flags & PTE_W) == 0 ) && (is_read == 0) )
187        {
188            _puts("[GIET ERROR] in _hba_set_cmd() : user buffer not writable\n");
189            return -1;
190        }
191
192        // check buffer index overflow
193        if( buf_id > 245 )
194        {
195            _puts("[GIET ERROR] in _hba_set_cmd() : max number of buffers is 248\n");
196            return -1;   
197        }
198
199        // buffer allocation
200        if( vpn == vpn_min )       // first page: one single buffer
201        {
202            paddr = (((paddr_t)ppn) << 12) + offset;
203            count = 0x1000 - offset;
204            cmd_table->entry[buf_id].dba  = (unsigned int)(paddr);
205            cmd_table->entry[buf_id].dbau = (unsigned int)(paddr >> 32);
206            cmd_table->entry[buf_id].dbc  = count;
207
208            buf_id++;
209        }
210        else if( vpn == vpn_max )  // last page: one single buffer
211        {
212            paddr = (((paddr_t)ppn) << 12);
213            count = offset_last;
214            cmd_table->entry[buf_id].dba  = (unsigned int)(paddr);
215            cmd_table->entry[buf_id].dbau = (unsigned int)(paddr >> 32);
216            cmd_table->entry[buf_id].dbc  = count;
217
218            buf_id++;
219        }
220        else if( offset )          // midle page and offset != 0: two buffers 
221        {
222            paddr = (((paddr_t)ppn) << 12);
223           
224            count = offset;
225            cmd_table->entry[buf_id].dba  = (unsigned int)(paddr);
226            cmd_table->entry[buf_id].dbau = (unsigned int)(paddr >> 32);
227            cmd_table->entry[buf_id].dbc  = count;
228
229            buf_id++;
230
231            paddr = (((paddr_t)ppn) << 12) + offset;
232            count = 0x1000 - offset;
233            cmd_table->entry[buf_id].dba  = (unsigned int)(paddr);
234            cmd_table->entry[buf_id].dbau = (unsigned int)(paddr >> 32);
235            cmd_table->entry[buf_id].dbc  = count;
236
237            buf_id++;
238        }
239        else                      // middle page and offset == 0: one buffer
240        {
241            paddr = (((paddr_t)ppn) << 12);
242            count = 0x1000;
243            cmd_table->entry[buf_id].dba  = (unsigned int)(paddr);
244            cmd_table->entry[buf_id].dbau = (unsigned int)(paddr >> 32);
245            cmd_table->entry[buf_id].dbc  = count;
246
247            buf_id++;
248        }
249    }
250*/
251
252
253//////////////////////////////////////////////
254unsigned int _hba_init( unsigned int channel )
255{
256    unsigned int ppn;
257    unsigned int flags;
258    unsigned int vbase;
259    unsigned int c;               // c == command index
260
261    // get page_table pointer
262    unsigned int pt = _get_context_slot(CTX_PTAB_ID);
263
264    // HBA registers TODO: ne faut_il pas un V2P pour PXCLB/PXCLBU ? (AG)
265    _hba_set_register( channel, HBA_PXCLB , (unsigned int)&hba_cmd_list[channel] );
266    _hba_set_register( channel, HBA_PXCLBU, 0 );
267    _hba_set_register( channel, HBA_PXIE  , 0x40000001 );
268    _hba_set_register( channel, HBA_PXIS  , 0 );
269    _hba_set_register( channel, HBA_PXCI  , 0 );
270    _hba_set_register( channel, HBA_PXCMD , 1 );
271
272    // command list pointer       
273    hba_cmd_slot[channel] = 0;
274
275    // Command list physical addresse
276    vbase = (unsigned int)(&hba_cmd_list[channel]);
277    _v2p_translate( (page_table_t*)pt,
278                     vbase>>12,
279                     &ppn,
280                     &flags );
281    hba_cmd_list_paddr[channel] = ((paddr_t)ppn) | (vbase & 0xFFF);
282
283    // Command tables physical addresses
284    for( c=0 ; c<32 ; c++ )
285    {
286        vbase = (unsigned int)(&hba_cmd_table[channel][c]);
287        _v2p_translate( (page_table_t*)pt,
288                         vbase>>12,
289                         &ppn,
290                         &flags );
291        hba_cmd_table_paddr[channel][c] = ((paddr_t)ppn) | (vbase & 0xFFF);
292    }
293
294    return 0;
295}
296
297///////////////////////////////////////////////
298unsigned int _hba_write( unsigned int  channel,
299                         unsigned int  mode,
300                         unsigned int  lba,
301                         paddr_t       buffer, 
302                         unsigned int  count )
303{
304    return _hba_cmd_set( channel, 
305                         0,         // write
306                         lba, 
307                         buffer, 
308                         count );
309}
310
311//////////////////////////////////////////////
312unsigned int _hba_read( unsigned int  channel,
313                        unsigned int  mode,
314                        unsigned int  lba, 
315                        paddr_t       buffer, 
316                        unsigned int  count )
317{
318    return _hba_cmd_set( channel,
319                         1,          // read
320                         lba, 
321                         buffer, 
322                         count );
323}
324
325//////////////////////////////////
326unsigned int _hba_get_block_size()
327{
328    // TODO The block size must be obtained from the hardware...
329    return 512;
330}
331
332////////////////////////////////////////////////////
333unsigned int _hba_get_status( unsigned int channel ) 
334{
335
336    if( channel >= NB_IOC_CHANNELS )
337    {
338        _puts("\n[GIET ERROR] in _hba_get_status() : illegal channel\n");
339        _exit();
340    }
341
342    // get HBA_PXIS value
343    unsigned int status = _hba_get_register( channel, HBA_PXIS );
344
345    // reset HBA_PXIS
346    _hba_set_register( channel, HBA_PXIS, 0 );
347
348    return status;
349}
350
351// Local Variables:
352// tab-width: 4
353// c-basic-offset: 4
354// c-file-offsets:((innamespace . 0)(inline-open . 0))
355// indent-tabs-mode: nil
356// End:
357// vim: filetype=c:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
358
Note: See TracBrowser for help on using the repository browser.