source: soft/giet_vm/giet_kernel/sys_handler.c @ 681

Last change on this file since 681 was 670, checked in by alain, 9 years ago

Introduce the "shared" argument in the _sys_tty_alloc() function.

  • Property svn:executable set to *
File size: 75.2 KB
RevLine 
[258]1///////////////////////////////////////////////////////////////////////////////////
2// File     : sys_handler.c
3// Date     : 01/04/2012
4// Author   : alain greiner and joel porquet
5// Copyright (c) UPMC-LIP6
6///////////////////////////////////////////////////////////////////////////////////
7
8#include <sys_handler.h>
9#include <tty_driver.h>
10#include <tim_driver.h>
11#include <nic_driver.h>
[440]12#include <mmc_driver.h>
[519]13#include <mwr_driver.h>
[440]14#include <cma_driver.h>
[258]15#include <ctx_handler.h>
16#include <fat32.h>
17#include <utils.h>
[478]18#include <kernel_malloc.h>
[459]19#include <tty0.h>
[396]20#include <vmem.h>
[322]21#include <hard_config.h>
[258]22#include <giet_config.h>
23#include <mapping_info.h>
[547]24#include <irq_handler.h>
[519]25#include <io.h>
[258]26
[322]27#if !defined(SEG_BOOT_MAPPING_BASE)
28# error: You must define SEG_BOOT_MAPPING_BASE in the hard_config.h file
29#endif
30
[449]31#if !defined(NB_TTY_CHANNELS)
32# error: You must define NB_TTY_CHANNELS in the hard_config.h file
33#endif
34
[459]35#if (NB_TTY_CHANNELS < 1)
36# error: NB_TTY_CHANNELS cannot be smaller than 1!
37#endif
38
[449]39#if !defined(NB_TIM_CHANNELS)
40# error: You must define NB_TIM_CHANNELS in the hard_config.h file
41#endif
42
43#if !defined(NB_NIC_CHANNELS)
44# error: You must define NB_NIC_CHANNELS in the hard_config.h file
45#endif
46
47#if !defined(NB_CMA_CHANNELS)
48# error: You must define NB_CMA_CHANNELS in the hard_config.h file
49#endif
50
[478]51#if !defined(GIET_NO_HARD_CC)
52# error: You must define GIET_NO_HARD_CC in the giet_config.h file
[449]53#endif
54
[478]55#if !defined ( GIET_NIC_MAC4 )
56# error: You must define GIET_NIC_MAC4 in the giet_config.h file
[449]57#endif
58
[478]59#if !defined ( GIET_NIC_MAC2 )
60# error: You must define GIET_NIC_MAC2 in the giet_config.h file
[449]61#endif
62
[258]63////////////////////////////////////////////////////////////////////////////
[528]64//        Extern variables
[519]65////////////////////////////////////////////////////////////////////////////
66
[528]67// allocated in tty0.c file.
68extern sqt_lock_t _tty0_sqt_lock;
[519]69
[528]70// allocated in mwr_driver.c file.
71extern simple_lock_t  _coproc_lock[X_SIZE*Y_SIZE];
[556]72extern unsigned int   _coproc_type[X_SIZE*Y_SIZE];
73extern unsigned int   _coproc_info[X_SIZE*Y_SIZE];
74extern unsigned int   _coproc_mode[X_SIZE*Y_SIZE];
75extern unsigned int   _coproc_error[X_SIZE*Y_SIZE];
76extern unsigned int   _coproc_gtid[X_SIZE*Y_SIZE];
[519]77
[556]78
[528]79// allocated in tty_driver.c file.
80extern unsigned int _tty_rx_full[NB_TTY_CHANNELS];
81extern unsigned int _tty_rx_buf[NB_TTY_CHANNELS];
82
[629]83// allocated in kernel_init.c file
84extern static_scheduler_t* _schedulers[X_SIZE][Y_SIZE][NB_PROCS_MAX]; 
85
[519]86////////////////////////////////////////////////////////////////////////////
[440]87//     Channel allocators for peripherals
88//     (TTY[0] is reserved for kernel)
89////////////////////////////////////////////////////////////////////////////
90
[494]91__attribute__((section(".kdata")))
[478]92unsigned int _tty_channel_allocator    = 1;
[494]93
94__attribute__((section(".kdata")))
[478]95unsigned int _tim_channel_allocator    = 0;
[494]96
97__attribute__((section(".kdata")))
[478]98unsigned int _cma_channel_allocator    = 0;
[494]99
100__attribute__((section(".kdata")))
[449]101unsigned int _nic_rx_channel_allocator = 0;
[494]102
103__attribute__((section(".kdata")))
[449]104unsigned int _nic_tx_channel_allocator = 0;
[440]105
106////////////////////////////////////////////////////////////////////////////
[614]107//     NIC_RX and NIC_TX kernel chbuf arrays
[449]108////////////////////////////////////////////////////////////////////////////
109
[494]110__attribute__((section(".kdata")))
[614]111ker_chbuf_t  _nic_ker_rx_chbuf[NB_NIC_CHANNELS] __attribute__((aligned(64)));
[459]112
[494]113__attribute__((section(".kdata")))
[614]114ker_chbuf_t  _nic_ker_tx_chbuf[NB_NIC_CHANNELS] __attribute__((aligned(64)));
[459]115
[478]116////////////////////////////////////////////////////////////////////////////
117// FBF related chbuf descriptors array, indexed by the CMA channel index.
118// Physical addresses of these chbuf descriptors required for L2 cache sync.
[614]119// FBF status
[478]120////////////////////////////////////////////////////////////////////////////
[459]121
[494]122__attribute__((section(".kdata")))
[478]123fbf_chbuf_t _fbf_chbuf[NB_CMA_CHANNELS] __attribute__((aligned(64)));
[459]124
[494]125__attribute__((section(".kdata")))
[478]126unsigned long long _fbf_chbuf_paddr[NB_CMA_CHANNELS];
127
[614]128__attribute__((section(".kdata")))
129buffer_status_t _fbf_status[NB_CMA_CHANNELS] __attribute__((aligned(64)));
130
[449]131////////////////////////////////////////////////////////////////////////////
[258]132//    Initialize the syscall vector with syscall handlers
133// Note: This array must be synchronised with the define in file stdio.h
134////////////////////////////////////////////////////////////////////////////
[494]135
136__attribute__((section(".kdata")))
[258]137const void * _syscall_vector[64] = 
138{
[556]139    &_sys_proc_xyp,                  /* 0x00 */
140    &_get_proctime,                  /* 0x01 */
141    &_sys_tty_write,                 /* 0x02 */
142    &_sys_tty_read,                  /* 0x03 */
143    &_sys_tty_alloc,                 /* 0x04 */
[670]144    &_sys_ukn,                       /* 0x05 */
145    &_sys_ukn,                       /* 0x06 */
[556]146    &_sys_heap_info,                 /* 0x07 */
147    &_sys_local_task_id,             /* 0x08 */
148    &_sys_global_task_id,            /* 0x09 */ 
149    &_sys_fbf_cma_alloc,             /* 0x0A */
[614]150    &_sys_fbf_cma_init_buf,          /* 0x0B */
151    &_sys_fbf_cma_start,             /* 0x0C */
152    &_sys_fbf_cma_display,           /* 0x0D */
153    &_sys_fbf_cma_stop,              /* 0x0E */
154    &_sys_task_exit,                 /* 0x0F */
[258]155
[614]156    &_sys_procs_number,              /* 0x10 */
157    &_sys_fbf_sync_write,            /* 0x11 */
158    &_sys_fbf_sync_read,             /* 0x12 */
159    &_sys_thread_id,                 /* 0x13 */
[556]160    &_sys_tim_alloc,                 /* 0x14 */
161    &_sys_tim_start,                 /* 0x15 */ 
162    &_sys_tim_stop,                  /* 0x16 */
[629]163    &_sys_kill_application,          /* 0x17 */
164    &_sys_exec_application,          /* 0x18 */   
[556]165    &_sys_context_switch,            /* 0x19 */
166    &_sys_vseg_get_vbase,            /* 0x1A */
167    &_sys_vseg_get_length,           /* 0x1B */
168    &_sys_xy_from_ptr,               /* 0x1C */
169    &_sys_ukn,                       /* 0x1D */
170    &_sys_ukn,                       /* 0x1E */
171    &_sys_ukn,                       /* 0x1F */
[258]172
[592]173    &_fat_open,                      /* 0x20 */
174    &_fat_read,                      /* 0x21 */
175    &_fat_write,                     /* 0x22 */
176    &_fat_lseek,                     /* 0x23 */
177    &_fat_file_info,                 /* 0x24 */
[556]178    &_fat_close,                     /* 0x25 */
[592]179    &_fat_remove,                    /* 0x26 */
180    &_fat_rename,                    /* 0x27 */
181    &_fat_mkdir,                     /* 0x28 */
[661]182    &_fat_opendir,                   /* 0x29 */
183    &_fat_closedir,                  /* 0x2A */
184    &_fat_readdir,                   /* 0x2B */
185    &_sys_ukn,                       /* 0x2C */
[556]186    &_sys_ukn,                       /* 0x2D */
187    &_sys_ukn,                       /* 0x2E */
188    &_sys_ukn,                       /* 0x2F */
[258]189
[556]190    &_sys_nic_alloc,                 /* 0x30 */
191    &_sys_nic_start,                 /* 0x31 */
192    &_sys_nic_move,                  /* 0x32 */
193    &_sys_nic_stop,                  /* 0x33 */
194    &_sys_nic_stats,                 /* 0x34 */
195    &_sys_nic_clear,                 /* 0x35 */ 
196    &_sys_ukn,                       /* 0x36 */
197    &_sys_ukn,                       /* 0x37 */
198    &_sys_ukn,                       /* 0x38 */   
199    &_sys_ukn,                       /* 0x39 */
200    &_sys_ukn,                       /* 0x3A */
201    &_sys_coproc_completed,          /* 0x3B */
202    &_sys_coproc_alloc,              /* 0x3C */
203    &_sys_coproc_channel_init,       /* 0x3D */
204    &_sys_coproc_run,                /* 0x3E */
205    &_sys_coproc_release,            /* 0x3F */
[258]206};
207
[459]208
[258]209//////////////////////////////////////////////////////////////////////////////
[648]210//           Applications related syscall handlers
211//////////////////////////////////////////////////////////////////////////////
212
213///////////////////////////////////////
214int _sys_kill_application( char* name )
215{
216    mapping_header_t * header  = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
217    mapping_vspace_t * vspace  = _get_vspace_base(header);
218    mapping_task_t   * task    = _get_task_base(header);
219
220    unsigned int vspace_id;
221    unsigned int task_id;
222    unsigned int y_size = header->y_size;
223
224#if GIET_DEBUG_EXEC
225if ( _get_proctime() > GIET_DEBUG_EXEC )
226_printf("\n[DEBUG EXEC] enters _sys_kill_application() for %s\n", name );
227#endif
228
229    // scan vspaces
230    for (vspace_id = 0; vspace_id < header->vspaces; vspace_id++) 
231    {
232        if ( _strcmp( vspace[vspace_id].name, name ) == 0 ) 
233        {
234            // check if pplication can be killed
235            if ( vspace[vspace_id].active ) return -2;
236
237            // scan tasks in vspace
238            for (task_id = vspace[vspace_id].task_offset; 
239                 task_id < (vspace[vspace_id].task_offset + vspace[vspace_id].tasks); 
240                 task_id++) 
241            {
242                unsigned int cid   = task[task_id].clusterid;
243                unsigned int x     = cid / y_size;
244                unsigned int y     = cid % y_size;
245                unsigned int p     = task[task_id].proclocid;
246                unsigned int ltid  = task[task_id].ltid;
247
248                // get scheduler pointer for processor running the task
249                static_scheduler_t* psched  = (static_scheduler_t*)_schedulers[x][y][p];
250
[670]251                // release private TTY terminal if required
[648]252                if ( psched->context[ltid][CTX_TTY_ID] < NB_TTY_CHANNELS ) 
253                {
254                    psched->context[ltid][CTX_TTY_ID] = 0xFFFFFFFF;
255                    _atomic_increment( &_tty_channel_allocator , 0xFFFFFFFF );
256                }
257
[670]258                // release private TIM channel if required
259                if ( psched->context[ltid][CTX_TIM_ID] < NB_TIM_CHANNELS ) 
260                {
261                    psched->context[ltid][CTX_TIM_ID] = 0xFFFFFFFF;
262                    _atomic_increment( &_tim_channel_allocator , 0xFFFFFFFF );
263                }
264
265                // release private NIC_RX channel if required
266                if ( psched->context[ltid][CTX_NIC_RX_ID] < NB_NIC_CHANNELS ) 
267                {
268                    psched->context[ltid][CTX_NIC_RX_ID] = 0xFFFFFFFF;
269                    _atomic_increment( &_nic_rx_channel_allocator , 0xFFFFFFFF );
270                }
271
272                // release private NIC_TX channel if required
273                if ( psched->context[ltid][CTX_NIC_TX_ID] < NB_NIC_CHANNELS ) 
274                {
275                    psched->context[ltid][CTX_NIC_TX_ID] = 0xFFFFFFFF;
276                    _atomic_increment( &_nic_tx_channel_allocator , 0xFFFFFFFF );
277                }
278
[648]279                // set NORUN_MASK_TASK bit
280                unsigned int*       ptr     = &psched->context[ltid][CTX_NORUN_ID];
281                _atomic_or( ptr , NORUN_MASK_TASK );
282            } 
283
284#if GIET_DEBUG_EXEC
285if ( _get_proctime() > GIET_DEBUG_EXEC )
286_printf("\n[DEBUG EXEC] exit _sys_kill_application() : %s desactivated\n", name );
287#endif
288
289            return 0;
290        }
291    } 
292
293#if GIET_DEBUG_EXEC
294if ( _get_proctime() > GIET_DEBUG_EXEC )
295_printf("\n[DEBUG EXEC] exit _sys_kill_application() : %s not found\n", name );
296#endif
297
298    return -1;    // not found
299
300}  // end _sys_kill_application()
301   
302///////////////////////////////////////
303int _sys_exec_application( char* name )
304{
305    mapping_header_t * header  = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
306    mapping_vspace_t * vspace  = _get_vspace_base(header);
307    mapping_task_t   * task    = _get_task_base(header);
308    mapping_vseg_t   * vseg    = _get_vseg_base(header);
309
310    unsigned int vspace_id;
311    unsigned int task_id;
312    unsigned int vseg_id;
313
314    unsigned int y_size = header->y_size;
315
316#if GIET_DEBUG_EXEC
317if ( _get_proctime() > GIET_DEBUG_EXEC )
318_printf("\n[DEBUG EXEC] enters _sys_exec_application() at cycle %d for %s\n",
319         _get_proctime() , name );
320#endif
321
322    // scan vspaces
323    for (vspace_id = 0 ; vspace_id < header->vspaces ; vspace_id++) 
324    {
325        if ( _strcmp( vspace[vspace_id].name, name ) == 0 ) 
326        {
327            // scan tasks in vspace
328            for (task_id = vspace[vspace_id].task_offset; 
329                 task_id < (vspace[vspace_id].task_offset + vspace[vspace_id].tasks); 
330                 task_id++) 
331            {
332                unsigned int cid   = task[task_id].clusterid;
333                unsigned int x     = cid / y_size;
334                unsigned int y     = cid % y_size;
335                unsigned int p     = task[task_id].proclocid;
336                unsigned int ltid  = task[task_id].ltid;
337
338                // get scheduler pointer for the processor running the task
339                static_scheduler_t* psched  = (static_scheduler_t*)_schedulers[x][y][p];
340
341                // sp_value : initial stack pointer
342                vseg_id = task[task_id].stack_vseg_id;
343                unsigned int sp_value = vseg[vseg_id].vbase + vseg[vseg_id].length;
344
345                // epc value : task entry point
346                unsigned int  epc_value = psched->context[ltid][CTX_ENTRY_ID];
347
348                // ra_value : initial return address
349                unsigned int ra_value = (unsigned int)(&_ctx_eret);
350
351                // initialise task context: RA / SR / EPC / SP / NORUN slots
352                psched->context[ltid][CTX_RA_ID]    = ra_value;
353                psched->context[ltid][CTX_SR_ID]    = GIET_SR_INIT_VALUE;
354                psched->context[ltid][CTX_SP_ID]    = sp_value;
355                psched->context[ltid][CTX_EPC_ID]   = epc_value;
356                psched->context[ltid][CTX_NORUN_ID] = 0;
357
358#if GIET_DEBUG_EXEC
359if ( _get_proctime() > GIET_DEBUG_EXEC )
360_printf("\n[DEBUG EXEC] _sys_exec_application() start task %d on P[%d,%d,%d]\n"
361        " - ctx_ra    = %x\n"
362        " - ctx_sp    = %x\n"
363        " - ctx_epc   = %x\n",
364        task_id , x , y , p , ra_value , sp_value , epc_value );
365#endif
366            } 
367
368#if GIET_DEBUG_EXEC
369if ( _get_proctime() > GIET_DEBUG_EXEC )
370_printf("\n[DEBUG EXEC] exit _sys_exec_application() at cycle %d : %s activated\n",
371        _get_proctime() , name );
372#endif
373
374            return 0;   // application found and activated
375        }
376    }
377
378#if GIET_DEBUG_EXEC
379if ( _get_proctime() > GIET_DEBUG_EXEC )
380_printf("\n[DEBUG EXEC] exit _sys_exec_application() at cycle %d : %s not found\n",
381         _get_proctime() , name );
382#endif
383
384    return -1;    // not found
385
386}  // end _sys_exec_application()
387   
388
389//////////////////////////////////////////////////////////////////////////////
[519]390//           Coprocessors related syscall handlers
391//////////////////////////////////////////////////////////////////////////////
392
393//////////////////////////////////////////////////
394int _sys_coproc_alloc( unsigned int   coproc_type,
[556]395                       unsigned int*  coproc_info )
[519]396{
397    // In this implementation, the allocation policy is constrained:
398    // the coprocessor must be in the same cluster as the calling task,
[556]399    // and there is at most one coprocessor per cluster
[519]400
401    mapping_header_t  * header  = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
402    mapping_cluster_t * cluster = _get_cluster_base(header);
403    mapping_periph_t  * periph  = _get_periph_base(header);
404
405    // get cluster coordinates and cluster global index
406    unsigned int procid     = _get_procid();
407    unsigned int x          = procid >> (Y_WIDTH + P_WIDTH);
408    unsigned int y          = (procid >> P_WIDTH) & ((1<<Y_WIDTH)-1);
[556]409    unsigned int cluster_id = x * Y_SIZE + y;
[519]410 
411    // search coprocessor in cluster
412    mapping_periph_t*  found = NULL;
413    unsigned int min   = cluster[cluster_id].periph_offset;
414    unsigned int max   = min + cluster[cluster_id].periphs;
415    unsigned int periph_id;
416    for ( periph_id = min ; periph_id < max ; periph_id++ )
417    {
418        if ( (periph[periph_id].type == PERIPH_TYPE_MWR) &&
419             (periph[periph_id].subtype == coproc_type) )
420        {
421            found = &periph[periph_id];
422            break;
423        }
424    } 
425
426    if ( found != NULL )
427    {
428        // get the lock (at most one coproc per cluster)
429        _simple_lock_acquire( &_coproc_lock[cluster_id] );
[556]430
431        // register coproc characteristics in kernel arrays
432        _coproc_type[cluster_id] = coproc_type;
433        _coproc_info[cluster_id] = (found->arg0 & 0xFF)     |
434                                   (found->arg1 & 0xFF)<<8  |
435                                   (found->arg2 & 0xFF)<<16 |
436                                   (found->arg3 & 0xFF)<<24 ;
437
[519]438        // returns coprocessor info
[556]439        *coproc_info = _coproc_info[cluster_id];
[519]440
[556]441        // register coprocessor coordinates in task context
442        unsigned int cluster_xy = (x<<Y_WIDTH) + y;
443        _set_context_slot( CTX_COPROC_ID , cluster_xy );
444
[519]445#if GIET_DEBUG_COPROC
446_printf("\n[GIET DEBUG COPROC] _sys_coproc_alloc() in cluster[%d,%d]\n"
447        "  coproc_info = %x / cluster_xy = %x\n",
[556]448        x , y , *coproc_info , cluster_xy );
[519]449#endif
450        return 0;
451    }
452    else
453    {
454         _printf("\n[GIET_ERROR] in _sys_coproc_alloc(): no coprocessor "
455                 " with type %d available in cluster[%d,%d]\n",
456                 coproc_type , x , y );
457        return -1;
458    }
459}  // end _sys_coproc_alloc()
460
[556]461////////////////////////////////////////////////////////
462int _sys_coproc_release( unsigned int coproc_reg_index )
[519]463{
[556]464    // processor coordinates
[519]465    unsigned int procid = _get_procid();
466    unsigned int x      = procid >> (Y_WIDTH + P_WIDTH);
467    unsigned int y      = (procid >> P_WIDTH) & ((1<<Y_WIDTH)-1);
[556]468    unsigned int p      = procid & ((1<<P_WIDTH)-1);
469   
470    // get coprocessor coordinates
471    unsigned int cluster_xy = _get_context_slot( CTX_COPROC_ID );
472    if ( cluster_xy > 0xFF )
[519]473    {
[556]474         _printf("\n[GIET_ERROR] in _sys_coproc_release(): "
475                 "no coprocessor allocated to task running on P[%d,%d,%d]\n",
476                 x , y , p ); 
[519]477         return -1;
478    }
479
[556]480    unsigned int cx         = cluster_xy >> Y_WIDTH;
481    unsigned int cy         = cluster_xy & ((1<<Y_WIDTH)-1);
482    unsigned int cluster_id = cx * Y_SIZE + cy;
483    unsigned int info       = _coproc_info[cluster_id];
484    unsigned int nb_to      = info & 0xFF;
485    unsigned int nb_from    = (info>>8) & 0xFF;
486    unsigned int channel;
[519]487
[556]488    // stops coprocessor and communication channels
489    _mwr_set_coproc_register( cluster_xy , coproc_reg_index , 0 );
490    for ( channel = 0 ; channel < (nb_from + nb_to) ; channel++ )
491    {
492        _mwr_set_channel_register( cluster_xy , channel , MWR_CHANNEL_RUNNING , 0 );
493    }
[519]494
[556]495    // deallocates coprocessor coordinates in task context
496    _set_context_slot( CTX_COPROC_ID , 0xFFFFFFFF );
497
498    // release coprocessor lock
499    _simple_lock_release( &_coproc_lock[cluster_id] );
500
[519]501#if GIET_DEBUG_COPROC
502_printf("\n[GIET DEBUG COPROC] _sys_coproc_release() in cluster[%d,%d]\n",
[556]503        cx, cy );
[519]504#endif
505
506    return 0;
507}  // end _sys_coproc_release()
508
[556]509//////////////////////////////////////////////////////////////
510int _sys_coproc_channel_init( unsigned int            channel,
[519]511                              giet_coproc_channel_t*  desc )
512{
[556]513    // processor coordinates
[519]514    unsigned int procid = _get_procid();
515    unsigned int x      = procid >> (Y_WIDTH + P_WIDTH);
516    unsigned int y      = (procid >> P_WIDTH) & ((1<<Y_WIDTH)-1);
[556]517    unsigned int p      = procid & ((1<<P_WIDTH)-1);
518   
519    // get coprocessor coordinates
520    unsigned int cluster_xy = _get_context_slot( CTX_COPROC_ID );
521    if ( cluster_xy > 0xFF )
[519]522    {
523         _printf("\n[GIET_ERROR] in _sys_coproc_channel_init(): "
[556]524                 "no coprocessor allocated to task running on P[%d,%d,%d]\n",
525                 x , y , p ); 
[519]526         return -1;
527    }
528
529    // check channel mode
530    unsigned mode = desc->channel_mode;
531    if ( (mode != MODE_MWMR) && 
532         (mode != MODE_DMA_IRQ) && 
533         (mode != MODE_DMA_NO_IRQ) )
534    {
[556]535         _printf("\n[GIET_ERROR] in _sys_coproc_channel_init(): "
[519]536                 " illegal mode\n");
537         return -1;
538    }
539
540    // get memory buffer size
541    unsigned int size = desc->buffer_size;
542 
[528]543    // physical addresses
[519]544    unsigned long long buffer_paddr;
545    unsigned int       buffer_lsb;
546    unsigned int       buffer_msb;
[556]547    unsigned long long mwmr_paddr = 0;
[519]548    unsigned int       mwmr_lsb;
549    unsigned int       mwmr_msb;
[556]550    unsigned long long lock_paddr = 0;
[519]551    unsigned int       lock_lsb;
552    unsigned int       lock_msb;
553
[528]554    unsigned int       flags;     // unused
555
[519]556    // compute memory buffer physical address
[528]557    buffer_paddr = _v2p_translate( desc->buffer_vaddr , &flags );
558    buffer_lsb   = (unsigned int)buffer_paddr;
559    buffer_msb   = (unsigned int)(buffer_paddr>>32); 
[519]560
561    // call MWMR_DMA driver
[556]562    _mwr_set_channel_register( cluster_xy, channel, MWR_CHANNEL_MODE, mode ); 
563    _mwr_set_channel_register( cluster_xy, channel, MWR_CHANNEL_SIZE, size ); 
564    _mwr_set_channel_register( cluster_xy, channel, MWR_CHANNEL_BUFFER_LSB, buffer_lsb ); 
565    _mwr_set_channel_register( cluster_xy, channel, MWR_CHANNEL_BUFFER_MSB, buffer_msb ); 
[519]566                       
567    if ( mode == MODE_MWMR )
568    {
[528]569        // compute MWMR descriptor physical address
570        mwmr_paddr = _v2p_translate( desc->mwmr_vaddr , &flags );
[519]571        mwmr_lsb = (unsigned int)mwmr_paddr;
572        mwmr_msb = (unsigned int)(mwmr_paddr>>32); 
573
[528]574        // call MWMR_DMA driver
[556]575        _mwr_set_channel_register( cluster_xy, channel, MWR_CHANNEL_MWMR_LSB, mwmr_lsb ); 
576        _mwr_set_channel_register( cluster_xy, channel, MWR_CHANNEL_MWMR_MSB, mwmr_msb ); 
[528]577
578        // compute lock physical address
579        lock_paddr = _v2p_translate( desc->lock_vaddr , &flags );
[519]580        lock_lsb = (unsigned int)lock_paddr;
581        lock_msb = (unsigned int)(lock_paddr>>32); 
582
583        // call MWMR_DMA driver
[556]584        _mwr_set_channel_register( cluster_xy, channel, MWR_CHANNEL_LOCK_LSB, lock_lsb ); 
585        _mwr_set_channel_register( cluster_xy, channel, MWR_CHANNEL_LOCK_MSB, lock_msb ); 
[519]586    }
587
588#if GIET_DEBUG_COPROC
[556]589_printf("\n[GIET DEBUG COPROC] _sys_coproc_channel_init() for coproc[%d,%d]\n"
[519]590        " channel =  %d / mode = %d / buffer_size = %d\n"
591        " buffer_paddr = %l / mwmr_paddr = %l / lock_paddr = %l\n",
592        x , y , channel , mode , size ,
593        buffer_paddr, mwmr_paddr, lock_paddr );
594#endif
595       
596    return 0;
597} // end _sys_coproc_channel_init()
598
[556]599////////////////////////////////////////////////////
600int _sys_coproc_run( unsigned int coproc_reg_index )
[519]601{
[556]602    // processor coordinates
[519]603    unsigned int procid = _get_procid();
604    unsigned int x      = procid >> (Y_WIDTH + P_WIDTH);
605    unsigned int y      = (procid >> P_WIDTH) & ((1<<Y_WIDTH)-1);
[556]606    unsigned int p      = procid & ((1<<P_WIDTH)-1);
607   
608    // get coprocessor coordinates
609    unsigned int cluster_xy = _get_context_slot( CTX_COPROC_ID );
610    if ( cluster_xy > 0xFF )
[519]611    {
[556]612         _printf("\n[GIET_ERROR] in _sys_coproc_run(): "
613                 "no coprocessor allocated to task running on P[%d,%d,%d]\n",
614                 x , y , p ); 
[519]615         return -1;
616    }
617
[556]618    unsigned int cx         = cluster_xy >> Y_WIDTH;
619    unsigned int cy         = cluster_xy & ((1<<Y_WIDTH)-1);
620    unsigned int cluster_id = cx * Y_SIZE + cy;
621    unsigned int info       = _coproc_info[cluster_id];
622    unsigned int nb_to      = info & 0xFF;
623    unsigned int nb_from    = (info>>8) & 0xFF;
624    unsigned int mode       = 0xFFFFFFFF;
625    unsigned int channel;
[519]626
[556]627    // register coprocessor running mode
628    for ( channel = 0 ; channel < (nb_from + nb_to) ; channel++ )
629    {
630        unsigned int temp;
631        temp = _mwr_get_channel_register( cluster_xy , channel , MWR_CHANNEL_MODE );
[519]632
[556]633        if ( mode == 0xFFFFFFFF ) 
634        {
635            mode = temp;
636        }
637        else if ( temp != mode )
638        {
639            _printf("\n[GIET_ERROR] P[%d,%d,%d] in _sys_coproc_run() for coprocessor[%d,%d]\n"
640                    "  all channels don't have the same mode\n", x , y , p , cx , cy );
641            return -1;
642        }
643    }
644    _coproc_mode[cluster_id] = mode;
[519]645
[556]646    // start all communication channels
647    for ( channel = 0 ; channel < (nb_from + nb_to) ; channel++ )
648    {
649        _mwr_set_channel_register( cluster_xy , channel , MWR_CHANNEL_RUNNING , 1 );
650    }
[519]651
[556]652    //////////////////////////////////////////////////////////////////////////
653    if ( (mode == MODE_MWMR) || (mode == MODE_DMA_NO_IRQ) )  // no descheduling
[519]654    {
[556]655        // start coprocessor
656        _mwr_set_coproc_register( cluster_xy , coproc_reg_index , 1 );
657
658#if GIET_DEBUG_COPROC
659if ( mode == MODE_MWMR )
660_printf("\n[GIET DEBUG COPROC] _sys_coproc_run() P[%d,%d,%d] starts coprocessor[%d,%d]\n"
661        "   MODE_MWMR at cycle %d\n", x , y , p , cx , cy , _get_proctime() );
662else
663_printf("\n[GIET DEBUG COPROC] _sys_coproc_run() P[%d,%d,%d] starts coprocessor[%d,%d]\n"
664        "   MODE_DMA_NO_IRQ at cycle %d\n", x , y , p , cx , cy , _get_proctime() );
665#endif
666
667        return 0;
[519]668    }
[556]669    ///////////////////////////////////////////////////////////////////////////
670    else                                // mode == MODE_DMA_IRQ => descheduling
671    {
672        // set _coproc_gtid
673        unsigned int ltid = _get_current_task_id();
674        _coproc_gtid[cluster_id] = (procid<<16) + ltid;
[519]675
[556]676        // enters critical section
677        unsigned int save_sr;
678        _it_disable( &save_sr ); 
679
[629]680        // set NORUN_MASK_COPROC bit
681        static_scheduler_t* psched  = (static_scheduler_t*)_schedulers[x][y][p];
682        unsigned int*       ptr     = &psched->context[ltid][CTX_NORUN_ID];
683        _atomic_or( ptr , NORUN_MASK_COPROC );
[556]684
685        // start coprocessor
686        _mwr_set_coproc_register( cluster_xy , coproc_reg_index , 1 );
687
[519]688#if GIET_DEBUG_COPROC
[556]689_printf("\n[GIET DEBUG COPROC] _sys_coproc_run() P[%d,%d,%d] starts coprocessor[%d,%d]\n"
690        "   MODE_DMA_IRQ at cycle %d\n", x , y , p , cx , cy , _get_proctime() );
[519]691#endif
692
[556]693        // deschedule task
694        _ctx_switch(); 
[519]695
[556]696#if GIET_DEBUG_COPROC
697_printf("\n[GIET DEBUG COPROC] _sys_coproc_run() P[%d,%d,%d] resume\n"
698        "  coprocessor[%d,%d] completion at cycle %d\n", 
699        x , y , p , cx , cy , _get_proctime() );
700#endif
701
702        // restore SR
703        _it_restore( &save_sr );
704
705        // return error computed by mwr_isr()
706        return _coproc_error[cluster_id];
707    } 
708} // end _sys_coproc_run()
709
710///////////////////////////
711int _sys_coproc_completed()
[519]712{
[556]713    // processor coordinates
[519]714    unsigned int procid = _get_procid();
715    unsigned int x      = procid >> (Y_WIDTH + P_WIDTH);
716    unsigned int y      = (procid >> P_WIDTH) & ((1<<Y_WIDTH)-1);
[556]717    unsigned int p      = procid & ((1<<P_WIDTH)-1);
718   
719    // get coprocessor coordinates
720    unsigned int cluster_xy = _get_context_slot( CTX_COPROC_ID );
721    if ( cluster_xy > 0xFF )
[519]722    {
723         _printf("\n[GIET_ERROR] in _sys_coproc_completed(): "
[556]724                 "no coprocessor allocated to task running on P[%d,%d,%d]\n",
725                 x , y , p ); 
[519]726         return -1;
727    }
728
[556]729    unsigned int cx         = cluster_xy >> Y_WIDTH;
730    unsigned int cy         = cluster_xy & ((1<<Y_WIDTH)-1);
731    unsigned int cluster_id = cx * Y_SIZE + cy;
732    unsigned int mode       = _coproc_mode[cluster_id];
[519]733
[556]734    // analyse possible errors
735    if ( mode == MODE_DMA_NO_IRQ )
736    {
737        unsigned int info       = _coproc_info[cluster_id];
738        unsigned int nb_to      = info & 0xFF;
739        unsigned int nb_from    = (info>>8) & 0xFF;
740        unsigned int error      = 0;
741        unsigned int channel;
742        unsigned int status;
743
744        // get status for all channels, and signal all reported errors
745        for ( channel = 0 ; channel < (nb_to +nb_from) ; channel++ )
746        {
747            do
748            {
749                status = _mwr_get_channel_register( cluster_xy , channel , MWR_CHANNEL_STATUS );
750                if ( status == MWR_CHANNEL_ERROR_DATA )
751                {
752                    _printf("\n[GIET_ERROR] in _sys_coproc_completed()"
753                            " / channel %d / DATA_ERROR\n", channel );
754                    error = 1;
755                    break;
756                }
757                else if ( status == MWR_CHANNEL_ERROR_LOCK )
758                {
759                    _printf("\n[GIET_ERROR] in _sys_coproc_completed()"
760                            " / channel %d / LOCK_ERROR\n", channel );
761                    error = 1;
762                    break;
763                }
764                else if ( status == MWR_CHANNEL_ERROR_DESC )
765                {
766                    _printf("\n[GIET_ERROR] in _sys_coproc_completed()"
767                            " / channel %d / DESC_ERROR\n", channel );
768                    error = 1;
769                    break;
770                }
771            } while ( status == MWR_CHANNEL_BUSY );
772
773            // reset channel
774            _mwr_set_channel_register( cluster_xy , channel , MWR_CHANNEL_RUNNING , 0 ); 
775
776        }  // end for channels
777
[519]778#if GIET_DEBUG_COPROC
[556]779_printf("\n[GIET DEBUG COPROC] _sys_coproc_completed() for coprocessor[%d,%d] error = %d\n", 
780        cx , cy , error );
[519]781#endif
782
[556]783        return error;
784    }
785    else  // mode == MODE_MWMR or MODE_DMA_IRQ
786    {
787        _printf("\n[GIET ERROR] sys_coproc_completed() should not be called for "
788                "coprocessor[%d,%d] running in MODE_MWMR or MODE_DMA_IRQ\n", cx , cy );
789        return 1;
790    }
[519]791} // end _sys_coproc_completed()
792
793
794//////////////////////////////////////////////////////////////////////////////
[440]795//             TTY related syscall handlers
[258]796//////////////////////////////////////////////////////////////////////////////
[440]797
[670]798/////////////////////////////////////////
799int _sys_tty_alloc( unsigned int shared )
[258]800{
[440]801    // get a new TTY terminal index
[459]802    unsigned int channel = _atomic_increment( &_tty_channel_allocator, 1 );
[440]803
804    if ( channel >= NB_TTY_CHANNELS )
805    {
[648]806        _atomic_increment( &_tty_channel_allocator , 0xFFFFFFFF );
[440]807        _printf("\n[GIET_ERROR] in _sys_tty_alloc() : not enough TTY channels\n");
808        return -1;
809    }
[547]810
[648]811    // reset kernel buffer for allocated TTY channel
812    _tty_rx_full[channel] = 0;
813
[547]814    // allocate a WTI mailbox to the calling proc if external IRQ
815    unsigned int unused;
816    if ( USE_PIC ) _ext_irq_alloc( ISR_TTY_RX , channel , &unused ); 
817   
[670]818    // update CTX_TTY_ID
819    if ( shared )         // for all tasks in the same vspace
820    {
821        unsigned int      vspace_id = _get_context_slot( CTX_VSID_ID );
822        mapping_header_t  *header   = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
823        mapping_vspace_t  *vspace   = _get_vspace_base(header);
824        mapping_task_t    *task     = _get_task_base(header);
[547]825
[670]826        // scan tasks in vspace
827        unsigned int task_id;
828        for (task_id = vspace[vspace_id].task_offset;
829             task_id < (vspace[vspace_id].task_offset + vspace[vspace_id].tasks);
830             task_id++)
831        {
832            unsigned int y_size        = header->y_size;
833            unsigned int cid           = task[task_id].clusterid;
834            unsigned int x             = cid / y_size;
835            unsigned int y             = cid % y_size;
836            unsigned int p             = task[task_id].proclocid;
837            unsigned int ltid          = task[task_id].ltid;
838            static_scheduler_t* psched = (static_scheduler_t*)_schedulers[x][y][p];
839            psched->context[ltid][CTX_TTY_ID] = channel;
840        }
841    }
842    else                  // for calling task only
843    {
844        _set_context_slot( CTX_TTY_ID, channel );
845    }
846
[547]847    return 0;
[258]848}
849
[440]850/////////////////////////////////////////////////
851int _sys_tty_write( const char*  buffer,   
852                    unsigned int length,    // number of characters
853                    unsigned int channel)   // channel index
854{
855    unsigned int  nwritten;
856
857    // compute and check tty channel
858    if( channel == 0xFFFFFFFF )  channel = _get_context_slot(CTX_TTY_ID);
859    if( channel >= NB_TTY_CHANNELS ) return -1;
860
861    // write string to TTY channel
862    for (nwritten = 0; nwritten < length; nwritten++) 
863    {
864        // check tty's status
865        if ( _tty_get_register( channel, TTY_STATUS ) & 0x2 )  break;
866
867        // write one byte
868        if (buffer[nwritten] == '\n') 
869        {
870            _tty_set_register( channel, TTY_WRITE, (unsigned int)'\r' );
871        }
872        _tty_set_register( channel, TTY_WRITE, (unsigned int)buffer[nwritten] );
873    }
874   
875    return nwritten;
876}
877
878////////////////////////////////////////////////
879int _sys_tty_read( char*        buffer, 
880                   unsigned int length,    // unused
881                   unsigned int channel)   // channel index
882{
883    // compute and check tty channel
884    if( channel == 0xFFFFFFFF )  channel = _get_context_slot(CTX_TTY_ID);
885    if( channel >= NB_TTY_CHANNELS ) return -1;
886
887    // read one character from TTY channel
888    if (_tty_rx_full[channel] == 0) 
889    {
890        return 0;
891    }
892    else 
893    {
894        *buffer = _tty_rx_buf[channel];
895        _tty_rx_full[channel] = 0;
896        return 1;
897    }
898}
899
900///////////////////////////////////////////
[494]901int _sys_tty_get_lock( unsigned int   channel,       // unused
[440]902                       unsigned int * save_sr_ptr )
903{
[494]904    // check tty channel
905    if( channel != 0 )  return 1;
[440]906
907    _it_disable( save_sr_ptr );
[494]908    _sqt_lock_acquire( &_tty0_sqt_lock );
[440]909    return 0;
910}
911
912///////////////////////////////////////////////
913int _sys_tty_release_lock( unsigned int   channel,
914                           unsigned int * save_sr_ptr )
915{
[494]916    // check tty channel
917    if( channel != 0 )  return 1;
[440]918
[494]919    _sqt_lock_release( &_tty0_sqt_lock );
[440]920    _it_restore( save_sr_ptr );
921    return 0;
922}
923
[428]924//////////////////////////////////////////////////////////////////////////////
[440]925//             TIM related syscall handlers
[428]926//////////////////////////////////////////////////////////////////////////////
[440]927
928////////////////////
929int _sys_tim_alloc()
[428]930{
[440]931    // get a new timer index
[459]932    unsigned int channel = _atomic_increment( &_tim_channel_allocator, 1 );
[440]933
934    if ( channel >= NB_TIM_CHANNELS )
935    {
936        _printf("\n[GIET_ERROR] in _sys_tim_alloc() : not enough TIM channels\n");
937        return -1;
938    }
939    else
940    {
[449]941        _set_context_slot( CTX_TIM_ID, channel );
942        return 0;
[440]943    }
944}
945
946/////////////////////////////////////////
947int _sys_tim_start( unsigned int period )
948{
949    // get timer index
950    unsigned int channel = _get_context_slot( CTX_TIM_ID );
951    if ( channel >= NB_TIM_CHANNELS )
952    {
953        _printf("\n[GIET_ERROR] in _sys_tim_start() : not enough TIM channels\n");
954        return -1;
955    }
956
957    // start timer
958    _timer_start( channel, period );
959
960    return 0;
961}
962
963///////////////////
964int _sys_tim_stop()
965{
966    // get timer index
967    unsigned int channel = _get_context_slot( CTX_TIM_ID );
968    if ( channel >= NB_TIM_CHANNELS )
969    {
970        _printf("\n[GIET_ERROR] in _sys_tim_stop() : illegal timer index\n");
971        return -1;
972    }
973
974    // stop timer
975    _timer_stop( channel );
976
977    return 0;
978}
979
980//////////////////////////////////////////////////////////////////////////////
981//             NIC related syscall handlers
982//////////////////////////////////////////////////////////////////////////////
983
[478]984#define NIC_CONTAINER_SIZE 4096
985
[494]986////////////////////////////////////////
987int _sys_nic_alloc( unsigned int is_rx,
988                    unsigned int xmax,
989                    unsigned int ymax )
[440]990{
[494]991    // check xmax / ymax parameters
992    if ( xmax > X_SIZE )
993    {
994        _printf("\n[GIET_ERROR] in _sys_nic_alloc() xmax argument too large\n");
995        return -1;
996    }
997    if ( ymax > Y_SIZE )
998    {
999        _printf("\n[GIET_ERROR] in _sys_nic_alloc() ymax argument too large\n");
1000        return -1;
1001    }
[459]1002
[614]1003    ////////////////////////////////////////////////////////
1004    // Step 1: get and register CMA and NIC channel index //
1005    ////////////////////////////////////////////////////////
1006
[494]1007    // get a NIC_RX or NIC_TX channel index
[449]1008    unsigned int nic_channel;
1009    unsigned int cma_channel;
[440]1010
[459]1011    if ( is_rx ) nic_channel = _atomic_increment( &_nic_rx_channel_allocator, 1 );
1012    else         nic_channel = _atomic_increment( &_nic_tx_channel_allocator, 1 );
[449]1013
1014    if ( (nic_channel >= NB_NIC_CHANNELS) )
[440]1015    {
[449]1016        _printf("\n[GIET_ERROR] in _sys_nic_alloc() not enough NIC channels\n");
[440]1017        return -1;
1018    }
[449]1019
1020    // get a CMA channel index
[459]1021    cma_channel = _atomic_increment( &_cma_channel_allocator, 1 );
[449]1022
1023    if ( cma_channel >= NB_CMA_CHANNELS )
1024    {
1025        _printf("\n[GIET_ERROR] in _sys_nic_alloc() not enough CMA channels\n");
1026        return -1;
1027    }
[459]1028
[494]1029#if GIET_DEBUG_NIC
1030unsigned int thread  = _get_context_slot( CTX_TRDID_ID );
1031_printf("\n[GIET DEBUG NIC] Task %d enters sys_nic_alloc() at cycle %d\n"
[547]1032        "  nic_channel = %d / cma_channel = %d\n",
[494]1033        thread , _get_proctime() , nic_channel , cma_channel );
1034#endif
1035
[449]1036    // register nic_index and cma_index in task context
1037    if ( is_rx )
1038    {
1039        _set_context_slot( CTX_NIC_RX_ID, nic_channel );
1040        _set_context_slot( CTX_CMA_RX_ID, cma_channel );
1041    }
[440]1042    else
1043    {
[449]1044        _set_context_slot( CTX_NIC_TX_ID, nic_channel );
1045        _set_context_slot( CTX_CMA_TX_ID, cma_channel );
[440]1046    }
1047
[614]1048    /////////////////////////////////////////////////////////////////////////////////
1049    // Step 2: loop on all the clusters                                            //
1050    // Allocate the kernel containers and status, compute the container and the    //
1051    // status physical addresses, fill and synchronize the kernel CHBUF descriptor //
1052    /////////////////////////////////////////////////////////////////////////////////
1053
[494]1054    // physical addresses to be registered in the CMA registers
[459]1055    unsigned long long nic_chbuf_pbase;     // NIC chbuf physical address
1056    unsigned long long ker_chbuf_pbase;     // kernel chbuf physical address
[449]1057
[614]1058    // allocate one kernel container and one status variable per cluster in the
1059    // (xmax / ymax) mesh
[528]1060    unsigned int        cx;                 // cluster X coordinate
1061    unsigned int        cy;                 // cluster Y coordinate
1062    unsigned int        index;              // container index in chbuf
1063    unsigned int        vaddr;              // virtual address
1064    unsigned long long  cont_paddr;         // container physical address
[614]1065    unsigned long long  sts_paddr;          // container status physical address
[494]1066
[528]1067    unsigned int        flags;              // for _v2p_translate()
1068
[494]1069    for ( cx = 0 ; cx < xmax ; cx++ )
[478]1070    {
[494]1071        for ( cy = 0 ; cy < ymax ; cy++ )
[478]1072        {
1073            // compute index in chbuf
[494]1074            index = (cx * ymax) + cy; 
[478]1075
[494]1076            // allocate the kernel container
[478]1077            vaddr = (unsigned int)_remote_malloc( NIC_CONTAINER_SIZE, cx, cy );
1078
[494]1079            if ( vaddr == 0 )  // not enough kernel heap memory in cluster[cx,cy]
1080            {
1081                _printf("\n[GIET_ERROR] in _sys_nic_alloc() not enough kenel heap"
1082                        " in cluster[%d,%d]\n", cx, cy );
1083                return -1;
1084            }
1085
[478]1086            // compute container physical address
[528]1087            cont_paddr = _v2p_translate( vaddr , &flags );
[478]1088
[614]1089            // checking container address alignment
1090            if ( cont_paddr & 0x3F )
1091            {
1092                _printf("\n[GIET ERROR] in _sys_nic_alloc() : container address of cluster[%d,%d] not aligned\n",
1093                        cx, cy);
1094                return -1;
1095            }
1096
1097#if GIET_DEBUG_NIC
1098_printf("\n[GIET DEBUG NIC] Task %d in _sys_nic_alloc()\n"
1099        " allocates in cluster[%d,%d]:\n"
1100        " - container vaddr = %x / paddr = %l\n",
1101        thread , cx , cy , vaddr, cont_paddr );
1102#endif
1103
1104            // allocate the kernel container status
1105            // it occupies 64 bytes but only last bit is useful (1 for full and 0 for empty)
1106            vaddr = (unsigned int)_remote_malloc( 64, cx, cy );
1107
1108            if ( vaddr == 0 )  // not enough kernel heap memory in cluster[cx,cy]
1109            {
1110                _printf("\n[GIET_ERROR] in _sys_nic_alloc() not enough kenel heap"
1111                        " in cluster[%d,%d]\n", cx, cy );
1112                return -1;
1113            }
1114
1115            // compute status physical address
1116            sts_paddr = _v2p_translate( vaddr , &flags );
1117
1118            // checking status address alignment
1119            if ( sts_paddr & 0x3F )
1120            {
1121                _printf("\n[GIET ERROR] in _sys_nic_alloc() : status address of cluster[%d,%d] not aligned\n",
1122                        cx, cy);
1123                return -1;
1124            }
1125
[494]1126            // initialize chbuf entry
[614]1127            // The buffer descriptor has the following structure:
1128            // - the 26 LSB bits contain bits[6:31] of the buffer physical address
1129            // - the 26 following bits contain bits[6:31] of the physical address where the
1130            //   buffer status is located
1131            // - the 12 MSB bits contain the common address extension of the buffer and its
1132            //   status
1133            if ( is_rx )
1134                _nic_ker_rx_chbuf[nic_channel].buf_desc[index] =
1135                    (unsigned long long)
1136                    ((sts_paddr & 0xFFFFFFFFULL) >> 6) +
1137                    (((cont_paddr & 0xFFFFFFFFFFFULL) >> 6) << 26);
1138            else
1139                _nic_ker_tx_chbuf[nic_channel].buf_desc[index] =
1140                    (unsigned long long)
1141                    ((sts_paddr & 0xFFFFFFC0ULL) >> 6) +
1142                    (((cont_paddr & 0xFFFFFFFFFC0ULL) >> 6) << 26);
[478]1143
1144#if GIET_DEBUG_NIC
[614]1145_printf("\n[GIET DEBUG NIC] Task %d in _sys_nic_alloc()\n"
1146        " - status vaddr = %x / paddr = %l\n"
1147        " Buffer descriptor = %l\n",
1148        thread, vaddr, sts_paddr,
1149        (unsigned long long)((sts_paddr & 0xFFFFFFFFULL) >> 6) + 
1150        (((cont_paddr & 0xFFFFFFFFFFFULL) >> 6) << 26) );
[478]1151#endif
1152        }
1153    }
1154
[494]1155    // complete kernel chbuf initialisation
1156    if ( is_rx )
1157    {
[614]1158        _nic_ker_rx_chbuf[nic_channel].xmax = xmax;
1159        _nic_ker_rx_chbuf[nic_channel].ymax = ymax;
[494]1160    }
1161    else
1162    {
[614]1163        _nic_ker_tx_chbuf[nic_channel].xmax = xmax;
1164        _nic_ker_tx_chbuf[nic_channel].ymax = ymax;
[494]1165    }
1166
[449]1167    // compute the kernel chbuf descriptor physical address
[614]1168    if ( is_rx ) vaddr = (unsigned int)( &_nic_ker_rx_chbuf[nic_channel] );
1169    else         vaddr = (unsigned int)( &_nic_ker_tx_chbuf[nic_channel] );
[440]1170
[528]1171    ker_chbuf_pbase = _v2p_translate( vaddr , &flags );
1172
[459]1173#if GIET_DEBUG_NIC
[547]1174_printf("\n[GIET DEBUG NIC] Task %d in _sys_nic_alloc() get kernel chbuf\n"
1175        "  vaddr = %x / paddr = %l\n",
[478]1176        thread , vaddr , ker_chbuf_pbase );
[459]1177#endif
[440]1178
[459]1179    // sync the kernel chbuf in L2 after write in L2
[614]1180    _mmc_sync( ker_chbuf_pbase, sizeof( ker_chbuf_t ) );
[459]1181
[614]1182    ///////////////////////////////////////////////////////////////
1183    // Step 3: compute the NIC chbuf descriptor physical address //
1184    ///////////////////////////////////////////////////////////////
1185
1186    unsigned int offset;
1187    if ( is_rx ) offset = 0x4100;
1188    else         offset = 0x4110;
1189    nic_chbuf_pbase = (((unsigned long long)((X_IO << Y_WIDTH) + Y_IO))<<32) |
1190                      (SEG_NIC_BASE + (nic_channel<<15) + offset);
1191
1192#if GIET_DEBUG_NIC
1193_printf("\n[GIET DEBUG NIC] Task %d in _sys_nic_alloc() get NIC chbuf : paddr = %l\n",
1194        thread , nic_chbuf_pbase );
1195#endif
1196
1197    ////////////////////////////////////////////////////////////////////////////////
1198    // Step 4: initialize CMA registers defining the source & destination chbufs //
1199    ////////////////////////////////////////////////////////////////////////////////
1200
[459]1201    if ( is_rx )               // NIC to kernel
1202    {
1203        _cma_set_register( cma_channel, CHBUF_SRC_DESC , (unsigned int)(nic_chbuf_pbase) );
1204        _cma_set_register( cma_channel, CHBUF_SRC_EXT  , (unsigned int)(nic_chbuf_pbase>>32) );
1205        _cma_set_register( cma_channel, CHBUF_SRC_NBUFS, 2 );
1206        _cma_set_register( cma_channel, CHBUF_DST_DESC , (unsigned int)(ker_chbuf_pbase) );
1207        _cma_set_register( cma_channel, CHBUF_DST_EXT  , (unsigned int)(ker_chbuf_pbase>>32) );
[494]1208        _cma_set_register( cma_channel, CHBUF_DST_NBUFS, xmax * ymax );
[459]1209    }
1210    else                      // kernel to NIC
1211    {
1212        _cma_set_register( cma_channel, CHBUF_SRC_DESC , (unsigned int)(ker_chbuf_pbase) );
1213        _cma_set_register( cma_channel, CHBUF_SRC_EXT  , (unsigned int)(ker_chbuf_pbase>>32) );
[494]1214        _cma_set_register( cma_channel, CHBUF_SRC_NBUFS, xmax * ymax );
[459]1215        _cma_set_register( cma_channel, CHBUF_DST_DESC , (unsigned int)(nic_chbuf_pbase) );
1216        _cma_set_register( cma_channel, CHBUF_DST_EXT  , (unsigned int)(nic_chbuf_pbase>>32) );
1217        _cma_set_register( cma_channel, CHBUF_DST_NBUFS, 2 );
1218    }
1219
[494]1220#if GIET_DEBUG_NIC
1221_printf("\n[GIET DEBUG NIC] Task %d exit _sys_nic_alloc() at cycle %d\n",
1222        thread, _get_proctime() );
1223#endif
1224
1225    return nic_channel;
1226} // end _sys_nic_alloc()
1227
1228
1229////////////////////////////////////////
1230int _sys_nic_start( unsigned int is_rx,
1231                    unsigned int channel )
1232{
1233    unsigned int nic_channel;
1234    unsigned int cma_channel;
1235
1236    // get NIC channel index and CMA channel index from task context
1237    if ( is_rx )
1238    {
1239        nic_channel = _get_context_slot( CTX_NIC_RX_ID );
1240        cma_channel = _get_context_slot( CTX_CMA_RX_ID );
1241    }
1242    else
1243    {
1244        nic_channel = _get_context_slot( CTX_NIC_TX_ID );
1245        cma_channel = _get_context_slot( CTX_CMA_TX_ID );
1246    }
1247
1248#if GIET_DEBUG_NIC
1249unsigned int thread  = _get_context_slot( CTX_TRDID_ID );
[547]1250_printf("\n[GIET DEBUG NIC] Task %d in _sys_nic_start() at cycle %d\n"
1251        "  get NIC channel = %d / CMA channel = %d\n",
[494]1252        thread, _get_proctime(), nic_channel, cma_channel );
1253#endif
1254
1255    // check NIC and CMA channels index
1256    if ( nic_channel != channel )
1257    {
1258        _printf("\n[GIET_ERROR] in _sys_nic_start(): illegal NIC channel\n");
1259        return -1;
1260    }
1261    if ( cma_channel >= NB_CMA_CHANNELS )
1262    {
1263        _printf("\n[GIET_ERROR] in _sys_nic_start(): illegal CMA channel\n");
1264        return -1;
1265    }
1266
[449]1267    // start CMA transfer
[478]1268    _cma_set_register( cma_channel, CHBUF_BUF_SIZE , NIC_CONTAINER_SIZE );
[505]1269    _cma_set_register( cma_channel, CHBUF_PERIOD   , 0 );     // OUT_OF_ORDER
[449]1270    _cma_set_register( cma_channel, CHBUF_RUN      , 1 );
1271
1272    // activates NIC channel
[614]1273    _nic_channel_start( nic_channel, is_rx, GIET_NIC_MAC4, GIET_NIC_MAC2 );
[459]1274
1275#if GIET_DEBUG_NIC
[614]1276    _printf("\n[GIET DEBUG NIC] Task %d exit _sys_nic_start() at cycle %d\n",
1277            thread , _get_proctime() );
[459]1278#endif
1279
[449]1280    return 0;
[505]1281}  // end _sys_nic_start()
[449]1282
[494]1283
[449]1284//////////////////////////////////////
1285int _sys_nic_move( unsigned int is_rx,
[459]1286                   unsigned int channel,
[449]1287                   void*        buffer )
1288{
1289
[459]1290#if GIET_DEBUG_NIC
1291unsigned int thread  = _get_context_slot( CTX_TRDID_ID );
[478]1292_printf("\n[GIET DEBUG NIC] Task %d enters _sys_nic_move() at cycle %d\n",
1293        thread , _get_proctime() );
[459]1294#endif
1295
[494]1296    // check NIC channel index
1297    if ( channel >= NB_NIC_CHANNELS )
1298    {
1299        _printf("\n[GIET_ERROR] in _sys_nic_move() : illegal NIC channel index\n");
1300        return -1;
1301    }
1302
1303    // get kernel chbuf virtual address
[614]1304    ker_chbuf_t* ker_chbuf;
1305    if ( is_rx )  ker_chbuf = &_nic_ker_rx_chbuf[channel];
1306    else          ker_chbuf = &_nic_ker_tx_chbuf[channel];
[494]1307
1308    // get xmax / ymax parameters
[614]1309    unsigned int xmax = ker_chbuf->xmax;
1310    unsigned int ymax = ker_chbuf->ymax;
[494]1311
[478]1312    // get cluster coordinates for the processor running the calling task
1313    unsigned int  procid = _get_procid();
1314    unsigned int  cx     = procid >> (Y_WIDTH + P_WIDTH);
1315    unsigned int  cy     = (procid >> P_WIDTH) & ((1<<Y_WIDTH)-1);
1316   
[494]1317    // check processor coordinates / (xmax,ymax)
1318    if ( cx >= xmax )
1319    {
1320        _printf("\n[GIET_ERROR] in _sys_nic_move() : processor X coordinate = %d"
1321                " / xmax = %d\n", cx , xmax );
1322        return -1;
1323    }
1324    if ( cy >= ymax )
1325    {
1326        _printf("\n[GIET_ERROR] in _sys_nic_move() : processor Y coordinate = %d"
1327                " / ymax = %d\n", cy , ymax );
1328        return -1;
1329    }
1330   
[614]1331    unsigned long long usr_buf_paddr;       // user buffer physical address
1332    unsigned long long ker_buf_paddr;       // kernel buffer physical address
1333    unsigned long long ker_sts_paddr;       // kernel buffer status physical address
1334    unsigned long long ker_buf_desc;        // kernel buffer descriptor
1335    unsigned int       ker_sts;             // kernel buffer status (full or empty)
1336    unsigned int       index;               // kernel buffer index in chbuf
1337    unsigned int       flags;               // for _v2P_translate
[459]1338
1339    // Compute user buffer physical address and check access rights
[614]1340    usr_buf_paddr = _v2p_translate( (unsigned int)buffer , &flags );
[478]1341
[440]1342    if ( (flags & PTE_U) == 0 )
1343    {
[614]1344        _printf("\n[GIET ERROR] in _sys_nic_tx_move() : illegal user buffer address\n");
[440]1345        return -1;
1346    }
1347
[459]1348#if GIET_DEBUG_NIC
[478]1349_printf("\n[GIET DEBUG NIC] Task %d in _sys_nic_move() get user buffer : paddr = %l\n",
[614]1350        thread, usr_buf_paddr );
[459]1351#endif
[440]1352
[614]1353    // compute buffer index, buffer descriptor paddr and buffer status paddr
1354    index = (ymax * cx) + cy;
1355    ker_buf_desc = ker_chbuf->buf_desc[index];
1356    ker_sts_paddr = ((ker_buf_desc & 0xFFF0000000000000ULL) >> 20) +
1357                    ((ker_buf_desc & 0x3FFFFFFULL) << 6);
[459]1358
[614]1359#if GIET_DEBUG_NIC
1360_printf("\n[GIET DEBUG NIC] Task %d in _sys_nic_move() read ker_buf_desc %d at cycle %d\n"
1361        "  kernel buffer descriptor = %l\n",
1362        thread, index, _get_proctime(), ker_buf_desc );
1363#endif
1364
[494]1365    // poll local kernel container status until success
[478]1366    while ( 1 )
[449]1367    {
[478]1368        // inval buffer descriptor in L2 before read in L2
[614]1369        _mmc_inval( ker_sts_paddr, 4 );
1370        ker_sts = _physical_read( ker_sts_paddr );
[459]1371
1372#if GIET_DEBUG_NIC
[614]1373_printf("\n[GIET DEBUG NIC] Task %d in _sys_nic_move() read ker_buf_sts %d at cycle %d\n"
1374        "  paddr = %l / kernel buffer status = %x\n",
1375        thread, index, _get_proctime(), ker_sts_paddr, ker_sts );
[459]1376#endif
1377
[478]1378        // test buffer status and break if found
[614]1379        if ( ( is_rx != 0 ) && ( ker_sts == 0x1 ) ) break;
1380        if ( ( is_rx == 0 ) && ( ker_sts == 0 ) ) break;
[449]1381    }
[459]1382
1383    // compute kernel buffer physical address
[614]1384    ker_buf_paddr = (ker_buf_desc & 0xFFFFFFFFFC000000ULL) >> 20;
[449]1385   
[494]1386    // move one container
1387    if ( is_rx )              // RX transfer
[459]1388    {
1389        // inval kernel buffer in L2 before read in L2
[614]1390        _mmc_inval( ker_buf_paddr, NIC_CONTAINER_SIZE );
[449]1391
[459]1392        // transfer data from kernel buffer to user buffer
[614]1393        _physical_memcpy( usr_buf_paddr, 
1394                          ker_buf_paddr, 
[478]1395                          NIC_CONTAINER_SIZE );
1396#if GIET_DEBUG_NIC
[547]1397_printf("\n[GIET DEBUG NIC] Task %d in _sys_nic_move() transfer kernel buffer %l\n"
1398        " to user buffer %l at cycle %d\n",
[614]1399        thread , ker_buf_paddr , usr_buf_paddr , _get_proctime() );
[478]1400#endif
[449]1401
[459]1402    }
[494]1403    else                      // TX transfer
[459]1404    {
1405        // transfer data from user buffer to kernel buffer
[614]1406        _physical_memcpy( ker_buf_paddr, 
1407                          usr_buf_paddr, 
[478]1408                          NIC_CONTAINER_SIZE );
[449]1409
[459]1410        // sync kernel buffer in L2 after write in L2
[614]1411        _mmc_sync( ker_buf_paddr, NIC_CONTAINER_SIZE );
[478]1412
1413#if GIET_DEBUG_NIC
1414_printf("\n[GIET DEBUG NIC] Task %d in _sys_nic_move() transfer "
1415        "user buffer %l to kernel buffer %l at cycle %d\n",
[614]1416        thread , usr_buf_paddr , ker_buf_paddr , _get_proctime() );
[478]1417#endif
1418
[459]1419    }
1420
[478]1421    // update kernel chbuf status
[614]1422    if ( is_rx ) _physical_write ( ker_sts_paddr, 0 );
1423    else         _physical_write ( ker_sts_paddr, 0x1 );
[459]1424
1425    // sync kernel chbuf in L2 after write in L2
[614]1426    _mmc_sync( ker_sts_paddr, 4 );
[459]1427
1428#if GIET_DEBUG_NIC
[478]1429_printf("\n[GIET DEBUG NIC] Task %d get buffer %d  and exit _sys_nic_move() at cycle %d\n",
1430        thread , index , _get_proctime() );
[459]1431#endif
1432
[440]1433    return 0;
[449]1434} // end _sys_nic_move()
[440]1435
[494]1436
[449]1437////////////////////////////////////////
[489]1438int _sys_nic_stop( unsigned int is_rx,
1439                   unsigned int channel )
[440]1440{
[449]1441    unsigned int nic_channel;
1442    unsigned int cma_channel;
[440]1443
[449]1444    // get NIC channel index and CMA channel index
1445    if ( is_rx )
[440]1446    {
[449]1447        nic_channel = _get_context_slot( CTX_NIC_RX_ID );
1448        cma_channel = _get_context_slot( CTX_CMA_RX_ID );
[440]1449    }
[449]1450    else
1451    {
1452        nic_channel = _get_context_slot( CTX_NIC_TX_ID );
1453        cma_channel = _get_context_slot( CTX_CMA_TX_ID );
1454    }
[440]1455
[494]1456    // check NIC and CMA channels index
[489]1457    if ( nic_channel != channel )
[440]1458    {
[494]1459        _printf("\n[GIET_ERROR] in _sys_nic_stop(): illegal NIC channel\n");
[440]1460        return -1;
1461    }
[449]1462    if ( cma_channel >= NB_CMA_CHANNELS )
[440]1463    {
[489]1464        _printf("\n[GIET_ERROR] in _sys_nic_stop(): illegal CMA channel\n");
[440]1465        return -1;
1466    }
1467
[449]1468    // desactivates the NIC channel
1469    _nic_channel_stop( nic_channel, is_rx );
[440]1470
[449]1471    // desactivates the CMA channel
[505]1472    _cma_set_register( cma_channel, CHBUF_RUN , 0 );
[449]1473
[440]1474    return 0;
[494]1475}  // end _sys_nic_stop()
[440]1476
[459]1477////////////////////////////////////////
[489]1478int _sys_nic_clear( unsigned int is_rx,
1479                    unsigned int channel )
[459]1480{
1481    unsigned int nic_channel;
1482
1483    // get NIC channel
1484    if ( is_rx )  nic_channel = _get_context_slot( CTX_NIC_RX_ID );
1485    else          nic_channel = _get_context_slot( CTX_NIC_TX_ID );
1486
[489]1487    if ( nic_channel != channel )
[459]1488    {
[489]1489        _printf("\n[GIET_ERROR] in _sys_nic_clear(): illegal NIC channel\n");
[459]1490        return -1;
1491    }
1492
1493    if ( is_rx )
1494    {
1495        _nic_set_global_register( NIC_G_NPKT_RX_G2S_RECEIVED       , 0 );
1496        _nic_set_global_register( NIC_G_NPKT_RX_DES_TOO_SMALL      , 0 );
1497        _nic_set_global_register( NIC_G_NPKT_RX_DES_TOO_BIG        , 0 );
1498        _nic_set_global_register( NIC_G_NPKT_RX_DES_MFIFO_FULL     , 0 );
1499        _nic_set_global_register( NIC_G_NPKT_RX_DES_CRC_FAIL       , 0 );
1500        _nic_set_global_register( NIC_G_NPKT_RX_DISPATCH_RECEIVED  , 0 );
1501        _nic_set_global_register( NIC_G_NPKT_RX_DISPATCH_BROADCAST , 0 );
1502        _nic_set_global_register( NIC_G_NPKT_RX_DISPATCH_DST_FAIL  , 0 );
1503        _nic_set_global_register( NIC_G_NPKT_RX_DISPATCH_CH_FULL   , 0 );
1504    } 
1505    else
1506    {
1507        _nic_set_global_register( NIC_G_NPKT_TX_DISPATCH_RECEIVED  , 0 );
1508        _nic_set_global_register( NIC_G_NPKT_TX_DISPATCH_TRANSMIT  , 0 );
1509        _nic_set_global_register( NIC_G_NPKT_TX_DISPATCH_TOO_BIG   , 0 );
1510        _nic_set_global_register( NIC_G_NPKT_TX_DISPATCH_TOO_SMALL , 0 );
1511        _nic_set_global_register( NIC_G_NPKT_TX_DISPATCH_SRC_FAIL  , 0 );
1512        _nic_set_global_register( NIC_G_NPKT_TX_DISPATCH_BYPASS    , 0 );
1513        _nic_set_global_register( NIC_G_NPKT_TX_DISPATCH_BROADCAST , 0 );
1514    }
1515    return 0;
[494]1516}  // en _sys_nic_clear()
[459]1517
1518////////////////////////////////////////
[489]1519int _sys_nic_stats( unsigned int is_rx,
1520                    unsigned int channel )
[459]1521{
1522    unsigned int nic_channel;
1523
1524    // get NIC channel
1525    if ( is_rx )  nic_channel = _get_context_slot( CTX_NIC_RX_ID );
1526    else          nic_channel = _get_context_slot( CTX_NIC_TX_ID );
1527
[489]1528    if ( nic_channel != channel )
[459]1529    {
[489]1530        _printf("\n[GIET_ERROR] in _sys_nic_stats(): illegal NIC channel\n");
[459]1531        return -1;
1532    }
1533
1534    if ( is_rx )
1535    {
1536        unsigned int received   = _nic_get_global_register( NIC_G_NPKT_RX_G2S_RECEIVED       );
1537        unsigned int too_small  = _nic_get_global_register( NIC_G_NPKT_RX_DES_TOO_SMALL      );
1538        unsigned int too_big    = _nic_get_global_register( NIC_G_NPKT_RX_DES_TOO_BIG        );
1539        unsigned int fifo_full  = _nic_get_global_register( NIC_G_NPKT_RX_DES_MFIFO_FULL     );
1540        unsigned int crc_fail   = _nic_get_global_register( NIC_G_NPKT_RX_DES_CRC_FAIL       );
1541        unsigned int broadcast  = _nic_get_global_register( NIC_G_NPKT_RX_DISPATCH_BROADCAST );
1542        unsigned int dst_fail   = _nic_get_global_register( NIC_G_NPKT_RX_DISPATCH_DST_FAIL  );
1543        unsigned int ch_full    = _nic_get_global_register( NIC_G_NPKT_RX_DISPATCH_CH_FULL   );
1544
1545        _printf("\n### Network Controller RX Statistics ###\n"
1546                "- packets received : %d\n"
1547                "- too small        : %d\n"
1548                "- too big          : %d\n"
1549                "- fifo full        : %d\n" 
1550                "- crc fail         : %d\n" 
1551                "- dst mac fail     : %d\n" 
1552                "- channel full     : %d\n" 
1553                "- broadcast        : %d\n",
1554                received,
1555                too_small,
1556                too_big,
1557                fifo_full,
1558                crc_fail,
1559                dst_fail,
1560                ch_full,
1561                broadcast );
1562    } 
1563    else
1564    {
1565        unsigned int received   = _nic_get_global_register( NIC_G_NPKT_TX_DISPATCH_RECEIVED  );
1566        unsigned int too_big    = _nic_get_global_register( NIC_G_NPKT_TX_DISPATCH_TOO_BIG   );
1567        unsigned int too_small  = _nic_get_global_register( NIC_G_NPKT_TX_DISPATCH_TOO_SMALL );
1568        unsigned int src_fail   = _nic_get_global_register( NIC_G_NPKT_TX_DISPATCH_SRC_FAIL  );
1569        unsigned int bypass     = _nic_get_global_register( NIC_G_NPKT_TX_DISPATCH_BYPASS    );
1570        unsigned int broadcast  = _nic_get_global_register( NIC_G_NPKT_TX_DISPATCH_BROADCAST );
1571
1572        _printf("\n### Network Controller TX Statistics ###\n"
1573                "- packets received : %d\n"
1574                "- too small        : %d\n"
1575                "- too big          : %d\n"
1576                "- src mac fail     : %d\n" 
1577                "- bypass           : %d\n" 
1578                "- broadcast        : %d\n",
1579                received,
1580                too_big,
1581                too_small,
1582                src_fail,
1583                bypass,
1584                broadcast );
1585    }
1586    return 0;
[494]1587}  // end _sys_nic_stats()
[459]1588
[440]1589/////////////////////////////////////////////////////////////////////////////////////////
1590//    FBF related syscall handlers
1591/////////////////////////////////////////////////////////////////////////////////////////
1592
1593/////////////////////////////////////////////
1594int _sys_fbf_sync_write( unsigned int offset,
1595                         void*        buffer,
1596                         unsigned int length )
1597{
1598    char* fbf_address = (char *)SEG_FBF_BASE + offset;
1599    memcpy( fbf_address, buffer, length);
1600
1601    return 0;
1602}
1603
1604/////////////////////////////////////////////
1605int _sys_fbf_sync_read(  unsigned int offset,
1606                         void*        buffer,
1607                         unsigned int length )
1608{
1609    char* fbf_address = (char *)SEG_FBF_BASE + offset;
1610    memcpy( buffer, fbf_address, length);
1611
1612    return 0;
1613}
1614
1615////////////////////////
1616int _sys_fbf_cma_alloc()
1617{
1618   // get a new CMA channel index
[459]1619    unsigned int channel = _atomic_increment( &_cma_channel_allocator, 1 );
[440]1620
1621    if ( channel >= NB_CMA_CHANNELS )
1622    {
1623        _printf("\n[GIET ERROR] in _sys_fbf_cma_alloc() : not enough CMA channels\n");
1624        return -1;
1625    }
1626    else
1627    {
[449]1628        _set_context_slot( CTX_CMA_FB_ID, channel );
1629        return 0;
[440]1630    }
1631} // end sys_fbf_cma_alloc()
1632
[614]1633
[648]1634///////////////////////////////////////////////////
1635int _sys_fbf_cma_init_buf( void*        buf0_vbase, 
1636                           void*        buf1_vbase, 
1637                           void*        sts0_vaddr,
1638                           void*        sts1_vaddr )
[440]1639{
1640#if NB_CMA_CHANNELS > 0
1641
1642    unsigned int       vaddr;           // virtual address
[528]1643    unsigned int       flags;           // for _v2p_translate()
[614]1644    unsigned long long fbf_paddr;       // fbf physical address
1645    unsigned long long fbf_sts_paddr;   // fbf status physical address
1646    unsigned long long buf0_pbase;      // buffer 0 base physical address
1647    unsigned long long sts0_paddr;      // buffer 0 status physical address
1648    unsigned long long buf1_pbase;      // buffer 1 base physical address
1649    unsigned long long sts1_paddr;      // buffer 1 status physical address
[440]1650
1651    // get channel index
[449]1652    unsigned int channel = _get_context_slot( CTX_CMA_FB_ID );
[440]1653
1654    if ( channel >= NB_CMA_CHANNELS )
1655    {
[648]1656        _printf("\n[GIET ERROR] in _sys_fbf_cma_init_buf() : CMA channel index too large\n");
[440]1657        return -1;
1658    }
1659
1660#if GIET_DEBUG_FBF_CMA
[614]1661_printf("\n[FBF_CMA DEBUG] enters _sys_fbf_cma_init_buf()\n"
1662        " - channel           = %d\n"
1663        " - buf0        vbase = %x\n"
1664        " - buf1        vbase = %x\n"
1665        " - sts0        vaddr = %x\n"
1666        " - sts1        vaddr = %x\n",
[440]1667        channel,
[614]1668        (unsigned int)buf0_vbase,
1669        (unsigned int)buf1_vbase,
1670        (unsigned int)sts0_vaddr,
1671        (unsigned int)sts1_vaddr );
[440]1672#endif
1673
[614]1674    // checking user buffers virtual addresses alignment
1675    if ( ((unsigned int)buf0_vbase & 0x3F) || 
1676         ((unsigned int)buf1_vbase & 0x3F) ) 
[440]1677    {
[648]1678        _printf("\n[GIET ERROR] in _sys_fbf_cma_init_buf() : user buffer not aligned\n");
[440]1679        return -1;
1680    }
1681
[614]1682    // checking user buffers status virtual addresses alignment
1683    if ( ((unsigned int)sts0_vaddr & 0x3F) ||
1684         ((unsigned int)sts1_vaddr & 0x3F) )
1685    {
[648]1686        _printf("\n[GIET ERROR] in _sys_fbf_cma_init_buf() : user status not aligned\n");
[614]1687        return -1;
1688    }
1689
[440]1690    // compute frame buffer physical address and initialize _fbf_chbuf[channel]
[528]1691    vaddr = (unsigned int)SEG_FBF_BASE;
[614]1692    fbf_paddr = _v2p_translate( vaddr , &flags );
1693    vaddr = (unsigned int)&_fbf_status[channel];
1694    fbf_sts_paddr = _v2p_translate( vaddr , &flags );
[440]1695
[614]1696    _fbf_chbuf[channel].fbf_desc =
1697        (unsigned long long) ((fbf_sts_paddr & 0xFFFFFFFFULL) >> 6) +
1698        (((fbf_paddr & 0xFFFFFFFFULL) >> 6 ) << 26);
1699
[528]1700    // Compute user buffer 0 physical addresses and intialize _fbf_chbuf[channel]
[614]1701    vaddr = (unsigned int)buf0_vbase;
1702    buf0_pbase = _v2p_translate( vaddr , &flags );
[440]1703    if ((flags & PTE_U) == 0) 
1704    {
[648]1705        _printf("\n[GIET ERROR] in _sys_fbf_cma_init_buf() : buf0 not in user space\n");
[440]1706        return -1;
1707    }
1708
[614]1709    vaddr = (unsigned int)sts0_vaddr;
1710    sts0_paddr = _v2p_translate( vaddr , &flags );
1711    if ((flags & PTE_U) == 0) 
1712    {
[648]1713        _printf("\n[GIET ERROR] in _sys_fbf_cma_init_buf() : sts0 not in user space\n");
[614]1714        return -1;
1715    }
1716
1717    _fbf_chbuf[channel].buf0_desc = 
1718        (unsigned long long) ((sts0_paddr & 0xFFFFFFFFULL) >> 6) +
1719        (((buf0_pbase & 0xFFFFFFFFULL) >> 6 ) << 26);
1720
[528]1721    // Compute user buffer 1 physical addresses and intialize _fbf_chbuf[channel]
[614]1722    vaddr = (unsigned int)buf1_vbase;
1723    buf1_pbase = _v2p_translate( vaddr , &flags );
[440]1724    if ((flags & PTE_U) == 0) 
1725    {
[648]1726        _printf("\n[GIET ERROR] in _sys_fbf_cma_init_buf() : buf1 not in user space\n");
[440]1727        return -1;
1728    }
1729
[614]1730    vaddr = (unsigned int)sts1_vaddr;
1731    sts1_paddr = _v2p_translate( vaddr , &flags );
1732    if ((flags & PTE_U) == 0) 
1733    {
[648]1734        _printf("\n[GIET ERROR] in _sys_fbf_cma_init_buf() : sts1 not in user space\n");
[614]1735        return -1;
1736    }
[440]1737
[614]1738    _fbf_chbuf[channel].buf1_desc = 
1739        (unsigned long long) ((sts1_paddr & 0xFFFFFFFFULL) >> 6) +
1740        (((buf1_pbase & 0xFFFFFFFFULL) >> 6 ) << 26);
1741
[505]1742    // Compute and register physical adress of the fbf_chbuf descriptor
[528]1743    vaddr = (unsigned int)&_fbf_chbuf[channel];
1744    _fbf_chbuf_paddr[channel] = _v2p_translate( vaddr , &flags );
[440]1745 
[614]1746#if GIET_DEBUG_FBF_CMA
1747_printf(" - fbf         pbase = %l\n"
1748        " - fbf status  paddr = %l\n"
1749        " - buf0        pbase = %l\n"
1750        " - buf0 status paddr = %l\n" 
1751        " - buf1        pbase = %l\n"
1752        " - buf0 status paddr = %l\n" 
1753        " - chbuf       pbase = %l\n",
1754        fbf_paddr,
1755        fbf_sts_paddr,
1756        buf0_pbase,
1757        sts0_paddr,
1758        buf1_pbase,
1759        sts1_paddr,
1760        _fbf_chbuf_paddr[channel] );
1761#endif
1762
1763    return 0;
1764
1765#else
1766
1767    _printf("\n[GIET ERROR] in _sys_fbf_cma_init_buf() : NB_CMA_CHANNELS = 0\n");
1768    return -1;
1769
1770#endif 
1771} // end sys_fbf_cma_init_buf()
1772
1773////////////////////////////////////////////
1774int _sys_fbf_cma_start( unsigned int length ) 
1775{
1776#if NB_CMA_CHANNELS > 0
1777
1778    // get channel index
1779    unsigned int channel = _get_context_slot( CTX_CMA_FB_ID );
1780
1781    if ( channel >= NB_CMA_CHANNELS )
1782    {
1783        _printf("\n[GIET ERROR] in _fbf_cma_start() : CMA channel index too large\n");
1784        return -1;
1785    }
1786
1787    // check buffers initialization
1788    if ( ( _fbf_chbuf[channel].buf0_desc == 0x0ULL ) &&
1789         ( _fbf_chbuf[channel].buf1_desc == 0x0ULL) &&
1790         ( _fbf_chbuf[channel].fbf_desc == 0x0ULL) )
1791    {
1792        _printf("\n[GIET ERROR] in _sys_fbf_cma_start() :\n"
1793                "Buffer initialization has not been done\n");
1794        return -1;
1795    }
1796
1797    // initializes buffer length
1798    _fbf_chbuf[channel].length = length;
1799
[440]1800    if ( USE_IOB )
1801    {
[505]1802        // SYNC request for fbf_chbuf descriptor
1803        _mmc_sync( _fbf_chbuf_paddr[channel] , sizeof( fbf_chbuf_t ) );
[440]1804    }
1805
[505]1806    // start CMA transfer
1807    unsigned long long paddr = _fbf_chbuf_paddr[channel];
1808    unsigned int src_chbuf_paddr_lsb = (unsigned int)(paddr & 0xFFFFFFFF);
1809    unsigned int src_chbuf_paddr_ext = (unsigned int)(paddr >> 32);
[614]1810    unsigned int dst_chbuf_paddr_lsb = src_chbuf_paddr_lsb + 16;
[505]1811    unsigned int dst_chbuf_paddr_ext = src_chbuf_paddr_ext;
1812
1813    _cma_set_register( channel, CHBUF_SRC_DESC , src_chbuf_paddr_lsb );
1814    _cma_set_register( channel, CHBUF_SRC_EXT  , src_chbuf_paddr_ext );
1815    _cma_set_register( channel, CHBUF_SRC_NBUFS, 2 );
1816    _cma_set_register( channel, CHBUF_DST_DESC , dst_chbuf_paddr_lsb );
1817    _cma_set_register( channel, CHBUF_DST_EXT  , dst_chbuf_paddr_ext );
1818    _cma_set_register( channel, CHBUF_DST_NBUFS, 1 );
1819    _cma_set_register( channel, CHBUF_BUF_SIZE , length );
1820    _cma_set_register( channel, CHBUF_PERIOD   , 300 );
1821    _cma_set_register( channel, CHBUF_RUN      , 1 );
1822
[440]1823    return 0;
1824
1825#else
1826
1827    _printf("\n[GIET ERROR] in _sys_fbf_cma_start() : NB_CMA_CHANNELS = 0\n");
1828    return -1;
1829
1830#endif
1831} // end _sys_fbf_cma_start()
1832
1833/////////////////////////////////////////////////////
1834int _sys_fbf_cma_display( unsigned int buffer_index )
1835{
1836#if NB_CMA_CHANNELS > 0
1837
[505]1838    volatile unsigned int full = 1;
[440]1839
1840    // get channel index
[449]1841    unsigned int channel = _get_context_slot( CTX_CMA_FB_ID );
[440]1842
1843    if ( channel >= NB_CMA_CHANNELS )
1844    {
[505]1845        _printf("\n[GIET ERROR] in _sys_fbf_cma_display() : "
1846                "CMA channel index too large\n");
[440]1847        return -1;
1848    }
1849
[505]1850    // get fbf_chbuf descriptor pointer
1851    fbf_chbuf_t* pdesc = &_fbf_chbuf[channel];     
1852
[440]1853#if GIET_DEBUG_FBF_CMA
1854_printf("\n[FBF_CMA DEBUG] enters _sys_fb_cma_display()\n"
[614]1855        " - cma channel      = %d\n"
1856        " - buffer index     = %d\n"
1857        " - buf0_desc value  = %l\n"
1858        " - buf1_desc value  = %l\n"
1859        " - fbf_desc  value  = %l\n",
[505]1860        channel , buffer_index,
[614]1861        _fbf_chbuf[channel].buf0_desc,
1862        _fbf_chbuf[channel].buf1_desc,
1863        _fbf_chbuf[channel].fbf_desc );
[440]1864#endif
1865
[614]1866    unsigned long long buf_sts_paddr;
1867    unsigned long long buf_paddr;
1868    unsigned long long fbf_sts_paddr;
1869
[478]1870    if ( buffer_index == 0 )    // user buffer 0
1871    {
[614]1872        buf_sts_paddr =
1873            ((pdesc->buf0_desc & 0xFFF0000000000000ULL) >> 20) + // compute address extension
1874            ((pdesc->buf0_desc & 0x3FFFFFFULL) << 6);            // compute 32 LSB of the address
[505]1875
[614]1876        buf_paddr =
1877            (pdesc->buf0_desc & 0xFFFFFFFFFC000000ULL) >> 20;  // compute the entire address
[440]1878    }
[478]1879    else                        // user buffer 1
1880    {
[614]1881        buf_sts_paddr =
1882            ((pdesc->buf1_desc & 0xFFF0000000000000ULL) >> 20) +
1883            ((pdesc->buf1_desc & 0x3FFFFFFULL) << 6);
[505]1884
[614]1885        buf_paddr =
1886            (pdesc->buf1_desc & 0xFFFFFFFFFC000000ULL) >> 20;
1887    }
[478]1888
[614]1889    fbf_sts_paddr =
1890        ((pdesc->fbf_desc & 0xFFF0000000000000ULL) >> 20) +
1891        ((pdesc->fbf_desc & 0x3FFFFFFULL) << 6);
[440]1892
[614]1893#if GIET_DEBUG_FBF_CMA
1894_printf(" - fbf status paddr = %l\n"
1895        " - buf        pbase = %l\n"
1896        " - buf status paddr = %l\n",
1897        fbf_sts_paddr,
1898        buf_paddr,
1899        buf_sts_paddr );
1900#endif
1901       
1902    // waiting user buffer released by the CMA component)
1903    while ( full )
1904    { 
[648]1905        // INVAL L2 cache copy of user buffer status     
[614]1906        // because it has been modified in RAM by the CMA component
1907        _mmc_inval( buf_sts_paddr , 4 );       
[440]1908
[614]1909        full = _physical_read( buf_sts_paddr );
[440]1910    }
1911
[614]1912    // SYNC request for the user buffer, because
1913    // it will be read from XRAM by the CMA component
1914    _mmc_sync( buf_paddr , pdesc->length );
[440]1915
[614]1916    // set user buffer status
1917    _physical_write( buf_sts_paddr, 0x1 );
1918
1919    // reset fbf buffer status
1920    _physical_write( fbf_sts_paddr, 0x0 );
1921   
1922    // SYNC request, because these buffer descriptors
1923    // will be read from XRAM by the CMA component
1924    _mmc_sync( buf_sts_paddr, 4 );
1925    _mmc_sync( fbf_sts_paddr, 4 );
1926
[440]1927    return 0;
1928
1929#else
1930
1931    _printf("\n[GIET ERROR] in _sys_fbf_cma_display() : no CMA channel allocated\n");
1932    return -1;
1933
1934#endif
1935} // end _sys_fbf_cma_display()
1936
1937///////////////////////
1938int _sys_fbf_cma_stop()
1939{
1940#if NB_CMA_CHANNELS > 0
1941
1942    // get channel index
[449]1943    unsigned int channel = _get_context_slot( CTX_CMA_FB_ID );
[440]1944
1945    if ( channel >= NB_CMA_CHANNELS )
1946    {
1947        _printf("\n[GIET ERROR] in _sys_fbf_cma_stop() : CMA channel index too large\n");
1948        return -1;
1949    }
1950
1951    // Desactivate CMA channel
[505]1952    _cma_set_register( channel, CHBUF_RUN, 0 );
[440]1953
1954    return 0;
1955
1956#else
1957
1958    _printf("\n[GIET ERROR] in _sys_fbf_cma_stop() : no CMA channel allocated\n");
1959    return -1;
1960
1961#endif
1962} // end _sys_fbf_cma_stop()
1963
1964
1965//////////////////////////////////////////////////////////////////////////////
1966//           Miscelaneous syscall handlers
1967//////////////////////////////////////////////////////////////////////////////
1968
1969///////////////
1970int _sys_ukn() 
1971{
1972    _printf("\n[GIET ERROR] Undefined System Call / EPC = %x\n", _get_epc() );
1973    return -1;
1974}
1975
1976////////////////////////////////////
1977int _sys_proc_xyp( unsigned int* x,
1978                   unsigned int* y,
1979                   unsigned int* p )
1980{
[428]1981    unsigned int gpid = _get_procid();  // global processor index from CPO register
1982
1983    *x = (gpid >> (Y_WIDTH + P_WIDTH)) & ((1<<X_WIDTH)-1);
1984    *y = (gpid >> P_WIDTH) & ((1<<Y_WIDTH)-1);
1985    *p = gpid & ((1<<P_WIDTH)-1);
[440]1986
1987    return 0;
[428]1988}
[440]1989
1990//////////////////////////////////
1991int _sys_task_exit( char* string ) 
[258]1992{
[294]1993    unsigned int date       = _get_proctime();
[428]1994
1995    unsigned int gpid       = _get_procid();
1996    unsigned int cluster_xy = gpid >> P_WIDTH;
[294]1997    unsigned int y          = cluster_xy & ((1<<Y_WIDTH)-1);
1998    unsigned int x          = cluster_xy >> Y_WIDTH;
[629]1999    unsigned int p          = gpid & ((1<<P_WIDTH)-1);
[428]2000
[629]2001    unsigned int ltid       = _get_context_slot(CTX_LTID_ID);
[258]2002
[440]2003    // print exit message
[294]2004    _printf("\n[GIET] Exit task %d on processor[%d,%d,%d] at cycle %d"
2005            "\n       Cause : %s\n\n",
[629]2006            ltid, x, y, p, date, string );
[258]2007
[629]2008    // set NORUN_MASK_TASK bit (non runnable state)
2009    static_scheduler_t*  psched  = (static_scheduler_t*)_schedulers[x][y][p];
2010    unsigned int*        ptr     = &psched->context[ltid][CTX_NORUN_ID];
2011    _atomic_or( ptr , NORUN_MASK_TASK );
[258]2012
2013    // deschedule
[528]2014    _sys_context_switch();
[440]2015
2016    return 0;
[258]2017} 
2018
[528]2019/////////////////////////
2020int _sys_context_switch() 
[258]2021{
[440]2022    unsigned int save_sr;
[258]2023
[440]2024    _it_disable( &save_sr );
2025    _ctx_switch();
2026    _it_restore( &save_sr );
2027
2028    return 0;
[258]2029}
2030
[440]2031////////////////////////
2032int _sys_local_task_id()
[258]2033{
2034    return _get_context_slot(CTX_LTID_ID);
2035}
2036
[440]2037/////////////////////////
2038int _sys_global_task_id()
[258]2039{
2040    return _get_context_slot(CTX_GTID_ID);
2041}
2042
[440]2043////////////////////
2044int _sys_thread_id()
[267]2045{
2046    return _get_context_slot(CTX_TRDID_ID);
2047}
2048
[494]2049////////////////////////////////////////////
2050int _sys_procs_number( unsigned int* x_size,
2051                       unsigned int* y_size,
2052                       unsigned int* nprocs )
[258]2053{
[494]2054    mapping_header_t * header   = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
[440]2055    mapping_cluster_t * cluster = _get_cluster_base(header);
2056
[494]2057    unsigned int x;
2058    unsigned int y;
2059    unsigned int okmin = 1;
2060    unsigned int okmax = 1;
2061
2062    // compute max values
2063    unsigned int xmax  = header->x_size;
2064    unsigned int ymax  = header->y_size;
2065    unsigned int procs = cluster[0].procs;
2066
2067    // check the (ymax-1) lower rows
2068    for ( y = 0 ; y < ymax-1 ; y++ )
[440]2069    {
[494]2070        for ( x = 0 ; x < xmax ; x++ )
2071        {
2072            if (cluster[x*ymax+y].procs != procs ) okmin = 0;
2073        }
[440]2074    }
[494]2075
2076    // check the upper row
2077    for ( x = 0 ; x < xmax ; x++ )
[440]2078    {
[494]2079        if (cluster[x*ymax+ymax-1].procs != procs ) okmax = 0;
[440]2080    }
[494]2081
2082    // return values
2083    if ( okmin && okmax )
2084    {
2085        *x_size = xmax;
2086        *y_size = ymax;
2087        *nprocs = procs;
2088    }
2089    else if ( okmin )
2090    {
2091        *x_size = xmax;
2092        *y_size = ymax-1;
2093        *nprocs = procs;
2094    }
2095    else
2096    {
2097        *x_size = 0;
2098        *y_size = 0;
2099        *nprocs = 0;
2100    }
2101    return 0;
[440]2102}
2103
2104///////////////////////////////////////////////////////
[516]2105int _sys_vseg_get_vbase( char*             vspace_name, 
2106                         char*             vseg_name, 
[440]2107                         unsigned int*     vbase ) 
2108{
[322]2109    mapping_header_t * header = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
[258]2110    mapping_vspace_t * vspace = _get_vspace_base(header);
[516]2111    mapping_vseg_t * vseg     = _get_vseg_base(header);
[258]2112
2113    unsigned int vspace_id;
[516]2114    unsigned int vseg_id;
[258]2115
2116    // scan vspaces
2117    for (vspace_id = 0; vspace_id < header->vspaces; vspace_id++) 
2118    {
2119        if (_strncmp( vspace[vspace_id].name, vspace_name, 31) == 0) 
2120        {
[516]2121            // scan vsegs
2122            for (vseg_id = vspace[vspace_id].vseg_offset; 
2123                 vseg_id < (vspace[vspace_id].vseg_offset + vspace[vspace_id].vsegs); 
2124                 vseg_id++) 
[258]2125            {
[516]2126                if (_strncmp(vseg[vseg_id].name, vseg_name, 31) == 0) 
[258]2127                {
[516]2128                    *vbase = vseg[vseg_id].vbase;
[258]2129                    return 0;
2130                }
2131            } 
2132        }
2133    } 
[440]2134    return -1;    // not found
[258]2135}
2136
[440]2137/////////////////////////////////////////////////////////
[516]2138int _sys_vseg_get_length( char*         vspace_name, 
2139                          char*         vseg_name,
[440]2140                          unsigned int* length ) 
[258]2141{
[440]2142    mapping_header_t * header = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
2143    mapping_vspace_t * vspace = _get_vspace_base(header);
[516]2144    mapping_vseg_t * vseg     = _get_vseg_base(header);
[258]2145
[440]2146    unsigned int vspace_id;
[516]2147    unsigned int vseg_id;
[440]2148
2149    // scan vspaces
2150    for (vspace_id = 0; vspace_id < header->vspaces; vspace_id++) 
[258]2151    {
[440]2152        if (_strncmp( vspace[vspace_id].name, vspace_name, 31) == 0) 
2153        {
[516]2154            // scan vsegs
2155            for (vseg_id = vspace[vspace_id].vseg_offset; 
2156                 vseg_id < (vspace[vspace_id].vseg_offset + vspace[vspace_id].vsegs); 
2157                 vseg_id++) 
[440]2158            {
[516]2159                if (_strncmp(vseg[vseg_id].name, vseg_name, 31) == 0) 
[440]2160                {
[516]2161                    *length = vseg[vseg_id].length;
[440]2162                    return 0;
2163                }
2164            } 
2165        }
2166    } 
2167    return -1;    // not found
[258]2168}
2169
[440]2170////////////////////////////////////////
2171int _sys_xy_from_ptr( void*         ptr,
2172                      unsigned int* x,
2173                      unsigned int* y )
[396]2174{
2175    unsigned int flags;
[528]2176    unsigned long long paddr = _v2p_translate( (unsigned int)ptr , &flags );
[396]2177   
[528]2178    *x = (paddr>>36) & 0xF;
2179    *y = (paddr>>32) & 0xF;
[396]2180
2181    return 0;
2182}
2183
[440]2184/////////////////////////////////////////
2185int _sys_heap_info( unsigned int* vaddr, 
2186                    unsigned int* length,
2187                    unsigned int  x,
2188                    unsigned int  y ) 
[258]2189{
[440]2190    mapping_header_t * header  = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
[516]2191    mapping_task_t *   task    = _get_task_base(header);
2192    mapping_vseg_t *   vseg    = _get_vseg_base(header);
2193    mapping_vspace_t * vspace  = _get_vspace_base(header);
[294]2194
[440]2195    unsigned int task_id;
2196    unsigned int vspace_id;
[516]2197    unsigned int vseg_id = 0xFFFFFFFF;
[258]2198
[516]2199    // searching the heap vseg
[440]2200    if ( (x < X_SIZE) && (y < Y_SIZE) )  // searching a task in cluster(x,y)
2201    {
2202        // get vspace global index
2203        vspace_id = _get_context_slot(CTX_VSID_ID);
2204
2205        // scan all tasks in vspace
[516]2206        unsigned int min = vspace[vspace_id].task_offset ;
2207        unsigned int max = min + vspace[vspace_id].tasks ;
[440]2208        for ( task_id = min ; task_id < max ; task_id++ )
2209        {
[516]2210            if ( task[task_id].clusterid == (x * Y_SIZE + y) )
[440]2211            {
[516]2212                vseg_id = task[task_id].heap_vseg_id;
2213                if ( vseg_id != 0xFFFFFFFF ) break;
[440]2214            }
2215        }
2216    }
2217    else                                // searching in the calling task
2218    {
2219        task_id = _get_context_slot(CTX_GTID_ID);
[516]2220        vseg_id = task[task_id].heap_vseg_id;
[440]2221    }
2222
[516]2223    // analysing the vseg_id
2224    if ( vseg_id != 0xFFFFFFFF ) 
[440]2225    {
[516]2226        *vaddr  = vseg[vseg_id].vbase;
2227        *length = vseg[vseg_id].length;
[440]2228        return 0;
2229    }
2230    else 
2231    {
2232        *vaddr  = 0;
2233        *length = 0;
2234        return -1;
2235    }
2236}  // end _sys_heap_info()
2237
2238
[258]2239// Local Variables:
2240// tab-width: 4
2241// c-basic-offset: 4
2242// c-file-offsets:((innamespace . 0)(inline-open . 0))
2243// indent-tabs-mode: nil
2244// End:
2245// vim: filetype=c:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
2246
Note: See TracBrowser for help on using the repository browser.