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

Last change on this file since 750 was 733, checked in by alain, 9 years ago

Modify the system functions associated to hardware coprocessors:
Introduce two explicit arguments "cluster_xy" and "cluster_type"
to allows any task to control a coprocessor located in any cluster.

  • Property svn:executable set to *
File size: 120.6 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>
[707]17#include <elf-types.h>
[258]18#include <utils.h>
[478]19#include <kernel_malloc.h>
[459]20#include <tty0.h>
[396]21#include <vmem.h>
[322]22#include <hard_config.h>
[258]23#include <giet_config.h>
24#include <mapping_info.h>
[547]25#include <irq_handler.h>
[519]26#include <io.h>
[258]27
[709]28#if !defined(X_SIZE)
29# error: You must define X_SIZE in the hard_config.h file
30#endif
31
32#if !defined(Y_SIZE)
33# error: You must define Y_SIZE in the hard_config.h file
34#endif
35
36#if !defined(NB_PROCS_MAX)
37# error: You must define NB_PROCS_MAX in the hard_config.h file
38#endif
39
[322]40#if !defined(SEG_BOOT_MAPPING_BASE)
41# error: You must define SEG_BOOT_MAPPING_BASE in the hard_config.h file
42#endif
43
[449]44#if !defined(NB_TTY_CHANNELS)
45# error: You must define NB_TTY_CHANNELS in the hard_config.h file
46#endif
47
[459]48#if (NB_TTY_CHANNELS < 1)
49# error: NB_TTY_CHANNELS cannot be smaller than 1!
50#endif
51
[449]52#if !defined(NB_TIM_CHANNELS)
53# error: You must define NB_TIM_CHANNELS in the hard_config.h file
54#endif
55
56#if !defined(NB_NIC_CHANNELS)
57# error: You must define NB_NIC_CHANNELS in the hard_config.h file
58#endif
59
60#if !defined(NB_CMA_CHANNELS)
61# error: You must define NB_CMA_CHANNELS in the hard_config.h file
62#endif
63
[478]64#if !defined(GIET_NO_HARD_CC)
65# error: You must define GIET_NO_HARD_CC in the giet_config.h file
[449]66#endif
67
[478]68#if !defined ( GIET_NIC_MAC4 )
69# error: You must define GIET_NIC_MAC4 in the giet_config.h file
[449]70#endif
71
[478]72#if !defined ( GIET_NIC_MAC2 )
73# error: You must define GIET_NIC_MAC2 in the giet_config.h file
[449]74#endif
75
[258]76////////////////////////////////////////////////////////////////////////////
[528]77//        Extern variables
[519]78////////////////////////////////////////////////////////////////////////////
79
[528]80// allocated in tty0.c file.
81extern sqt_lock_t _tty0_sqt_lock;
[519]82
[528]83// allocated in mwr_driver.c file.
84extern simple_lock_t  _coproc_lock[X_SIZE*Y_SIZE];
[556]85extern unsigned int   _coproc_type[X_SIZE*Y_SIZE];
86extern unsigned int   _coproc_info[X_SIZE*Y_SIZE];
87extern unsigned int   _coproc_mode[X_SIZE*Y_SIZE];
88extern unsigned int   _coproc_error[X_SIZE*Y_SIZE];
[709]89extern unsigned int   _coproc_trdid[X_SIZE*Y_SIZE];
[519]90
[528]91// allocated in tty_driver.c file.
[709]92extern tty_fifo_t   _tty_rx_fifo[NB_TTY_CHANNELS];
[528]93
[629]94// allocated in kernel_init.c file
95extern static_scheduler_t* _schedulers[X_SIZE][Y_SIZE][NB_PROCS_MAX]; 
96
[714]97// allocated in bdv_driver.c file
98spin_lock_t  _bdv_lock;
99
[709]100////////////////////////////////////////////////////////////////////////////////
[714]101//     Allocator protecting exclusive access to FBF by a single application.
102// - The number of users in a given application should be set by a single
103//   thread using an _atomic_test_and_set().
104// - The allocator is atomically decremented by each user thread when
105//   the thread exit.   
106////////////////////////////////////////////////////////////////////////////////
107
108__attribute__((section(".kdata")))
109unsigned int _fbf_alloc = 0;
110
111////////////////////////////////////////////////////////////////////////////////
[709]112//     Channel allocators for multi-channels peripherals
113// - The array _***_channel_allocator[channel] defines the number of user
114//   threads for a dynamically allocated channel of peripheral ***.
115// - The array _***_channel_wti[channel] defines the WTI index and the
116//   processor coordinates for the processor receiving the channel WTI.
117////////////////////////////////////////////////////////////////////////////////
[440]118
[709]119#if NB_TTY_CHANNELS
[494]120__attribute__((section(".kdata")))
[709]121unsigned int _tty_channel_alloc[NB_TTY_CHANNELS] = {0};
[494]122
123__attribute__((section(".kdata")))
[709]124unsigned int _tty_channel_wti[NB_TTY_CHANNELS];
125#endif
[494]126
[709]127#if NB_TIM_CHANNELS
[494]128__attribute__((section(".kdata")))
[709]129unsigned int _tim_channel_alloc[NB_TIM_CHANNELS] = {0};
[494]130
131__attribute__((section(".kdata")))
[709]132unsigned int _tim_channel_wti[NB_TIM_CHANNELS];
133#endif
[494]134
[709]135#if NB_CMA_CHANNELS
[494]136__attribute__((section(".kdata")))
[709]137unsigned int _cma_channel_alloc[NB_CMA_CHANNELS] = {0};
[440]138
[709]139__attribute__((section(".kdata")))
140unsigned int _cma_channel_wti[NB_CMA_CHANNELS];
141#endif
142
143#if NB_NIC_CHANNELS
144__attribute__((section(".kdata")))
145unsigned int _nic_rx_channel_alloc[NB_NIC_CHANNELS] = {0};
146
147__attribute__((section(".kdata")))
148unsigned int _nic_rx_channel_wti[NB_NIC_CHANNELS];
149
150__attribute__((section(".kdata")))
151unsigned int _nic_tx_channel_alloc[NB_NIC_CHANNELS] = {0};
152
153__attribute__((section(".kdata")))
154unsigned int _nic_tx_channel_wti[NB_NIC_CHANNELS];
155#endif
156
[440]157////////////////////////////////////////////////////////////////////////////
[614]158//     NIC_RX and NIC_TX kernel chbuf arrays
[449]159////////////////////////////////////////////////////////////////////////////
160
[494]161__attribute__((section(".kdata")))
[725]162nic_chbuf_t  _nic_ker_rx_chbuf[NB_NIC_CHANNELS] __attribute__((aligned(64)));
[459]163
[494]164__attribute__((section(".kdata")))
[725]165nic_chbuf_t  _nic_ker_tx_chbuf[NB_NIC_CHANNELS] __attribute__((aligned(64)));
[459]166
[478]167////////////////////////////////////////////////////////////////////////////
[725]168//     FBF related chbuf
169// The physical address of this chbuf is required for L2 cache sync.
[478]170////////////////////////////////////////////////////////////////////////////
[459]171
[494]172__attribute__((section(".kdata")))
[725]173fbf_chbuf_t          _fbf_ker_chbuf  __attribute__((aligned(64)));
[459]174
[494]175__attribute__((section(".kdata")))
[725]176unsigned long long   _fbf_chbuf_paddr;
[478]177
[449]178////////////////////////////////////////////////////////////////////////////
[258]179//    Initialize the syscall vector with syscall handlers
180// Note: This array must be synchronised with the define in file stdio.h
181////////////////////////////////////////////////////////////////////////////
[494]182
183__attribute__((section(".kdata")))
[258]184const void * _syscall_vector[64] = 
185{
[556]186    &_sys_proc_xyp,                  /* 0x00 */
187    &_get_proctime,                  /* 0x01 */
[709]188    &_sys_procs_number,              /* 0x02 */
189    &_sys_xy_from_ptr,               /* 0x03 */
190    &_sys_ukn,                       /* 0x04 */
[714]191    &_sys_vseg_get_vbase,            /* 0x05 */
192    &_sys_vseg_get_length,           /* 0x06 */
[556]193    &_sys_heap_info,                 /* 0x07 */
[714]194    &_sys_fbf_size,                  /* 0x08 */
195    &_sys_fbf_alloc,                 /* 0x09 */ 
[556]196    &_sys_fbf_cma_alloc,             /* 0x0A */
[614]197    &_sys_fbf_cma_init_buf,          /* 0x0B */
198    &_sys_fbf_cma_start,             /* 0x0C */
199    &_sys_fbf_cma_display,           /* 0x0D */
200    &_sys_fbf_cma_stop,              /* 0x0E */
[725]201    &_sys_fbf_cma_check,             /* 0x0F */
[258]202
[709]203    &_sys_applications_status,       /* 0x10 */
[614]204    &_sys_fbf_sync_write,            /* 0x11 */
205    &_sys_fbf_sync_read,             /* 0x12 */
[709]206    &_sys_ukn,                       /* 0x13 */
[556]207    &_sys_tim_alloc,                 /* 0x14 */
208    &_sys_tim_start,                 /* 0x15 */ 
209    &_sys_tim_stop,                  /* 0x16 */
[629]210    &_sys_kill_application,          /* 0x17 */
211    &_sys_exec_application,          /* 0x18 */   
[709]212    &_sys_ukn,                       /* 0x19 */
213    &_sys_pthread_control,           /* 0x1A */
214    &_sys_pthread_yield,             /* 0x1B */
215    &_sys_pthread_kill,              /* 0x1C */
216    &_sys_pthread_create,            /* 0x1D */
217    &_sys_pthread_join,              /* 0x1E */
218    &_sys_pthread_exit,              /* 0x1F */
[258]219
[592]220    &_fat_open,                      /* 0x20 */
[709]221    &_fat_read,                      /* 0x21 */
[592]222    &_fat_write,                     /* 0x22 */
223    &_fat_lseek,                     /* 0x23 */
224    &_fat_file_info,                 /* 0x24 */
[556]225    &_fat_close,                     /* 0x25 */
[592]226    &_fat_remove,                    /* 0x26 */
227    &_fat_rename,                    /* 0x27 */
228    &_fat_mkdir,                     /* 0x28 */
[661]229    &_fat_opendir,                   /* 0x29 */
230    &_fat_closedir,                  /* 0x2A */
231    &_fat_readdir,                   /* 0x2B */
232    &_sys_ukn,                       /* 0x2C */
[556]233    &_sys_ukn,                       /* 0x2D */
234    &_sys_ukn,                       /* 0x2E */
235    &_sys_ukn,                       /* 0x2F */
[258]236
[556]237    &_sys_nic_alloc,                 /* 0x30 */
238    &_sys_nic_start,                 /* 0x31 */
239    &_sys_nic_move,                  /* 0x32 */
240    &_sys_nic_stop,                  /* 0x33 */
241    &_sys_nic_stats,                 /* 0x34 */
242    &_sys_nic_clear,                 /* 0x35 */ 
[709]243    &_sys_tty_write,                 /* 0x36 */
244    &_sys_tty_read,                  /* 0x37 */
245    &_sys_tty_alloc,                 /* 0x38 */
[556]246    &_sys_ukn,                       /* 0x39 */
247    &_sys_ukn,                       /* 0x3A */
248    &_sys_coproc_completed,          /* 0x3B */
249    &_sys_coproc_alloc,              /* 0x3C */
250    &_sys_coproc_channel_init,       /* 0x3D */
251    &_sys_coproc_run,                /* 0x3E */
252    &_sys_coproc_release,            /* 0x3F */
[258]253};
254
[709]255
256//////////////////////////////////////////////////////////////////////////////
257//           Applications related syscall handlers
258//////////////////////////////////////////////////////////////////////////////
259
[707]260////////////////////////////////////////////////////////////////////////
[709]261// This function is called by the _sys_exec_application function
262// to reload all data segments contained in an application.elf file.
[714]263// File checking is minimal, because these segments have already
264// been loaded by the boot code.
[709]265////////////////////////////////////////////////////////////////////////
[707]266static unsigned int _load_writable_segments( mapping_vspace_t*  vspace )
267{
[709]268
269#if GIET_DEBUG_EXEC 
[707]270unsigned int gpid       = _get_procid();
271unsigned int cluster_xy = gpid >> P_WIDTH;
272unsigned int p          = gpid & ((1<<P_WIDTH)-1);
273unsigned int x          = cluster_xy >> Y_WIDTH;
274unsigned int y          = cluster_xy & ((1<<Y_WIDTH)-1);
[709]275if ( _get_proctime() > GIET_DEBUG_EXEC )
[714]276_printf("\n[DEBUG EXEC] _load_writable_segments() at cycle %d\n"
277        "P[%d,%d,%d] enters for %s\n",
278        _get_proctime() , x , y , p , vspace->name );
[707]279#endif
[459]280
[707]281    mapping_header_t*  header  = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
282    mapping_vseg_t*    vseg    = _get_vseg_base(header);
283
[709]284    unsigned int vseg_id;        // vseg index in mapping
285    char         buf[4096];      // buffer to store one cluster
[714]286    unsigned int fd    = 0;      // file descriptor
287    unsigned int found = 0;
[707]288
[709]289    // first scan on vsegs in vspace to find the .elf pathname
[707]290    for (vseg_id = vspace->vseg_offset;
291         vseg_id < (vspace->vseg_offset + vspace->vsegs);
292         vseg_id++)
293    {
[709]294        if( vseg[vseg_id].type == VSEG_TYPE_ELF )
[707]295        {
[709]296            // open the .elf file associated to vspace
[707]297            fd = _fat_open( vseg[vseg_id].binpath , O_RDONLY );
[709]298            if ( fd < 0 ) return 1;
[707]299
[709]300#if GIET_DEBUG_EXEC
301if ( _get_proctime() > GIET_DEBUG_EXEC )
[714]302_printf("\n[DEBUG EXEC] _load_writable_segments() at cycle %d\n"
303        "P[%d,%d,%d] open %s / fd = %d\n", 
304        _get_proctime() , x , y , p , vseg[vseg_id].binpath , fd );
[707]305#endif
[714]306            found = 1;
307            break;
308 
[707]309        }
310    }
[709]311 
[714]312    // check .elf file found
313    if ( found == 0 )
314    {
[733]315        _printf("\n[GIET ERROR] _load_writable_segments() : .elf not found\n");
[714]316        return 1;
317    }
318
[707]319    // load Elf-Header into buffer from .elf file
[709]320    if ( _fat_lseek( fd, 0, SEEK_SET ) < 0 )
321    {
[733]322        _printf("\n[GIET ERROR] _load_writable_segments() : cannot seek\n");
[709]323        _fat_close( fd );
324        return 1;
325    }
326    if ( _fat_read( fd, (unsigned int)buf, 4096, 0 ) < 0 )
327    {
[733]328        _printf("\n[GIET ERROR] _load_writable_segments() : cannot read\n");
[709]329        _fat_close( fd );
330        return 1;
331    }
[707]332
[709]333#if GIET_DEBUG_EXEC
334if ( _get_proctime() > GIET_DEBUG_EXEC )
[714]335_printf("\n[DEBUG EXEC] _load_writable_segments() at cycle %d\n"
336        "P[%d,%d,%d] loaded Elf-Header\n",
337        _get_proctime() , x , y , p );
[707]338#endif
339
340    // get nsegments and Program-Header-Table offset from Elf-Header
341    Elf32_Ehdr*  elf_header_ptr = (Elf32_Ehdr*)buf;
342    unsigned int offset         = elf_header_ptr->e_phoff;
343    unsigned int nsegments      = elf_header_ptr->e_phnum;
344
345    // load Program-Header-Table from .elf file
[709]346    if ( _fat_lseek( fd, offset, SEEK_SET ) < 0 )
347    {
348        _fat_close( fd );
349        return 1;
350    }
351    if ( _fat_read( fd, (unsigned int)buf, 4096, 0 ) < 0 )
352    {
353        _fat_close( fd );
354        return 1;
355    }
[707]356
[709]357#if GIET_DEBUG_EXEC
358if ( _get_proctime() > GIET_DEBUG_EXEC )
[714]359_printf("\n[DEBUG EXEC] _load_writable_segments() at cycle %d\n"
360        "P[%d,%d,%d] loaded Program-Header-Table\n",
361        _get_proctime() , x , y , p );
[707]362#endif
363
364    // set Program-Header-Table pointer
365    Elf32_Phdr*  elf_pht_ptr = (Elf32_Phdr*)buf;
366
[709]367    // second scan on vsegs in vspace to load the seg_data segments :
368    // - type == VSEG_TYPE_ELF
369    // - non eXecutable
370    for (vseg_id = vspace->vseg_offset;
371         vseg_id < (vspace->vseg_offset + vspace->vsegs);
372         vseg_id++)
[707]373    {
[709]374        if( (vseg[vseg_id].type == VSEG_TYPE_ELF) &&   // type ELF
375            ((vseg[vseg_id].mode & 0x4) == 0) )        // non executable
[707]376        {
[709]377            // get vbase and pbase
378            paddr_t      pbase = vseg[vseg_id].pbase; 
379            unsigned int vbase = vseg[vseg_id].vbase;
[707]380
[709]381            // scan segments in Progam-Header-Table to find match
382            // No match checking as the segment was previously found
383            unsigned int seg;
384            for (seg = 0 ; seg < nsegments ; seg++)
385            {
386                if ( (elf_pht_ptr[seg].p_type == PT_LOAD) &&    // loadable
387                     (elf_pht_ptr[seg].p_flags & PF_W)    &&    // writable
388                     (elf_pht_ptr[seg].p_vaddr == vbase) )      // matching
389                {
390                    // Get segment offset and size in .elf file
391                    unsigned int seg_offset = elf_pht_ptr[seg].p_offset;
392                    unsigned int seg_size   = elf_pht_ptr[seg].p_filesz;
[707]393
[709]394                    // compute destination address and extension for _fat_read()
395                    unsigned int dest   = (unsigned int)pbase;
396                    unsigned int extend = (unsigned int)(pbase>>32) | 0xFFFF0000;
397
398                    // load the segment
399                    if ( _fat_lseek( fd, seg_offset, SEEK_SET ) < 0 ) 
400                    {
401                        _fat_close( fd );
402                        return 1;
403                    }
404                    if ( _fat_read( fd, dest, seg_size, extend ) < 0 )
405                    {
406                        _fat_close( fd );
407                        return 1;
408                    }
409                }
410            }
411
412#if GIET_DEBUG_EXEC
413if ( _get_proctime() > GIET_DEBUG_EXEC )
[714]414_printf("\n[DEBUG EXEC] _load_writable_segments() at cycle %d\n"
415        "P[%d,%d,%d] loaded segment %x\n",
416        _get_proctime() , x , y , p , vbase );
[707]417#endif
418        }
419    }  // end loop on writable & loadable segments
420
421    // close .elf file
422    _fat_close( fd );
423
424    return 0;
425}  // end load_writable_segments()
426
[648]427
[709]428
[648]429///////////////////////////////////////
[709]430int _sys_exec_application( char* name )
[648]431{
432    mapping_header_t * header  = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
433    mapping_vspace_t * vspace  = _get_vspace_base(header);
[709]434    mapping_thread_t * thread  = _get_thread_base(header);
435    mapping_vseg_t   * vseg    = _get_vseg_base(header);
[648]436
437    unsigned int vspace_id;
[709]438    unsigned int thread_id;
[648]439
[709]440#if GIET_DEBUG_EXEC
441unsigned int gpid       = _get_procid();
442unsigned int cluster_xy = gpid >> P_WIDTH;
443unsigned int p          = gpid & ((1<<P_WIDTH)-1);
444unsigned int x          = cluster_xy >> Y_WIDTH;
445unsigned int y          = cluster_xy & ((1<<Y_WIDTH)-1);
[648]446if ( _get_proctime() > GIET_DEBUG_EXEC )
[714]447_printf("\n[DEBUG EXEC] _sys_exec_application() at cycle %d\n"
448        "P[%d,%d,%d] enters for vspace %s\n",
449        _get_proctime() , x, y, p, name );
[648]450#endif
451
[709]452    unsigned int y_size = header->y_size;
453
454    // scan vspaces to find matching vspace name
455    for (vspace_id = 0 ; vspace_id < header->vspaces ; vspace_id++) 
[648]456    {
[709]457        if ( _strcmp( vspace[vspace_id].name, name ) == 0 )  // vspace found
[648]458        {
459
[709]460#if GIET_DEBUG_EXEC
461if ( _get_proctime() > GIET_DEBUG_EXEC )
[714]462_printf("\n[DEBUG EXEC] _sys_exec_application() at cycle %d\n"
463        "P[%d,%d,%d] found vspace %s\n",
464        _get_proctime() , x, y, p, name );
[709]465#endif
466            // reload writable segments
467            if ( _load_writable_segments( &vspace[vspace_id] ) )
[648]468            {
[709]469                _printf("[GIET ERROR] _sys_exec_application() : "
470                        "can't load data segment for vspace %s\n", name );
[714]471                return SYSCALL_CANNOT_LOAD_DATA_SEGMENT;
[709]472            }
473 
474#if GIET_DEBUG_EXEC
475if ( _get_proctime() > GIET_DEBUG_EXEC )
[714]476_printf("\n[DEBUG EXEC] _sys_exec_application() at cycle %d\n"
477        "P[%d,%d,%d] loaded all writable segments for vspace %s\n",
478        _get_proctime() , x, y, p, name );
[709]479#endif
480            // scan threads in vspace with three goals :
481            // - check all threads desactivated
482            // - re-initialise all threads contexts
483            // - find main thread
484            unsigned int        main_found  = 0;
485            unsigned int        main_ltid   = 0;
486            static_scheduler_t* main_psched = NULL;
487            unsigned int        min         = vspace[vspace_id].thread_offset; 
488            unsigned int        max         = min + vspace[vspace_id].threads; 
489            for ( thread_id = min ; thread_id < max ; thread_id++ ) 
490            {
491                // get thread identifiers : [x,y,p,ltid]
492                unsigned int cid   = thread[thread_id].clusterid;
[648]493                unsigned int x     = cid / y_size;
494                unsigned int y     = cid % y_size;
[709]495                unsigned int p     = thread[thread_id].proclocid;
496                unsigned int ltid  = thread[thread_id].ltid;
497                unsigned int vsid  = thread[thread_id].stack_vseg_id;
[648]498
[709]499                // get scheduler pointer
500                static_scheduler_t* psched = _schedulers[x][y][p];
[648]501
[709]502                // check thread non active
503                if ( psched->context[ltid].slot[CTX_NORUN_ID] == 0 )  // runnable !!!
504                {
505                    _printf("\n[GIET ERROR] in _sys_exec_application() : "
506                            "thread %s already active in vspace %s\n",
507                            thread[thread_id].name, name );
[714]508                    return SYSCALL_THREAD_ALREADY_ACTIVE;
[709]509                }
510               
511                // initialise thread context
512                unsigned int ctx_epc = psched->context[ltid].slot[CTX_ENTRY_ID];
513                unsigned int ctx_sp  = vseg[vsid].vbase + vseg[vsid].length;
514                unsigned int ctx_ra  = (unsigned int)&_ctx_eret;
515                unsigned int ctx_sr  = GIET_SR_INIT_VALUE;
[648]516
[709]517                psched->context[ltid].slot[CTX_EPC_ID] = ctx_epc;
518                psched->context[ltid].slot[CTX_RA_ID]  = ctx_ra;
519                psched->context[ltid].slot[CTX_SR_ID]  = ctx_sr;
520                psched->context[ltid].slot[CTX_SP_ID]  = ctx_sp;
521
522                // register information required to activate main thread
523                // actual activation done when threads initialisation is completed
524                if ( thread[thread_id].is_main ) 
525                {
526                    main_psched = psched;
527                    main_ltid   = ltid;
528                    main_found  = 1;
529                }
530 
[648]531#if GIET_DEBUG_EXEC
532if ( _get_proctime() > GIET_DEBUG_EXEC )
[714]533_printf("\n[DEBUG EXEC] _sys_exec_application() at cycle %d\n"
534        "P[%d,%d,%d] initialise thread %s in vspace %s\n",
535        _get_proctime() , x, y, p, thread[thread_id].name , name );
[648]536#endif
[714]537            }  // end loop on threads
[648]538
[709]539            // activate main thread
540            if ( main_found )
541            {
542                main_psched->context[main_ltid].slot[CTX_NORUN_ID] = 0;
543            }
544            else
545            {
546                _printf("\n[GIET ERROR] in _sys_exec_application() : "
547                        "main not found in vspace %s\n", name );
[714]548                return SYSCALL_MAIN_NOT_FOUND;
[709]549            }
550             
[714]551            _printf("\n[GIET WARNING] application %s launched : %d threads\n",
552                    name , max-min );
553
554            return SYSCALL_OK;
[709]555        }
556    }  // end of loop on vspaces
[648]557
[709]558    // vspace not found
559    _printf("\n[GIET ERROR] in _sys_exec_application() : "
560            "vspace %s not found\n", name );
[714]561    return SYSCALL_VSPACE_NOT_FOUND;
[648]562
[709]563}  // end _sys_exec_application()
[648]564   
[709]565
[648]566///////////////////////////////////////
[709]567int _sys_kill_application( char* name )
[648]568{
569    mapping_header_t * header  = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
570    mapping_vspace_t * vspace  = _get_vspace_base(header);
[709]571    mapping_thread_t * thread  = _get_thread_base(header);
[648]572
573    unsigned int vspace_id;
[709]574    unsigned int thread_id;
[648]575
[707]576#if GIET_DEBUG_EXEC
[709]577unsigned int gpid       = _get_procid();
578unsigned int cluster_xy = gpid >> P_WIDTH;
579unsigned int p          = gpid & ((1<<P_WIDTH)-1);
580unsigned int x          = cluster_xy >> Y_WIDTH;
581unsigned int y          = cluster_xy & ((1<<Y_WIDTH)-1);
[648]582if ( _get_proctime() > GIET_DEBUG_EXEC )
[714]583_printf("\n[DEBUG EXEC] _sys_kill_application() at cycle %d\n"
584        "P[%d,%d,%d] enters for vspace %s\n",
585        _get_proctime() , x , y , p , name );
[648]586#endif
587
[709]588    // shell cannot be killed
589    if ( _strcmp( name , "shell" ) == 0 )
[648]590    {
[709]591        _printf("\n[GIET ERROR] in _sys_kill_application() : "
592                "%s application cannot be killed\n", name );
[714]593        return SYSCALL_APPLI_CANNOT_BE_KILLED;
[707]594    }
[648]595
[709]596    // scan vspaces to find matching vspace name
597    for (vspace_id = 0; vspace_id < header->vspaces; vspace_id++) 
[707]598    {
[709]599        if ( _strcmp( vspace[vspace_id].name, name ) == 0 ) 
600        {
601            // scan threads to send KILL signal to all threads in vspace
602            unsigned int y_size = header->y_size;
603            unsigned int min    = vspace[vspace_id].thread_offset; 
604            unsigned int max    = min + vspace[vspace_id].threads; 
605            for ( thread_id = min ; thread_id < max ; thread_id++ ) 
606            {
607                unsigned int cid   = thread[thread_id].clusterid;
608                unsigned int x     = cid / y_size;
609                unsigned int y     = cid % y_size;
610                unsigned int p     = thread[thread_id].proclocid;
611                unsigned int ltid  = thread[thread_id].ltid;
[648]612
[709]613                // get scheduler pointer for processor running the thread
614                static_scheduler_t* psched  = (static_scheduler_t*)_schedulers[x][y][p];
615
616                // set KILL signal bit
617                _atomic_or( &psched->context[ltid].slot[CTX_SIGS_ID] , SIGS_MASK_KILL );
618            } 
619
[714]620            _printf("\n[GIET WARNING] application %s killed / %d threads\n",
621                    name , max-min );
[709]622
[714]623            return SYSCALL_OK;
[709]624        }
625    }  // en loop on vspaces
626
627    _printf("\n[GIET ERROR] in _sys_kill_application() : "
628            "application %s not found\n", name );
[714]629    return SYSCALL_VSPACE_NOT_FOUND;
[709]630
631}  // end _sys_kill_application()
632   
633
634
[714]635//////////////////////////////////////////
636int _sys_applications_status( char* name )
[709]637{
638    mapping_header_t *  header  = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
639    mapping_thread_t *  thread  = _get_thread_base(header);
640    mapping_vspace_t *  vspace  = _get_vspace_base(header);
641    mapping_cluster_t * cluster = _get_cluster_base(header);
642
[714]643    unsigned int thread_id;   // thread index in mapping
644    unsigned int vspace_id;   // vspace index in mapping
[709]645
[714]646    // scan vspaces
[709]647    for( vspace_id = 0 ; vspace_id < header->vspaces ; vspace_id++ )
[707]648    {
[714]649        if ( (name == NULL) || (_strcmp(vspace[vspace_id].name , name ) == 0) )
[709]650        {
[714]651            _user_printf("\n*** vspace %s\n", vspace[vspace_id].name );
[648]652
[714]653            // scan all threads in vspace
654            unsigned int min = vspace[vspace_id].thread_offset ;
655            unsigned int max = min + vspace[vspace_id].threads ;
656            for ( thread_id = min ; thread_id < max ; thread_id++ )
657            {
658                unsigned int         clusterid = thread[thread_id].clusterid;
659                unsigned int         p         = thread[thread_id].proclocid;
660                unsigned int         x         = cluster[clusterid].x;
661                unsigned int         y         = cluster[clusterid].y;
662                unsigned int         ltid      = thread[thread_id].ltid;
663                static_scheduler_t*  psched    = (static_scheduler_t*)_schedulers[x][y][p];
664                unsigned int         norun     = psched->context[ltid].slot[CTX_NORUN_ID];
665                unsigned int         tty       = psched->context[ltid].slot[CTX_TTY_ID];
666                unsigned int         current   = psched->current;
667
668                if ( current == ltid )
669                _user_printf(" - thread %s / P[%d,%d,%d] / ltid = %d / "
670                             "TTY = %d / norun = %x : running\n", 
671                             thread[thread_id].name, x, y, p, ltid, tty, norun );
672                else if ( norun == 0 )
673                _user_printf(" - thread %s / P[%d,%d,%d] / ltid = %d / "
674                             "TTY = %d / norun = %x : runable\n", 
675                             thread[thread_id].name, x, y, p, ltid, tty, norun);
676                else
677                _user_printf(" - thread %s / P[%d,%d,%d] / ltid = %d / "
678                             "TTY = %d / norun = %x : blocked\n", 
679                             thread[thread_id].name, x, y, p, ltid, tty, norun);
680            }
[648]681        }
682    }
[709]683    _user_printf("\n");
[714]684
685    return SYSCALL_OK;
[709]686}  // end _sys_applications_status()
[648]687
[709]688
689
690/////////////////////////////////////////////////////////////////////////////
691//          Threads related syscall handlers
692/////////////////////////////////////////////////////////////////////////////
693
694////////////////////////////////////////////////
695int _sys_pthread_create( unsigned int*  buffer,
696                         void*          attr,
697                         void*          function,
698                         void*          arg )
699{
700    // attr argument not supported
701    if ( attr != NULL )
[707]702    {
[709]703        _printf("\n[GIET ERROR] in _sys_pthread_create() : "
704                "attr argument not supported\n" );
705       
[714]706        return SYSCALL_PTHREAD_ARGUMENT_NOT_SUPPORTED;
[707]707    }
708
[709]709    // get pointers in mapping
710    mapping_header_t*    header   = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
711    mapping_thread_t*    thread   = _get_thread_base(header);
712    mapping_vspace_t*    vspace   = _get_vspace_base(header);
713    mapping_cluster_t*   cluster  = _get_cluster_base(header);
714
715    // get scheduler for processor running the calling thread
716    static_scheduler_t* psched = (static_scheduler_t*)_get_sched();
717
718    // get calling thread local index in scheduler
719    unsigned int  current = psched->current;
720
721    // get vspace index
722    unsigned int  vspace_id = psched->context[current].slot[CTX_VSID_ID];
723
724#if GIET_DEBUG_EXEC
[714]725unsigned int gpid       = _get_procid();
726unsigned int cluster_xy = gpid >> P_WIDTH;
727unsigned int p          = gpid & ((1<<P_WIDTH)-1);
728unsigned int x          = cluster_xy >> Y_WIDTH;
729unsigned int y          = cluster_xy & ((1<<Y_WIDTH)-1);
[709]730if ( _get_proctime() > GIET_DEBUG_EXEC )
[714]731_printf("\n[DEBUG EXEC] _sys_pthread_create() at cycle %d\n"
732        "P[%d,%d,%d] enters for vspace %s / entry = %x\n",
733        _get_proctime() , x , y , p , vspace[vspace_id].name , (unsigned int)function );
[709]734#endif
735
736    unsigned int thread_id;        // searched thread : local index in mapping
737    unsigned int clusterid;        // searched thread : cluster index
738    unsigned int lpid;             // searched thread : processor local index
739    unsigned int ltid;             // searched thread : scheduler thread index
740    unsigned int cx;               // searched thread : X coordinate for searched thread
741    unsigned int cy;               // searched thread : Y coordinate for searched thread
742    unsigned int entry;            // searched thread : entry point
743    unsigned int norun;            // searched thread : norun vector
744    unsigned int trdid;            // searched thread : thread identifier
745
746    // scan threads in vspace to find an inactive thread matching function
747    unsigned int min   = vspace[vspace_id].thread_offset;
748    unsigned int max   = min + vspace[vspace_id].threads;
749    unsigned int found = 0;
750    for ( thread_id = min ; (thread_id < max) && (found == 0) ; thread_id++ )
[707]751    {
[709]752        // get thread coordinates [cx,cy,lpid] and ltid from mapping
753        ltid       = thread[thread_id].ltid;
754        clusterid  = thread[thread_id].clusterid; 
755        lpid       = thread[thread_id].proclocid;
756        cx = cluster[clusterid].x;
757        cy = cluster[clusterid].y;
[707]758
[709]759        // get thread scheduler pointer
760        psched = _schedulers[cx][cy][lpid];
[707]761
[709]762        // get thread entry-point, norun-vector, and trdid from context
763        entry = psched->context[ltid].slot[CTX_ENTRY_ID];
764        norun = psched->context[ltid].slot[CTX_NORUN_ID];
765        trdid = psched->context[ltid].slot[CTX_TRDID_ID];
[707]766
[709]767        // check matching
768        if ( ((unsigned int)function == entry ) && 
769             (norun & NORUN_MASK_THREAD)  ) found = 1;
770
771    }  // end loop on threads
772
773    if ( found )  // one matching inactive thread has been found
774    {
775        // set argument value in thread context
776        if ( arg != NULL ) psched->context[ltid].slot[CTX_A0_ID] = (unsigned int)arg;
777
778        // activate thread
779        psched->context[ltid].slot[CTX_NORUN_ID] = 0;
780
781        // return launched thead global identifier
782        *buffer   = trdid;
783               
784#if GIET_DEBUG_EXEC
785if ( _get_proctime() > GIET_DEBUG_EXEC )
[714]786_printf("\n[DEBUG EXEC] _sys_pthread_create() at cycle %d\n"
787        "P[%d,%d,%d] exit : thread %x launched in vspace %s\n",
788        _get_proctime() , x , y , p , trdid , vspace[vspace_id].name );
[709]789#endif
[714]790        return SYSCALL_OK;
[707]791    }
[709]792    else         // no matching thread found
793    {
794        _printf("\n[GIET ERROR] in _sys_pthread_create() : "
795                "no matching thread for entry = %x in vspace %s\n",
796                (unsigned int)function , vspace[vspace_id].name );
797       
[714]798        return SYSCALL_THREAD_NOT_FOUND;
[709]799    }
[707]800
[709]801} // end _sys_pthread_create()
802
803
804///////////////////////////////////////////
805int _sys_pthread_join( unsigned int  trdid,
806                       void*         ptr )
807{
808    // ptr argument not supported
809    if ( ptr != NULL )
810    {
811        _printf("\n[GIET ERROR] in _sys_pthread_join() : "
812                "ptr argument not supported, must be NULL\n" );
813       
[714]814        return SYSCALL_PTHREAD_ARGUMENT_NOT_SUPPORTED;
[709]815    }
816
[714]817    // get calling thread vspace
818    unsigned int  caller_vspace = _get_context_slot( CTX_VSID_ID );
[709]819               
820#if GIET_DEBUG_EXEC
[714]821unsigned int gpid       = _get_procid();
822unsigned int cluster_xy = gpid >> P_WIDTH;
823unsigned int p          = gpid & ((1<<P_WIDTH)-1);
824unsigned int x          = cluster_xy >> Y_WIDTH;
825unsigned int y          = cluster_xy & ((1<<Y_WIDTH)-1);
[648]826if ( _get_proctime() > GIET_DEBUG_EXEC )
[714]827_printf("\n[DEBUG EXEC] _sys_pthread_join() at cycle %d\n"
828        "P[%d,%d,%d] enters for thread %x in vspace %d\n",
829        _get_proctime() , x , y , p , trdid , caller_vspace );
[648]830#endif
831
[714]832    // get target thread indexes from trdid
[709]833    unsigned int cx   = (trdid>>24) & 0xFF;
834    unsigned int cy   = (trdid>>16) & 0xFF;
835    unsigned int lpid = (trdid>>8 ) & 0xFF;
836    unsigned int ltid = (trdid    ) & 0xFF;
837
838    // get target thread scheduler, vspace and registered trdid
839    static_scheduler_t*  psched   = _schedulers[cx][cy][lpid];
840    unsigned int target_vspace    = psched->context[ltid].slot[CTX_VSID_ID];
841    unsigned int registered_trdid = psched->context[ltid].slot[CTX_TRDID_ID];
842
843    // check trdid
844    if ( trdid != registered_trdid )
845    {
846       _printf("\nerror in _sys_pthread_join() : "
847               "trdid = %x / registered_trdid = %x\n",
848               trdid , registered_trdid );
849
[714]850       return SYSCALL_UNCOHERENT_THREAD_CONTEXT;
[709]851    }
852   
853    // check calling thread and target thread in same vspace
854    if ( caller_vspace != target_vspace )
855    {
856       _printf("\n[GIET ERROR] in _sys_pthread_join() : "
857               " calling thread and target thread not in same vspace\n");
858
[714]859       return SYSCALL_NOT_IN_SAME_VSPACE;
[709]860    }
861
862    // get target thread state
863    unsigned int* pnorun = &psched->context[ltid].slot[CTX_NORUN_ID];
864
865    asm volatile ( "2000:                      \n"                         
[714]866                   "move  $11,  %0             \n"   /* $11 <= pnorun        */
867                   "lw    $11,  0($11)         \n"   /* $11 <= norun         */
[709]868                   "andi  $11,  $11,    1      \n"   /* $11 <= norun & 0x1   */
869                   "beqz  $11,  2000b          \n"   
870                   :
871                   : "r" (pnorun)
872                   : "$11" );
873
[714]874#if GIET_DEBUG_EXEC
875if ( _get_proctime() > GIET_DEBUG_EXEC )
876_printf("\n[DEBUG EXEC] _sys_pthread_join() at cycle %d\n"
877        "P[%d,%d,%d] exit for thread %x in vspace %d\n",
878        _get_proctime() , x , y , p , trdid , caller_vspace );
879#endif
[709]880
[714]881    return SYSCALL_OK;
882
[709]883}  // end _sys_pthread_join()
884                       
885
886////////////////////////////////////////
887int _sys_pthread_kill( pthread_t  trdid,
888                       int        signal )
889{
890    // get calling thread vspace
891    unsigned int  caller_vspace = _get_context_slot( CTX_VSID_ID );
892
[714]893#if GIET_DEBUG_EXEC
894unsigned int gpid       = _get_procid();
895unsigned int cluster_xy = gpid >> P_WIDTH;
896unsigned int p          = gpid & ((1<<P_WIDTH)-1);
897unsigned int x          = cluster_xy >> Y_WIDTH;
898unsigned int y          = cluster_xy & ((1<<Y_WIDTH)-1);
899if ( _get_proctime() > GIET_DEBUG_EXEC )
900_printf("\n[DEBUG EXEC] _sys_pthread_kill() at cycle %d\n"
901        "P[%d,%d,%d] enters for thread %x in vspace %d\n",
902        _get_proctime() , x , y , p , trdid , caller_vspace );
903#endif
904
905
[709]906    // get and check target thread indexes from trdid
907    unsigned int cx   = (trdid>>24) & 0xFF;
908    unsigned int cy   = (trdid>>16) & 0xFF;
909    unsigned int lpid = (trdid>>8 ) & 0xFF;
910    unsigned int ltid = (trdid    ) & 0xFF;
911
912    // get target thread scheduler, vspace and registered trdid
913    static_scheduler_t*  psched       = _schedulers[cx][cy][lpid];
914    unsigned int target_vspace        = psched->context[ltid].slot[CTX_VSID_ID];
915    unsigned int registered_trdid = psched->context[ltid].slot[CTX_TRDID_ID];
916
917    // check trdid
918    if ( trdid != registered_trdid )
919    {
920       _printf("\n[GIET ERROR] in _sys_pthread_kill() : trdid = %x"
921               " / registered_trdid = %x\n", trdid , registered_trdid );
[714]922       return SYSCALL_UNCOHERENT_THREAD_CONTEXT;
[709]923    }
924   
925    // check calling thread and target thread in same vspace
926    if ( caller_vspace != target_vspace )
927    {
928       _printf("\n[GIET ERROR] in _sys_pthread_kill() : not in same vspace\n");
[714]929       return SYSCALL_NOT_IN_SAME_VSPACE;
[709]930    }
931
932    // register KILL signal in target thread context if required
933    if ( signal )
934    {
935        _atomic_or( &psched->context[ltid].slot[CTX_SIGS_ID] , SIGS_MASK_KILL );
936    }
937
[714]938#if GIET_DEBUG_EXEC
939if ( _get_proctime() > GIET_DEBUG_EXEC )
940_printf("\n[DEBUG EXEC] _sys_pthread_kill() at cycle %d\n"
941        "P[%d,%d,%d] exit for thread %x in vspace %d\n",
942        _get_proctime() , x , y , p , trdid , caller_vspace );
943#endif
[709]944
[714]945    return SYSCALL_OK;
946
[709]947}  // end _sys_pthread_kill()
948
949
950/////////////////////////////////////
951int _sys_pthread_exit( void* string ) 
952{
953    mapping_header_t * header  = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
954    mapping_vspace_t * vspace  = _get_vspace_base(header);
955
956    unsigned int ltid       = _get_context_slot(CTX_LTID_ID);
957    unsigned int trdid      = _get_context_slot(CTX_TRDID_ID);
958    unsigned int vsid       = _get_context_slot(CTX_VSID_ID);
959
960    // print exit message
961    if ( string == NULL )
962    {
[719]963        _printf("\n[GIET WARNING] Exit thread %x in application %s\n",
964                trdid , vspace[vsid].name );
[709]965    }
966    else
967    {
[719]968        _printf("\n[GIET WARNING] Exit thread %x in vspace %s\n"
969                "               Cause : %s\n\n",
[717]970                     trdid , vspace[vsid].name , (char*) string );
[709]971    }
[648]972   
[709]973    // get scheduler pointer for calling thread
974    static_scheduler_t*  psched = (static_scheduler_t*)_get_sched();
[648]975
[709]976    // register KILL signal in calling thread context (suicid request)
977    _atomic_or( &psched->context[ltid].slot[CTX_SIGS_ID] , SIGS_MASK_KILL );
978
979    // deschedule calling thread
980    unsigned int save_sr; 
981    _it_disable( &save_sr );
982
983    _ctx_switch();
984
[714]985    return SYSCALL_OK;
[709]986
987}  // end _sys_pthread_exit()
988
989////////////////////////
990int _sys_pthread_yield() 
991{
992    unsigned int save_sr;
993
994    _it_disable( &save_sr );
995    _ctx_switch();
996    _it_restore( &save_sr );
997
[714]998    return SYSCALL_OK;
[709]999}
1000
1001//////////////////////////////////////////////////
1002int _sys_pthread_control( unsigned  int  command,
1003                          char*     vspace_name,
1004                          char*     thread_name )
1005{
1006
1007#if GIET_DEBUG_EXEC
[714]1008unsigned int gpid       = _get_procid();
1009unsigned int cluster_xy = gpid >> P_WIDTH;
1010unsigned int p          = gpid & ((1<<P_WIDTH)-1);
1011unsigned int x          = cluster_xy >> Y_WIDTH;
1012unsigned int y          = cluster_xy & ((1<<Y_WIDTH)-1);
[709]1013if ( _get_proctime() > GIET_DEBUG_EXEC )
[714]1014_printf("\n[DEBUG EXEC] _sys_pthread_control() at cycle %d\n"
1015        "P[%d,%d,%d] enter for vspace %s / thread %s / command = %d\n",
1016        _get_proctime() , x , y , p , vspace_name, thread_name, command );
[709]1017#endif
1018
1019    // get pointers in mapping
1020    mapping_header_t*    header   = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
1021    mapping_thread_t*    thread   = _get_thread_base(header);
1022    mapping_vspace_t*    vspace   = _get_vspace_base(header);
1023    mapping_cluster_t*   cluster  = _get_cluster_base(header);
1024
1025    unsigned int found;
1026
1027    // search vspace name to get vspace index: vsid
1028    found = 0;
1029    unsigned int   vsid;
1030    for( vsid = 0 ; vsid < header->vspaces ; vsid++ )
1031    {
1032        if ( _strcmp( vspace[vsid].name, vspace_name ) == 0 )
1033        {
1034            found = 1;
1035            break;
1036        }
1037    }
1038
[714]1039    if ( found == 0 ) return SYSCALL_VSPACE_NOT_FOUND;
[709]1040
1041    // search thread name in vspace to get thread index: tid
1042    found = 0;
1043    unsigned int   tid;
1044    unsigned int   min = vspace[vsid].thread_offset;
1045    unsigned int   max = min + vspace[vsid].threads;
1046    for( tid = min ; tid < max ; tid++ )
1047    {
1048        if ( _strcmp( thread[tid].name, thread_name ) == 0 )
1049        {
1050            found = 1;
1051            break;
1052        }
1053    }
1054
[714]1055    if ( found == 0 ) return SYSCALL_THREAD_NOT_FOUND;
[709]1056
[714]1057    // get target thread coordinates
[709]1058    unsigned int cid  = thread[tid].clusterid;
[714]1059    unsigned int cx   = cluster[cid].x;
1060    unsigned int cy   = cluster[cid].y;
1061    unsigned int cp   = thread[tid].proclocid;
[709]1062    unsigned int ltid = thread[tid].ltid;
1063
[714]1064    // get target thread scheduler
1065    static_scheduler_t* psched = _schedulers[cx][cy][cp];
[709]1066
1067    // check trdid and vsid
[714]1068    unsigned int trdid = cx<<24 | cy<<16 | cp<<8 | ltid;
[709]1069    if ( (psched->context[ltid].slot[CTX_TRDID_ID] != trdid) ||
1070         (psched->context[ltid].slot[CTX_VSID_ID]  != vsid) )
[714]1071    {
1072        return SYSCALL_UNCOHERENT_THREAD_CONTEXT;
1073    }
[709]1074
1075    // execute command
1076    if ( command == THREAD_CMD_PAUSE ) 
1077    {
1078        _atomic_or ( &psched->context[ltid].slot[CTX_NORUN_ID],  NORUN_MASK_THREAD );
[714]1079        return SYSCALL_OK;
[709]1080    }
1081    else if ( command == THREAD_CMD_RESUME )
1082    {
1083        _atomic_and( &psched->context[ltid].slot[CTX_NORUN_ID], ~NORUN_MASK_THREAD );
[714]1084        return SYSCALL_OK;
[709]1085    }
1086    else if ( command == THREAD_CMD_CONTEXT )
1087    {
1088        _user_printf( " - CTX_TRDID  = %x\n"
1089                      " - CTX_VSID   = %x\n"
1090                      " - CTX_EPC    = %x\n"
1091                      " - CTX_PTAB   = %x\n"
1092                      " - CTX_PTPR   = %x\n"
1093                      " - CTX_SR     = %x\n"
1094                      " - CTX_RA     = %x\n"
1095                      " - CTX_SP     = %x\n"
1096                      " - CTX_ENTRY  = %x\n"
1097                      " - CTX_NORUN  = %x\n"
1098                      " - CTX_SIGS   = %x\n"
1099                      " - CTX_LOCKS  = %x\n"
1100                      " - CTX_TTY    = %x\n"
1101                      " - CTX_NIC_RX = %x\n"
1102                      " - CTX_NIC_TX = %x\n"
1103                      " - CTX_CMA_RX = %x\n"
1104                      " - CTX_CMA_TX = %x\n"
1105                      " - CTX_CMA_FB = %x\n",
1106                      psched->context[ltid].slot[CTX_TRDID_ID], 
1107                      psched->context[ltid].slot[CTX_VSID_ID], 
1108                      psched->context[ltid].slot[CTX_EPC_ID], 
1109                      psched->context[ltid].slot[CTX_PTAB_ID], 
1110                      psched->context[ltid].slot[CTX_PTPR_ID], 
1111                      psched->context[ltid].slot[CTX_SR_ID], 
1112                      psched->context[ltid].slot[CTX_RA_ID], 
1113                      psched->context[ltid].slot[CTX_SP_ID], 
1114                      psched->context[ltid].slot[CTX_ENTRY_ID], 
1115                      psched->context[ltid].slot[CTX_NORUN_ID],
1116                      psched->context[ltid].slot[CTX_SIGS_ID],
1117                      psched->context[ltid].slot[CTX_LOCKS_ID],
1118                      psched->context[ltid].slot[CTX_TTY_ID],
1119                      psched->context[ltid].slot[CTX_NIC_RX_ID],
1120                      psched->context[ltid].slot[CTX_NIC_TX_ID],
1121                      psched->context[ltid].slot[CTX_CMA_RX_ID],
1122                      psched->context[ltid].slot[CTX_CMA_TX_ID],
1123                      psched->context[ltid].slot[CTX_CMA_FB_ID] );
[714]1124        return SYSCALL_OK;
[709]1125    }
1126    else
1127    {
[714]1128        return SYSCALL_ILLEGAL_THREAD_COMMAND_TYPE;
[709]1129    }
1130
1131} // end _sys_pthread_control()
1132
1133
1134
1135
[648]1136//////////////////////////////////////////////////////////////////////////////
[519]1137//           Coprocessors related syscall handlers
1138//////////////////////////////////////////////////////////////////////////////
1139
1140//////////////////////////////////////////////////
[733]1141int _sys_coproc_alloc( unsigned int   cluster_xy,
1142                       unsigned int   coproc_type,
1143                       unsigned int*  return_info )
[519]1144{
1145    mapping_header_t  * header  = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
1146    mapping_cluster_t * cluster = _get_cluster_base(header);
1147    mapping_periph_t  * periph  = _get_periph_base(header);
1148
[733]1149    // compute cluster coordinates and cluster index in mapping
1150    unsigned int y          = cluster_xy & ((1<<Y_WIDTH)-1);
1151    unsigned int x          = (cluster_xy>>Y_WIDTH) & ((1<<X_WIDTH)-1);
[556]1152    unsigned int cluster_id = x * Y_SIZE + y;
[519]1153 
1154    // search coprocessor in cluster
1155    mapping_periph_t*  found = NULL;
1156    unsigned int min   = cluster[cluster_id].periph_offset;
1157    unsigned int max   = min + cluster[cluster_id].periphs;
1158    unsigned int periph_id;
1159    for ( periph_id = min ; periph_id < max ; periph_id++ )
1160    {
1161        if ( (periph[periph_id].type == PERIPH_TYPE_MWR) &&
1162             (periph[periph_id].subtype == coproc_type) )
1163        {
1164            found = &periph[periph_id];
1165            break;
1166        }
1167    } 
1168
1169    if ( found != NULL )
1170    {
[733]1171        // get the lock
[519]1172        _simple_lock_acquire( &_coproc_lock[cluster_id] );
[556]1173
1174        // register coproc characteristics in kernel arrays
1175        _coproc_type[cluster_id] = coproc_type;
1176        _coproc_info[cluster_id] = (found->arg0 & 0xFF)     |
1177                                   (found->arg1 & 0xFF)<<8  |
1178                                   (found->arg2 & 0xFF)<<16 |
1179                                   (found->arg3 & 0xFF)<<24 ;
1180
[519]1181        // returns coprocessor info
[733]1182        *return_info = _coproc_info[cluster_id];
[519]1183
1184#if GIET_DEBUG_COPROC
[714]1185_printf("\n[DEBUG COPROC] _sys_coproc_alloc() at cycle %d\n"
[733]1186        "type = %d in cluster[%d,%d] / coproc_info = %x\n",
1187        _get_proctime() , coproc_type, x , y , *return_info );
[519]1188#endif
[714]1189        return SYSCALL_OK;
[519]1190    }
1191    else
1192    {
[714]1193         _printf("\n[GIET_ERROR] in _sys_coproc_alloc(): "
1194                 "no coprocessor with type %d in cluster[%d,%d]\n",
[519]1195                 coproc_type , x , y );
[714]1196
1197        return SYSCALL_COPROCESSOR_NOT_FOUND;
[519]1198    }
1199}  // end _sys_coproc_alloc()
1200
[556]1201////////////////////////////////////////////////////////
[733]1202int _sys_coproc_release( unsigned int cluster_xy,
1203                         unsigned int coproc_type )
[519]1204{
[733]1205    // compute cluster coordinates and cluster index
1206    unsigned int y          = cluster_xy & ((1<<Y_WIDTH)-1);
1207    unsigned int x          = (cluster_xy>>Y_WIDTH) & ((1<<X_WIDTH)-1);
1208    unsigned int cluster_id = x * Y_SIZE + y;
[714]1209
[733]1210    // check coprocessor type
1211    if ( _coproc_type[cluster_id] != coproc_type )
[519]1212    {
[556]1213         _printf("\n[GIET_ERROR] in _sys_coproc_release(): "
[733]1214                 "no coprocessor of type %d allocated in cluster[%d,%d]\n", 
1215                 coproc_type, x , y );
[714]1216
1217         return SYSCALL_COPROCESSOR_NON_ALLOCATED;
[519]1218    }
1219
[556]1220    unsigned int info       = _coproc_info[cluster_id];
1221    unsigned int nb_to      = info & 0xFF;
1222    unsigned int nb_from    = (info>>8) & 0xFF;
1223    unsigned int channel;
[519]1224
[556]1225    // stops coprocessor and communication channels
[733]1226    _mwr_set_coproc_register( cluster_xy , 0 , 0 );
[556]1227    for ( channel = 0 ; channel < (nb_from + nb_to) ; channel++ )
1228    {
1229        _mwr_set_channel_register( cluster_xy , channel , MWR_CHANNEL_RUNNING , 0 );
1230    }
[519]1231
[556]1232    // release coprocessor lock
1233    _simple_lock_release( &_coproc_lock[cluster_id] );
1234
[519]1235#if GIET_DEBUG_COPROC
[714]1236_printf("\n[DEBUG COPROC] _sys_coproc_release() at cycle %d\n"
[733]1237        "type = %d in cluster[%d,%d]\n",
1238        _get_proctime() , coproc_type , x , y );
[519]1239#endif
1240
[714]1241    return SYSCALL_OK;
[519]1242}  // end _sys_coproc_release()
1243
[733]1244////////////////////////////////////////////////////////////////
1245int _sys_coproc_channel_init( unsigned int            cluster_xy,
1246                              unsigned int            coproc_type,
1247                              unsigned int            channel,
[519]1248                              giet_coproc_channel_t*  desc )
1249{
[733]1250    // compute cluster coordinates and cluster index
1251    unsigned int y          = cluster_xy & ((1<<Y_WIDTH)-1);
1252    unsigned int x          = (cluster_xy>>Y_WIDTH) & ((1<<X_WIDTH)-1);
1253    unsigned int cluster_id = x * Y_SIZE + y;
[714]1254
[733]1255    // check coprocessor type
1256    if ( _coproc_type[cluster_id] != coproc_type )
[519]1257    {
[733]1258         _printf("\n[GIET_ERROR] in _sys_coproc_release(): "
1259                 "no coprocessor of type %d allocated in cluster[%d,%d]\n", 
1260                 coproc_type, x , y );
[714]1261
1262         return SYSCALL_COPROCESSOR_NON_ALLOCATED;
[519]1263    }
1264
1265    // check channel mode
1266    unsigned mode = desc->channel_mode;
1267    if ( (mode != MODE_MWMR) && 
1268         (mode != MODE_DMA_IRQ) && 
1269         (mode != MODE_DMA_NO_IRQ) )
1270    {
[556]1271         _printf("\n[GIET_ERROR] in _sys_coproc_channel_init(): "
[714]1272                 "illegal mode\n");
1273
1274         return SYSCALL_COPROCESSOR_ILLEGAL_MODE;
[519]1275    }
1276
1277    // get memory buffer size
1278    unsigned int size = desc->buffer_size;
1279 
[528]1280    // physical addresses
[709]1281    unsigned long long buffer_paddr;
[519]1282    unsigned int       buffer_lsb;
1283    unsigned int       buffer_msb;
[733]1284    unsigned long long status_paddr = 0;
1285    unsigned int       status_lsb;
1286    unsigned int       status_msb;
[709]1287    unsigned long long lock_paddr = 0;
[519]1288    unsigned int       lock_lsb;
1289    unsigned int       lock_msb;
1290
[528]1291    unsigned int       flags;     // unused
1292
[519]1293    // compute memory buffer physical address
[528]1294    buffer_paddr = _v2p_translate( desc->buffer_vaddr , &flags );
1295    buffer_lsb   = (unsigned int)buffer_paddr;
1296    buffer_msb   = (unsigned int)(buffer_paddr>>32); 
[519]1297
1298    // call MWMR_DMA driver
[556]1299    _mwr_set_channel_register( cluster_xy, channel, MWR_CHANNEL_MODE, mode ); 
1300    _mwr_set_channel_register( cluster_xy, channel, MWR_CHANNEL_SIZE, size ); 
1301    _mwr_set_channel_register( cluster_xy, channel, MWR_CHANNEL_BUFFER_LSB, buffer_lsb ); 
1302    _mwr_set_channel_register( cluster_xy, channel, MWR_CHANNEL_BUFFER_MSB, buffer_msb ); 
[519]1303                       
1304    if ( mode == MODE_MWMR )
1305    {
[528]1306        // compute MWMR descriptor physical address
[733]1307        status_paddr = _v2p_translate( desc->status_vaddr , &flags );
1308        status_lsb = (unsigned int)status_paddr;
1309        status_msb = (unsigned int)(status_paddr>>32); 
[519]1310
[528]1311        // call MWMR_DMA driver
[733]1312        _mwr_set_channel_register( cluster_xy, channel, MWR_CHANNEL_MWMR_LSB, status_lsb ); 
1313        _mwr_set_channel_register( cluster_xy, channel, MWR_CHANNEL_MWMR_MSB, status_msb ); 
[528]1314
1315        // compute lock physical address
1316        lock_paddr = _v2p_translate( desc->lock_vaddr , &flags );
[519]1317        lock_lsb = (unsigned int)lock_paddr;
1318        lock_msb = (unsigned int)(lock_paddr>>32); 
1319
1320        // call MWMR_DMA driver
[556]1321        _mwr_set_channel_register( cluster_xy, channel, MWR_CHANNEL_LOCK_LSB, lock_lsb ); 
1322        _mwr_set_channel_register( cluster_xy, channel, MWR_CHANNEL_LOCK_MSB, lock_msb ); 
[519]1323    }
1324
1325#if GIET_DEBUG_COPROC
[714]1326_printf("\n[DEBUG COPROC] _sys_coproc_channel_init() at cycle %d\n"
1327        "cluster[%d,%d] / channel = %d / mode = %d / buffer_size = %d\n"
[733]1328        "buffer_vaddr = %x / status_vaddr = %x / lock_vaddr = %x\n"
1329        "buffer_paddr = %l / status_paddr = %l / lock_paddr = %l\n",
[714]1330        _get_proctime() , x , y , channel , mode , size ,
[733]1331        desc->buffer_vaddr, desc->status_vaddr, desc->lock_vaddr,
1332        buffer_paddr, status_paddr, lock_paddr );
[519]1333#endif
1334       
[714]1335    return SYSCALL_OK;
[519]1336} // end _sys_coproc_channel_init()
1337
[733]1338//////////////////////////////////////////////
1339int _sys_coproc_run( unsigned int  cluster_xy,
1340                     unsigned int  coproc_type )
[519]1341{
[733]1342    // compute cluster coordinates and cluster index
1343    unsigned int y          = cluster_xy & ((1<<Y_WIDTH)-1);
1344    unsigned int x          = (cluster_xy>>Y_WIDTH) & ((1<<X_WIDTH)-1);
1345    unsigned int cluster_id = x * Y_SIZE + y;
[714]1346
[733]1347    // check coprocessor type
1348    if ( _coproc_type[cluster_id] != coproc_type )
[519]1349    {
[733]1350         _printf("\n[GIET_ERROR] in _sys_coproc_release(): "
1351                 "no coprocessor of type %d allocated in cluster[%d,%d]\n", 
1352                 coproc_type, x , y );
[714]1353
1354         return SYSCALL_COPROCESSOR_NON_ALLOCATED;
[519]1355    }
1356
[556]1357    unsigned int info       = _coproc_info[cluster_id];
1358    unsigned int nb_to      = info & 0xFF;
1359    unsigned int nb_from    = (info>>8) & 0xFF;
1360    unsigned int mode       = 0xFFFFFFFF;
1361    unsigned int channel;
[519]1362
[733]1363    // check channels modes, and register coprocessor running mode
[556]1364    for ( channel = 0 ; channel < (nb_from + nb_to) ; channel++ )
1365    {
1366        unsigned int temp;
1367        temp = _mwr_get_channel_register( cluster_xy , channel , MWR_CHANNEL_MODE );
[519]1368
[556]1369        if ( mode == 0xFFFFFFFF ) 
1370        {
1371            mode = temp;
1372        }
1373        else if ( temp != mode )
1374        {
[714]1375            _printf("\n[GIET_ERROR] in _sys_coproc_run(): "
[733]1376                    "channels don't have same mode in coprocessor[%d,%d]\n", x , y );
[714]1377
1378            return SYSCALL_COPROCESSOR_ILLEGAL_MODE;
[556]1379        }
1380    }
1381    _coproc_mode[cluster_id] = mode;
[519]1382
[556]1383    // start all communication channels
1384    for ( channel = 0 ; channel < (nb_from + nb_to) ; channel++ )
1385    {
1386        _mwr_set_channel_register( cluster_xy , channel , MWR_CHANNEL_RUNNING , 1 );
1387    }
[519]1388
[556]1389    //////////////////////////////////////////////////////////////////////////
1390    if ( (mode == MODE_MWMR) || (mode == MODE_DMA_NO_IRQ) )  // no descheduling
[519]1391    {
[556]1392        // start coprocessor
[733]1393        _mwr_set_coproc_register( cluster_xy , 0 , 1 );
[556]1394
1395#if GIET_DEBUG_COPROC
1396if ( mode == MODE_MWMR )
[714]1397_printf("\n[DEBUG COPROC] _sys_coproc_run() at cycle %d\n"
[733]1398        "type = %d / cluster[%d,%d] / MODE_MWMR\n", 
1399        _get_proctime() , coproc_type , x , y );
[556]1400else
[714]1401_printf("\n[DEBUG COPROC] _sys_coproc_run() at cycle %d\n"
[733]1402        "type = %d / cluster[%d,%d] / MODE_DMA_NO_IRQ\n", 
1403        _get_proctime() , coproc_type , x , y );
[556]1404#endif
1405
[714]1406        return SYSCALL_OK;
[519]1407    }
[556]1408    ///////////////////////////////////////////////////////////////////////////
1409    else                                // mode == MODE_DMA_IRQ => descheduling
1410    {
[733]1411        // register calling thread trdid
1412        unsigned int trdid = _get_thread_trdid();
1413        _coproc_trdid[cluster_id] = trdid;
[519]1414
[556]1415        // enters critical section
1416        unsigned int save_sr;
1417        _it_disable( &save_sr ); 
1418
[629]1419        // set NORUN_MASK_COPROC bit
[733]1420        static_scheduler_t* psched  = _get_sched();
1421        unsigned int        ltid    = _get_thread_ltid();
[709]1422        unsigned int*       ptr     = &psched->context[ltid].slot[CTX_NORUN_ID];
[629]1423        _atomic_or( ptr , NORUN_MASK_COPROC );
[556]1424
1425        // start coprocessor
[733]1426        _mwr_set_coproc_register( cluster_xy , 0 , 1 );
[556]1427
[519]1428#if GIET_DEBUG_COPROC
[714]1429_printf("\n[DEBUG COPROC] _sys_coproc_run() at cycle %d\n"
[733]1430        "thread %x starts coprocessor / type = %d / cluster[%d,%d] / MODE_DMA_IRQ\n", 
1431        _get_proctime() , trdid , coproc_type , x , y );
[519]1432#endif
1433
[709]1434        // deschedule thread
[556]1435        _ctx_switch(); 
[519]1436
[556]1437#if GIET_DEBUG_COPROC
[714]1438_printf("\n[DEBUG COPROC] _sys_coproc_run() at cycle %d\n"
1439        "thread %x resume after coprocessor[%d,%d] completion\n", 
[733]1440        _get_proctime() , trdid , x , y );
[556]1441#endif
1442
1443        // restore SR
1444        _it_restore( &save_sr );
1445
1446        // return error computed by mwr_isr()
1447        return _coproc_error[cluster_id];
1448    } 
1449} // end _sys_coproc_run()
1450
[733]1451////////////////////////////////////////////////////
1452int _sys_coproc_completed( unsigned int  cluster_xy,
1453                           unsigned int  coproc_type )
[519]1454{
[733]1455    // compute cluster coordinates and cluster index
1456    unsigned int y          = cluster_xy & ((1<<Y_WIDTH)-1);
1457    unsigned int x          = (cluster_xy>>Y_WIDTH) & ((1<<X_WIDTH)-1);
1458    unsigned int cluster_id = x * Y_SIZE + y;
[714]1459
[733]1460    // check coprocessor type
1461    if ( _coproc_type[cluster_id] != coproc_type )
[519]1462    {
[733]1463         _printf("\n[GIET_ERROR] in _sys_coproc_release(): "
1464                 "no coprocessor of type %d allocated in cluster[%d,%d]\n", 
1465                 coproc_type, x , y );
[714]1466
1467         return SYSCALL_COPROCESSOR_NON_ALLOCATED;
[519]1468    }
1469
[733]1470    unsigned int mode = _coproc_mode[cluster_id];
[519]1471
[556]1472    // analyse possible errors
1473    if ( mode == MODE_DMA_NO_IRQ )
1474    {
1475        unsigned int info       = _coproc_info[cluster_id];
1476        unsigned int nb_to      = info & 0xFF;
1477        unsigned int nb_from    = (info>>8) & 0xFF;
1478        unsigned int error      = 0;
1479        unsigned int channel;
1480        unsigned int status;
1481
[714]1482        // get status for all channels, and signal reported errors
[556]1483        for ( channel = 0 ; channel < (nb_to +nb_from) ; channel++ )
1484        {
1485            do
1486            {
[714]1487                status = _mwr_get_channel_register( cluster_xy, channel,
1488                                                    MWR_CHANNEL_STATUS );
[556]1489                if ( status == MWR_CHANNEL_ERROR_DATA )
1490                {
[714]1491                    _printf("\n[GIET_ERROR] in _sys_coproc_completed(): "
1492                            "channel %d / DATA_ERROR\n", channel );
[556]1493                    error = 1;
1494                }
1495                else if ( status == MWR_CHANNEL_ERROR_LOCK )
1496                {
1497                    _printf("\n[GIET_ERROR] in _sys_coproc_completed()"
1498                            " / channel %d / LOCK_ERROR\n", channel );
1499                    error = 1;
1500                }
1501                else if ( status == MWR_CHANNEL_ERROR_DESC )
1502                {
1503                    _printf("\n[GIET_ERROR] in _sys_coproc_completed()"
1504                            " / channel %d / DESC_ERROR\n", channel );
1505                    error = 1;
1506                }
[714]1507            } 
1508            while ( status == MWR_CHANNEL_BUSY );
[556]1509
1510            // reset channel
[733]1511            _mwr_set_channel_register( cluster_xy, channel, MWR_CHANNEL_RUNNING , 0 ); 
[556]1512
1513        }  // end for channels
1514
[714]1515        if ( error )
1516        {
1517            return SYSCALL_COPROCESSOR_ILLEGAL_MODE;
1518        }
1519        else
1520        {
1521
[519]1522#if GIET_DEBUG_COPROC
[714]1523_printf("\n[DEBUG COPROC] _sys_coproc_completed() at cycle %d\n"
[733]1524        "coprocessor type = %d / cluster[%d,%d] completes operation for thread %d\n", 
1525        _get_proctime() , coproc_type , x , y , _get_thread_trdid() );
[519]1526#endif
[714]1527            return SYSCALL_OK;
1528        }
[556]1529    }
1530    else  // mode == MODE_MWMR or MODE_DMA_IRQ
1531    {
[714]1532        _printf("\n[GIET ERROR] in sys_coproc_completed(): "
[733]1533                "coprocessor[%d,%d] is not running in MODE_DMA_NO_IRQ\n", x , y );
[714]1534
1535        return SYSCALL_COPROCESSOR_ILLEGAL_MODE;
[556]1536    }
[519]1537} // end _sys_coproc_completed()
1538
1539
1540//////////////////////////////////////////////////////////////////////////////
[440]1541//             TTY related syscall handlers
[258]1542//////////////////////////////////////////////////////////////////////////////
[440]1543
[670]1544/////////////////////////////////////////
1545int _sys_tty_alloc( unsigned int shared )
[258]1546{
[709]1547    unsigned int channel;    // allocated TTY channel
[440]1548
[709]1549    // get trdid and vsid for the calling thread
1550    unsigned int vsid  = _get_context_slot( CTX_VSID_ID );
1551    unsigned int trdid = _get_thread_trdid();
1552
1553    mapping_header_t  *header   = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
1554    mapping_vspace_t  *vspace   = _get_vspace_base(header);
1555    mapping_thread_t  *thread   = _get_thread_base(header);
1556   
1557    // compute number of users
1558    unsigned int users;
1559    if ( shared )  users = vspace[vsid].threads;
1560    else           users = 1;
1561
1562    // get a TTY channel
[698]1563    for ( channel = 0 ; channel < NB_TTY_CHANNELS ; channel++ )
1564    {
[709]1565        unsigned int* palloc  = &_tty_channel_alloc[channel];
1566
1567        if ( _atomic_test_and_set( palloc , users ) == 0 ) break;
[698]1568    }
[440]1569    if ( channel >= NB_TTY_CHANNELS )
1570    {
[709]1571        _printf("\n[GIET_ERROR] in _sys_tty_alloc() : "
1572                "no TTY channel available for thread %x\n", trdid );
[714]1573        return SYSCALL_NO_CHANNEL_AVAILABLE;
[440]1574    }
[547]1575
[709]1576    // initialise allocated TTY channel
1577    _tty_init( channel );
[648]1578
[547]1579    // allocate a WTI mailbox to the calling proc if external IRQ
[709]1580    unsigned int wti_id;
1581    if ( USE_PIC ) _ext_irq_alloc( ISR_TTY_RX , channel , &wti_id ); 
1582
1583    // register wti_id and coordinates for processor receiving WTI
1584    unsigned int procid = _get_procid();
1585    unsigned int x      = procid >> (Y_WIDTH + P_WIDTH);
1586    unsigned int y      = (procid >> P_WIDTH) & ((1<<Y_WIDTH)-1);
1587    unsigned int p      = procid & ((1<<P_WIDTH)-1);
1588    _tty_channel_wti[channel] = x<<24 | y<<16 | p<<8 | wti_id;
[547]1589   
[670]1590    // update CTX_TTY_ID
[709]1591    if ( shared )         // for all threads in vspace
[670]1592    {
[709]1593        // scan threads in vspace
1594        unsigned int tid;
1595        for (tid = vspace[vsid].thread_offset;
1596             tid < (vspace[vsid].thread_offset + vspace[vsid].threads);
1597             tid++)
[670]1598        {
1599            unsigned int y_size        = header->y_size;
[709]1600            unsigned int cid           = thread[tid].clusterid;
[670]1601            unsigned int x             = cid / y_size;
1602            unsigned int y             = cid % y_size;
[709]1603            unsigned int p             = thread[tid].proclocid;
1604            unsigned int ltid          = thread[tid].ltid;
[670]1605            static_scheduler_t* psched = (static_scheduler_t*)_schedulers[x][y][p];
[698]1606
[709]1607            psched->context[ltid].slot[CTX_TTY_ID] = channel;
[670]1608        }
1609    }
[709]1610    else                  // for calling thread only
[670]1611    {
1612        _set_context_slot( CTX_TTY_ID, channel );
1613    }
1614
[714]1615    return SYSCALL_OK;
[709]1616}  // end _sys_tty_alloc()
[258]1617
[709]1618//////////////////////
[714]1619int _sys_tty_release()     // NOTE: not a syscall: used by _ctx_kill_thread()
[695]1620{
[698]1621    unsigned int channel = _get_context_slot( CTX_TTY_ID );
1622
1623    if ( channel == -1 )
1624    {
[709]1625        unsigned int trdid = _get_thread_trdid();
1626        _printf("\n[GIET_ERROR] in _sys_tty_release() : "
1627                "TTY channel already released for thread %x\n", trdid );
[714]1628
1629        return SYSCALL_CHANNEL_ALREADY_ALLOCATED;
[698]1630    }
1631
[709]1632    // reset CTX_TTY_ID for the calling thread
1633    _set_context_slot( CTX_TTY_ID , 0xFFFFFFFF );
[697]1634
[709]1635    // atomically decrement the _tty_channel_allocator[] array
1636    _atomic_increment( &_tty_channel_alloc[channel] , -1 );
[695]1637
[709]1638    // release WTI mailbox if TTY channel no more used
1639    if ( USE_PIC  && (_tty_channel_alloc[channel] == 0) ) 
[698]1640    {
[709]1641        _ext_irq_release( ISR_TTY_RX , channel );
[698]1642    }
1643
[714]1644    return SYSCALL_OK;
[709]1645}  // end sys_tty_release()
[698]1646
[709]1647////////////////////////////////////////
[440]1648int _sys_tty_write( const char*  buffer,   
1649                    unsigned int length,    // number of characters
1650                    unsigned int channel)   // channel index
1651{
1652    unsigned int  nwritten;
1653
1654    // compute and check tty channel
1655    if( channel == 0xFFFFFFFF )  channel = _get_context_slot(CTX_TTY_ID);
1656
[714]1657    if( channel >= NB_TTY_CHANNELS )
1658    {
1659        _printf("\n[GIET_ERROR] in _sys_tty_write() : "
1660                "no TTY channel allocated for thread %x\n", _get_thread_trdid() );
1661
1662        return SYSCALL_CHANNEL_NON_ALLOCATED;
1663    }
1664
[440]1665    // write string to TTY channel
1666    for (nwritten = 0; nwritten < length; nwritten++) 
1667    {
1668        // check tty's status
1669        if ( _tty_get_register( channel, TTY_STATUS ) & 0x2 )  break;
1670
1671        // write one byte
1672        if (buffer[nwritten] == '\n') 
1673        {
1674            _tty_set_register( channel, TTY_WRITE, (unsigned int)'\r' );
1675        }
1676        _tty_set_register( channel, TTY_WRITE, (unsigned int)buffer[nwritten] );
1677    }
1678   
1679    return nwritten;
1680}
1681
[709]1682///////////////////////////////////////
[440]1683int _sys_tty_read( char*        buffer, 
1684                   unsigned int length,    // unused
1685                   unsigned int channel)   // channel index
1686{
1687    // compute and check tty channel
1688    if( channel == 0xFFFFFFFF )  channel = _get_context_slot(CTX_TTY_ID);
1689
[714]1690    if( channel >= NB_TTY_CHANNELS )
1691    {
1692        _printf("\n[GIET_ERROR] in _sys_tty_read() : "
1693                "no TTY channel allocated for thread %x\n", _get_thread_trdid() );
1694
1695        return SYSCALL_CHANNEL_NON_ALLOCATED;
1696    }
1697
[709]1698    unsigned int save_sr;
1699    unsigned int found = 0;
1700
1701    // get pointer on TTY_RX FIFO
1702    tty_fifo_t*  fifo = &_tty_rx_fifo[channel];
1703
1704    // try to read one character from FIFO
1705    // blocked in while loop until success
1706    while ( found == 0 )
[440]1707    {
[709]1708        if ( fifo->sts == 0)   // FIFO empty => deschedule
1709        {
1710            // enters critical section
1711             _it_disable( &save_sr );
[440]1712
[709]1713            // set NORUN_MASK_TTY bit for calling thread
1714            static_scheduler_t* psched  = (static_scheduler_t*)_get_sched();
1715            unsigned int ltid = psched->current;
1716            _atomic_or( &psched->context[ltid].slot[CTX_NORUN_ID] , NORUN_MASK_TTY );
[440]1717
[709]1718            // register descheduling thread trdid
1719            fifo->trdid = _get_thread_trdid();
[440]1720
[709]1721             // deschedule calling thread
1722            _ctx_switch();
[440]1723
[709]1724            // exit critical section
1725            _it_restore( &save_sr );
1726        }
1727        else                             // FIFO not empty => get one character
1728        {
1729            *buffer   = fifo->data[fifo->ptr];
1730            fifo->sts = fifo->sts - 1;
1731            fifo->ptr = (fifo->ptr + 1) % TTY_FIFO_DEPTH;
1732            found     = 1;
1733        }
1734    }
1735
1736    return 1;
[440]1737}
1738
[709]1739
1740
[428]1741//////////////////////////////////////////////////////////////////////////////
[709]1742//             TIMER related syscall handlers
[428]1743//////////////////////////////////////////////////////////////////////////////
[440]1744
1745////////////////////
1746int _sys_tim_alloc()
[428]1747{
[440]1748
[709]1749#if NB_TIM_CHANNELS
1750
1751    unsigned int channel;    // allocated TIMER channel
1752
1753    unsigned int trdid = _get_thread_trdid();
1754
1755    // check no TIMER already allocated to calling thread
1756    if ( _get_context_slot( CTX_TIM_ID ) < NB_TIM_CHANNELS )
[440]1757    {
[709]1758        _printf("\n[GIET_ERROR] in _sys_tim_alloc() : "
1759                "TIMER channel already allocated to thread %x\n", trdid );
[714]1760
1761        return SYSCALL_CHANNEL_ALREADY_ALLOCATED;
[440]1762    }
[709]1763
1764    // get a TIMER channel
1765    for ( channel = 0 ; channel < NB_TIM_CHANNELS ; channel++ )
[440]1766    {
[709]1767        unsigned int* palloc  = &_tim_channel_alloc[channel];
1768
1769        if ( _atomic_test_and_set( palloc , 1 ) == 0 ) break;
[440]1770    }
[709]1771    if ( channel >= NB_TIM_CHANNELS )
1772    {
1773        _printf("\n[GIET_ERROR] in _sys_tim_alloc() : "
1774                "no TIMER channel available for thread %x\n", trdid );
[714]1775
1776        return SYSCALL_NO_CHANNEL_AVAILABLE;
[709]1777    }
[440]1778
[709]1779    // allocate a WTI mailbox to the calling proc if external IRQ
1780    unsigned int wti_id;
1781    if ( USE_PIC ) _ext_irq_alloc( ISR_TIMER , channel , &wti_id ); 
1782
1783    // register wti_id and coordinates for processor receiving WTI
1784    unsigned int procid = _get_procid();
1785    unsigned int x      = procid >> (Y_WIDTH + P_WIDTH);
1786    unsigned int y      = (procid >> P_WIDTH) & ((1<<Y_WIDTH)-1);
1787    unsigned int p      = procid & ((1<<P_WIDTH)-1);
1788    _tim_channel_wti[channel] = x<<24 | y<<16 | p<<8 | wti_id;
1789   
1790    // update CTX_TIM_ID in thread context
1791    _set_context_slot( CTX_TIM_ID, channel );
1792
[714]1793    return SYSCALL_OK;
[709]1794
1795#else
1796
[714]1797    _printf("\n[GIET ERROR] in _sys_tim_alloc(): NB_TIM_CHANNELS == 0\n");
[709]1798
[714]1799    return SYSCALL_NO_CHANNEL_AVAILABLE;
1800
[709]1801#endif
1802}  // end _sys_tim_alloc()
1803
1804
1805//////////////////////
[714]1806int _sys_tim_release()     // NOTE: not a syscall: used by _ctx_kill_thread()
[695]1807{
1808
[709]1809#if NB_TIM_CHANNELS
[695]1810
[709]1811    unsigned int channel = _get_context_slot( CTX_TIM_ID );
1812
1813    if ( channel == -1 )
1814    {
1815        unsigned int trdid = _get_thread_trdid();
[714]1816        _printf("\n[GIET_ERROR] in _sys_tim_release(): "
[709]1817                "TIMER channel already released for thread %x\n", trdid );
[714]1818
1819        return SYSCALL_CHANNEL_ALREADY_ALLOCATED;
[709]1820    }
1821
1822    // reset CTX_TIM_ID for the calling thread
1823    _set_context_slot( CTX_TIM_ID , 0xFFFFFFFF );
1824
1825    // reset the _tim_channel_alloc[] array
1826    _tim_channel_alloc[channel] = 0;
1827
1828    // release WTI mailbox if TTY channel no more used
1829    if ( USE_PIC ) 
1830    {
1831        _ext_irq_release( PERIPH_TYPE_TIM , channel );
1832    }
1833
[714]1834    return SYSCALL_OK;
[709]1835
1836#else
1837
[714]1838    _printf("\n[GIET ERROR] in _sys_tim_release(): NB_TIM_CHANNELS = 0\n");
[709]1839
[714]1840    return SYSCALL_NO_CHANNEL_AVAILABLE;
1841
[709]1842#endif
1843}  // end _sys_tim_release()
1844
[440]1845/////////////////////////////////////////
1846int _sys_tim_start( unsigned int period )
1847{
[709]1848
1849#if NB_TIM_CHANNELS
1850
[440]1851    // get timer index
1852    unsigned int channel = _get_context_slot( CTX_TIM_ID );
[714]1853
[440]1854    if ( channel >= NB_TIM_CHANNELS )
1855    {
[714]1856        _printf("\n[GIET_ERROR] in _sys_tim_start(): not enough TIM channels\n");
1857
1858        return SYSCALL_NO_CHANNEL_AVAILABLE;
[440]1859    }
1860
1861    // start timer
1862    _timer_start( channel, period );
1863
[714]1864    return SYSCALL_OK;
[709]1865
1866#else
1867
1868    _printf("\n[GIET ERROR] in _sys_tim_start() : NB_TIM_CHANNELS = 0\n");
1869
[714]1870    return SYSCALL_NO_CHANNEL_AVAILABLE;
1871
[709]1872#endif
[440]1873}
1874
1875///////////////////
1876int _sys_tim_stop()
1877{
[709]1878
1879#if NB_TIM_CHANNELS
1880
[440]1881    // get timer index
1882    unsigned int channel = _get_context_slot( CTX_TIM_ID );
[714]1883
[440]1884    if ( channel >= NB_TIM_CHANNELS )
1885    {
1886        _printf("\n[GIET_ERROR] in _sys_tim_stop() : illegal timer index\n");
[714]1887
1888        return SYSCALL_CHANNEL_NON_ALLOCATED;
[440]1889    }
1890
1891    // stop timer
1892    _timer_stop( channel );
1893
[714]1894    return SYSCALL_OK;
[709]1895
1896#else
1897
1898    _printf("\n[GIET ERROR] in _sys_tim_stop() : NB_TIM_CHANNELS = 0\n");
1899
[714]1900    return SYSCALL_NO_CHANNEL_AVAILABLE;
1901
[709]1902#endif
[440]1903}
1904
[709]1905
[440]1906//////////////////////////////////////////////////////////////////////////////
1907//             NIC related syscall handlers
1908//////////////////////////////////////////////////////////////////////////////
1909
[478]1910#define NIC_CONTAINER_SIZE 4096
1911
[709]1912#if NB_NIC_CHANNELS
1913
[494]1914////////////////////////////////////////
1915int _sys_nic_alloc( unsigned int is_rx,
1916                    unsigned int xmax,
1917                    unsigned int ymax )
[440]1918{
[709]1919    mapping_header_t  *header   = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
1920    mapping_vspace_t  *vspace   = _get_vspace_base(header);
1921    mapping_thread_t  *thread   = _get_thread_base(header);
1922
1923    // get calling thread trdid, vspace index, and number of threads
1924    unsigned int trdid = _get_thread_trdid();
1925    unsigned int vsid  = _get_context_slot( CTX_VSID_ID );
1926    unsigned int users = vspace[vsid].threads;
1927
[494]1928    // check xmax / ymax parameters
[709]1929    if ( (xmax > X_SIZE) || (ymax > Y_SIZE) )
[494]1930    {
[709]1931        _printf("\n[GIET_ERROR] in _sys_nic_alloc() "
1932                "xmax or ymax argument too large for thread %x\n", trdid );
[714]1933
[725]1934        return SYSCALL_ILLEGAL_ARGUMENT;
[494]1935    }
[459]1936
[614]1937    ////////////////////////////////////////////////////////
1938    // Step 1: get and register CMA and NIC channel index //
1939    ////////////////////////////////////////////////////////
1940
[709]1941    unsigned int   nic_channel;
1942    unsigned int   cma_channel;
1943    unsigned int*  palloc;
[440]1944
[709]1945    // get a NIC_RX or NIC_TX channel
1946    for ( nic_channel = 0 ; nic_channel < NB_NIC_CHANNELS ; nic_channel++ )
1947    {
1948        if ( is_rx ) palloc = &_nic_rx_channel_alloc[nic_channel];
1949        else         palloc = &_nic_tx_channel_alloc[nic_channel];
[449]1950
[709]1951        if ( _atomic_test_and_set( palloc , users ) == 0 ) break;
1952    }
[449]1953    if ( (nic_channel >= NB_NIC_CHANNELS) )
[440]1954    {
[709]1955        _printf("\n[GIET_ERROR] in _sys_nic_alloc() : "
1956                "no NIC channel available for thread %x\n", trdid );
[714]1957
1958        return SYSCALL_NO_CHANNEL_AVAILABLE;
[440]1959    }
[449]1960
[709]1961    // get a CMA channel
[699]1962    for ( cma_channel = 0 ; cma_channel < NB_CMA_CHANNELS ; cma_channel++ )
1963    {
[709]1964        palloc = &_cma_channel_alloc[cma_channel];
1965
1966        if ( _atomic_test_and_set( palloc , users ) == 0 ) break;
[699]1967    }
[449]1968    if ( cma_channel >= NB_CMA_CHANNELS )
1969    {
[709]1970        _printf("\n[GIET_ERROR] in _sys_nic_alloc() : "
1971                "no CMA channel available for thread %x\n", trdid );
1972        if ( is_rx )  _nic_rx_channel_alloc[nic_channel] = 0;
1973        else          _nic_tx_channel_alloc[nic_channel] = 0;
[714]1974
1975        return SYSCALL_NO_CHANNEL_AVAILABLE;
[449]1976    }
[459]1977
[494]1978#if GIET_DEBUG_NIC
[714]1979_printf("\n[DEBUG NIC] sys_nic_alloc() at cycle %d\n"
1980        "thread %d get nic_channel = %d / cma_channel = %d\n",
1981        _get_proctime() , trdid , nic_channel , cma_channel );
[494]1982#endif
1983
[709]1984    // register nic_index and cma_index in all threads
1985    // contexts that are in the same vspace
1986    unsigned int tid;
1987    for (tid = vspace[vsid].thread_offset;
1988         tid < (vspace[vsid].thread_offset + vspace[vsid].threads);
1989         tid++)
[449]1990    {
[709]1991        unsigned int y_size        = header->y_size;
1992        unsigned int cid           = thread[tid].clusterid;
1993        unsigned int x             = cid / y_size;
1994        unsigned int y             = cid % y_size;
1995        unsigned int p             = thread[tid].proclocid;
1996        unsigned int ltid          = thread[tid].ltid;
1997        static_scheduler_t* psched = (static_scheduler_t*)_schedulers[x][y][p];
[440]1998
[709]1999        if ( is_rx )
2000        {
2001            if ( (psched->context[ltid].slot[CTX_NIC_RX_ID] < NB_NIC_CHANNELS) ||
2002                 (psched->context[ltid].slot[CTX_CMA_RX_ID] < NB_CMA_CHANNELS) )
2003            {
2004                _printf("\n[GIET_ERROR] in _sys_nic_alloc() : "
2005                        "NIC_RX or CMA_RX channel already allocated for thread %x\n", trdid );
2006                _nic_rx_channel_alloc[nic_channel] = 0;
2007                _cma_channel_alloc[cma_channel]    = 0;
[714]2008
2009                return SYSCALL_CHANNEL_ALREADY_ALLOCATED;
[709]2010            }
2011            else
2012            {
2013                psched->context[ltid].slot[CTX_NIC_RX_ID] = nic_channel;
2014                psched->context[ltid].slot[CTX_CMA_RX_ID] = cma_channel;
2015            }
2016        }
2017        else // is_tx
2018        {
2019            if ( (psched->context[ltid].slot[CTX_NIC_TX_ID] < NB_NIC_CHANNELS) ||
2020                 (psched->context[ltid].slot[CTX_CMA_TX_ID] < NB_CMA_CHANNELS) )
2021            {
2022                _printf("\n[GIET_ERROR] in _sys_nic_alloc() : "
2023                        "NIC_TX or CMA_TX channel already allocated for thread %x\n", trdid );
2024                _nic_tx_channel_alloc[nic_channel] = 0;
2025                _cma_channel_alloc[cma_channel]    = 0;
[714]2026
2027                return SYSCALL_CHANNEL_ALREADY_ALLOCATED;
[709]2028            }
2029            else
2030            {
2031                psched->context[ltid].slot[CTX_NIC_TX_ID] = nic_channel;
2032                psched->context[ltid].slot[CTX_CMA_TX_ID] = cma_channel;
2033            }
2034        }
2035    }  // end loop on threads
2036
[614]2037    /////////////////////////////////////////////////////////////////////////////////
2038    // Step 2: loop on all the clusters                                            //
2039    // Allocate the kernel containers and status, compute the container and the    //
2040    // status physical addresses, fill and synchronize the kernel CHBUF descriptor //
2041    /////////////////////////////////////////////////////////////////////////////////
2042
[494]2043    // physical addresses to be registered in the CMA registers
[459]2044    unsigned long long nic_chbuf_pbase;     // NIC chbuf physical address
2045    unsigned long long ker_chbuf_pbase;     // kernel chbuf physical address
[449]2046
[614]2047    // allocate one kernel container and one status variable per cluster in the
2048    // (xmax / ymax) mesh
[528]2049    unsigned int        cx;                 // cluster X coordinate
2050    unsigned int        cy;                 // cluster Y coordinate
2051    unsigned int        index;              // container index in chbuf
2052    unsigned int        vaddr;              // virtual address
2053    unsigned long long  cont_paddr;         // container physical address
[614]2054    unsigned long long  sts_paddr;          // container status physical address
[494]2055
[528]2056    unsigned int        flags;              // for _v2p_translate()
2057
[494]2058    for ( cx = 0 ; cx < xmax ; cx++ )
[478]2059    {
[494]2060        for ( cy = 0 ; cy < ymax ; cy++ )
[478]2061        {
2062            // compute index in chbuf
[494]2063            index = (cx * ymax) + cy; 
[478]2064
[494]2065            // allocate the kernel container
[478]2066            vaddr = (unsigned int)_remote_malloc( NIC_CONTAINER_SIZE, cx, cy );
2067
[494]2068            if ( vaddr == 0 )  // not enough kernel heap memory in cluster[cx,cy]
2069            {
[709]2070                _printf("\n[GIET_ERROR] in _sys_nic_alloc() : "
[714]2071                        "not enough kernel heap in cluster[%d,%d]\n", cx, cy );
2072
2073                return SYSCALL_OUT_OF_KERNEL_HEAP_MEMORY;
[494]2074            }
2075
[478]2076            // compute container physical address
[528]2077            cont_paddr = _v2p_translate( vaddr , &flags );
[478]2078
[614]2079            // checking container address alignment
2080            if ( cont_paddr & 0x3F )
2081            {
[709]2082                _printf("\n[GIET ERROR] in _sys_nic_alloc() : "
[714]2083                        "container address in cluster[%d,%d] not aligned\n", cx, cy);
2084
2085                return SYSCALL_ADDRESS_NON_ALIGNED;
[614]2086            }
2087
2088#if GIET_DEBUG_NIC
[714]2089_printf("\n[DEBUG NIC] _sys_nic_alloc() at cycle %d\n"
2090        "thread %x allocates a container in cluster[%d,%d] / vaddr = %x / paddr = %l\n",
2091        -get_proctime() , trdid , cx , cy , vaddr, cont_paddr );
[614]2092#endif
2093
2094            // allocate the kernel container status
2095            // it occupies 64 bytes but only last bit is useful (1 for full and 0 for empty)
2096            vaddr = (unsigned int)_remote_malloc( 64, cx, cy );
2097
2098            if ( vaddr == 0 )  // not enough kernel heap memory in cluster[cx,cy]
2099            {
[709]2100                _printf("\n[GIET_ERROR] in _sys_nic_alloc() : "
2101                        "not enough kernel heap in cluster[%d,%d]\n", cx, cy );
[714]2102
2103                return SYSCALL_OUT_OF_KERNEL_HEAP_MEMORY;
[614]2104            }
2105
2106            // compute status physical address
2107            sts_paddr = _v2p_translate( vaddr , &flags );
2108
2109            // checking status address alignment
2110            if ( sts_paddr & 0x3F )
2111            {
[709]2112                _printf("\n[GIET ERROR] in _sys_nic_alloc() : "
[714]2113                        "status address in cluster[%d,%d] not aligned\n", cx, cy);
2114
2115                return SYSCALL_ADDRESS_NON_ALIGNED;
[614]2116            }
2117
[494]2118            // initialize chbuf entry
[614]2119            // The buffer descriptor has the following structure:
2120            // - the 26 LSB bits contain bits[6:31] of the buffer physical address
2121            // - the 26 following bits contain bits[6:31] of the physical address where the
2122            //   buffer status is located
2123            // - the 12 MSB bits contain the common address extension of the buffer and its
2124            //   status
2125            if ( is_rx )
2126                _nic_ker_rx_chbuf[nic_channel].buf_desc[index] =
2127                    (unsigned long long)
2128                    ((sts_paddr & 0xFFFFFFFFULL) >> 6) +
2129                    (((cont_paddr & 0xFFFFFFFFFFFULL) >> 6) << 26);
2130            else
2131                _nic_ker_tx_chbuf[nic_channel].buf_desc[index] =
2132                    (unsigned long long)
2133                    ((sts_paddr & 0xFFFFFFC0ULL) >> 6) +
2134                    (((cont_paddr & 0xFFFFFFFFFC0ULL) >> 6) << 26);
[478]2135
2136#if GIET_DEBUG_NIC
[714]2137_printf("\n[DEBUG NIC] _sys_nic_alloc() at cycle %d\n"
2138        "thread %x allocates a status in cluster[%d,%d] / vaddr = %x / paddr = %l\n"
2139        "   descriptor = %l\n",
2140        _get_proctime() , trdid , cx , cy , vaddr, sts_paddr,
[614]2141        (unsigned long long)((sts_paddr & 0xFFFFFFFFULL) >> 6) + 
2142        (((cont_paddr & 0xFFFFFFFFFFFULL) >> 6) << 26) );
[478]2143#endif
2144        }
2145    }
2146
[494]2147    // complete kernel chbuf initialisation
2148    if ( is_rx )
2149    {
[614]2150        _nic_ker_rx_chbuf[nic_channel].xmax = xmax;
2151        _nic_ker_rx_chbuf[nic_channel].ymax = ymax;
[494]2152    }
2153    else
2154    {
[614]2155        _nic_ker_tx_chbuf[nic_channel].xmax = xmax;
2156        _nic_ker_tx_chbuf[nic_channel].ymax = ymax;
[494]2157    }
2158
[449]2159    // compute the kernel chbuf descriptor physical address
[614]2160    if ( is_rx ) vaddr = (unsigned int)( &_nic_ker_rx_chbuf[nic_channel] );
2161    else         vaddr = (unsigned int)( &_nic_ker_tx_chbuf[nic_channel] );
[440]2162
[528]2163    ker_chbuf_pbase = _v2p_translate( vaddr , &flags );
2164
[459]2165#if GIET_DEBUG_NIC
[714]2166_printf("\n[DEBUG NIC] _sys_nic_alloc() at cycle %d\n"
2167        "thread %x initialise kernel chbuf / vaddr = %x / paddr = %l\n",
2168        _get_proctime() , trdid , vaddr , ker_chbuf_pbase );
[459]2169#endif
[440]2170
[459]2171    // sync the kernel chbuf in L2 after write in L2
[725]2172    _mmc_sync( ker_chbuf_pbase, sizeof( nic_chbuf_t ) );
[459]2173
[614]2174    ///////////////////////////////////////////////////////////////
2175    // Step 3: compute the NIC chbuf descriptor physical address //
2176    ///////////////////////////////////////////////////////////////
2177
2178    unsigned int offset;
2179    if ( is_rx ) offset = 0x4100;
2180    else         offset = 0x4110;
2181    nic_chbuf_pbase = (((unsigned long long)((X_IO << Y_WIDTH) + Y_IO))<<32) |
2182                      (SEG_NIC_BASE + (nic_channel<<15) + offset);
2183
2184#if GIET_DEBUG_NIC
[714]2185_printf("\n[DEBUG NIC] _sys_nic_alloc() at cycle %d\n"
2186        "thread %x get NIC chbuf paddr = %l\n",
2187        _get_proctime() , trdid , nic_chbuf_pbase );
[614]2188#endif
2189
2190    ////////////////////////////////////////////////////////////////////////////////
2191    // Step 4: initialize CMA registers defining the source & destination chbufs //
2192    ////////////////////////////////////////////////////////////////////////////////
2193
[459]2194    if ( is_rx )               // NIC to kernel
2195    {
2196        _cma_set_register( cma_channel, CHBUF_SRC_DESC , (unsigned int)(nic_chbuf_pbase) );
2197        _cma_set_register( cma_channel, CHBUF_SRC_EXT  , (unsigned int)(nic_chbuf_pbase>>32) );
2198        _cma_set_register( cma_channel, CHBUF_SRC_NBUFS, 2 );
2199        _cma_set_register( cma_channel, CHBUF_DST_DESC , (unsigned int)(ker_chbuf_pbase) );
2200        _cma_set_register( cma_channel, CHBUF_DST_EXT  , (unsigned int)(ker_chbuf_pbase>>32) );
[494]2201        _cma_set_register( cma_channel, CHBUF_DST_NBUFS, xmax * ymax );
[459]2202    }
2203    else                      // kernel to NIC
2204    {
2205        _cma_set_register( cma_channel, CHBUF_SRC_DESC , (unsigned int)(ker_chbuf_pbase) );
2206        _cma_set_register( cma_channel, CHBUF_SRC_EXT  , (unsigned int)(ker_chbuf_pbase>>32) );
[494]2207        _cma_set_register( cma_channel, CHBUF_SRC_NBUFS, xmax * ymax );
[459]2208        _cma_set_register( cma_channel, CHBUF_DST_DESC , (unsigned int)(nic_chbuf_pbase) );
2209        _cma_set_register( cma_channel, CHBUF_DST_EXT  , (unsigned int)(nic_chbuf_pbase>>32) );
2210        _cma_set_register( cma_channel, CHBUF_DST_NBUFS, 2 );
2211    }
2212
[494]2213#if GIET_DEBUG_NIC
[714]2214_printf("\n[DEBUG NIC] _sys_nic_alloc() at cycle %d\n"
2215        "thread %x exit\n", 
2216        _get_proctime() , trdid );
[494]2217#endif
2218
[714]2219    return SYSCALL_OK;
[494]2220} // end _sys_nic_alloc()
2221
2222
[709]2223//////////////////////////////////////////
[714]2224int _sys_nic_release( unsigned int is_rx )     // NOTE: not a syscall: used by _ctx_kill_thread()
[695]2225{
[709]2226    unsigned int trdid = _get_thread_trdid();
2227
2228    unsigned int nic_channel;
2229    unsigned int cma_channel;
2230   
2231    // update the kernel tables
[695]2232    if ( is_rx )
[709]2233    {
2234        nic_channel = _get_context_slot( CTX_NIC_RX_ID );
2235        cma_channel = _get_context_slot( CTX_CMA_RX_ID );
2236
2237        if ( (nic_channel >= NB_NIC_CHANNELS) )
2238        {
2239            _printf("\n[GIET ERROR] in _sys_nic_release() : "
2240                    "NIC_RX channel already released for thread %x\n", trdid );
[714]2241
2242            return SYSCALL_CHANNEL_NON_ALLOCATED;
[709]2243        }
2244        if ( (cma_channel >= NB_CMA_CHANNELS) )
2245        {
2246            _printf("\n[GIET ERROR] in _sys_nic_release() : "
2247                    "CMA_RX channel already released for thread %x\n", trdid );
[714]2248
2249            return SYSCALL_CHANNEL_NON_ALLOCATED;
[709]2250        }
2251
2252        // atomically decrement the NIC and CMA channel allocators
2253        _atomic_increment( &_nic_rx_channel_alloc[nic_channel] , -1 );
2254        _atomic_increment( &_cma_channel_alloc[cma_channel] , -1 );
2255   
2256        // stop the NIC and CMA peripherals channels if no more users
2257        if ( (_nic_rx_channel_alloc[nic_channel] == 0) &&
2258             (_cma_channel_alloc[cma_channel] == 0) )  _sys_nic_stop( 1 );
2259
2260        // reset the calling thread context slots
2261        _set_context_slot( CTX_NIC_RX_ID , 0xFFFFFFFF );
2262        _set_context_slot( CTX_CMA_RX_ID , 0xFFFFFFFF );
2263    }         
[695]2264    else
[709]2265    {
2266        nic_channel = _get_context_slot( CTX_NIC_TX_ID );
2267        cma_channel = _get_context_slot( CTX_CMA_TX_ID );
[695]2268
[709]2269        if ( (nic_channel >= NB_NIC_CHANNELS) )
2270        {
2271            _printf("\n[GIET ERROR] in _sys_nic_release() : "
2272                    "NIC_TX channel already released for thread %x\n", trdid );
[714]2273
2274            return SYSCALL_CHANNEL_NON_ALLOCATED;
[709]2275        }
2276        if ( (cma_channel >= NB_CMA_CHANNELS) )
2277        {
2278            _printf("\n[GIET ERROR] in _sys_nic_release() : "
2279                    "CMA_TX channel already released for thread %x\n", trdid );
[714]2280
2281            return SYSCALL_CHANNEL_NON_ALLOCATED;
[709]2282        }
[695]2283
[709]2284        // atomically decrement the NIC and CMA channel allocators
2285        _atomic_increment( &_nic_tx_channel_alloc[nic_channel] , -1 );
2286        _atomic_increment( &_cma_channel_alloc[cma_channel] , -1 );
2287   
2288        // stop the NIC and CMA peripherals channels if no more users
2289        if ( (_nic_tx_channel_alloc[nic_channel] == 0) &&
2290             (_cma_channel_alloc[cma_channel] == 0) )  _sys_nic_stop( 0 );
[695]2291
[709]2292        // reset the calling thread context slots
2293        _set_context_slot( CTX_NIC_TX_ID , 0xFFFFFFFF );
2294        _set_context_slot( CTX_CMA_TX_ID , 0xFFFFFFFF );
2295    }
2296
[714]2297    return SYSCALL_OK;
[709]2298}  // end sys_nic_release()
2299
2300
[695]2301////////////////////////////////////////
[709]2302int _sys_nic_start( unsigned int is_rx )
[494]2303{
[709]2304    unsigned int trdid  = _get_context_slot( CTX_TRDID_ID );
2305
[494]2306    unsigned int nic_channel;
2307    unsigned int cma_channel;
2308
[709]2309    // get NIC channel index and CMA channel index from thread context
[494]2310    if ( is_rx )
2311    {
2312        nic_channel = _get_context_slot( CTX_NIC_RX_ID );
2313        cma_channel = _get_context_slot( CTX_CMA_RX_ID );
2314    }
2315    else
2316    {
2317        nic_channel = _get_context_slot( CTX_NIC_TX_ID );
2318        cma_channel = _get_context_slot( CTX_CMA_TX_ID );
2319    }
2320
2321#if GIET_DEBUG_NIC
[714]2322_printf("\n[DEBUG NIC] _sys_nic_start() at cycle %d\n"
2323        "thread %x enter / NIC channel = %d / CMA channel = %d\n",
2324        _get_proctime() , trdid , nic_channel, cma_channel );
[494]2325#endif
2326
2327    // check NIC and CMA channels index
[709]2328    if ( nic_channel >= NB_NIC_CHANNELS )
[494]2329    {
[709]2330        _printf("\n[GIET_ERROR] in _sys_nic_start() : "
2331                "illegal NIC channel for thread %x\n", trdid );
2332        return -1111;
[494]2333    }
2334    if ( cma_channel >= NB_CMA_CHANNELS )
2335    {
[709]2336        _printf("\n[GIET_ERROR] in _sys_nic_start() : "
2337                "illegal CMA channel for thread %x\n", trdid );
2338        return -1111;
[494]2339    }
2340
[449]2341    // start CMA transfer
[478]2342    _cma_set_register( cma_channel, CHBUF_BUF_SIZE , NIC_CONTAINER_SIZE );
[725]2343    _cma_set_register( cma_channel, CHBUF_PERIOD   , 0 );                  // OUT_OF_ORDER
2344    _cma_set_register( cma_channel, CHBUF_RUN      , MODE_NORMAL );
[449]2345
2346    // activates NIC channel
[614]2347    _nic_channel_start( nic_channel, is_rx, GIET_NIC_MAC4, GIET_NIC_MAC2 );
[459]2348
2349#if GIET_DEBUG_NIC
[714]2350    _printf("\n[DEBUG NIC] _sys_nic_start() at cycle %d\n"
2351            "thread %d exit\n",
2352            _get_proctime() , trdid );
[459]2353#endif
2354
[714]2355    return SYSCALL_OK;
[505]2356}  // end _sys_nic_start()
[449]2357
[494]2358
[449]2359//////////////////////////////////////
2360int _sys_nic_move( unsigned int is_rx,
2361                   void*        buffer )
2362{
[709]2363    unsigned int trdid  = _get_context_slot( CTX_TRDID_ID );
[449]2364
[709]2365    unsigned int channel;
2366
[459]2367#if GIET_DEBUG_NIC
[714]2368_printf("\n[DEBUG NIC] _sys_nic_move() at cycle %d\n",
2369        "thread %x enters\n",
2370        _get_proctime() , trdid );
[459]2371#endif
2372
[709]2373    // get NIC channel index from thread context
2374    if ( is_rx )  channel = _get_context_slot( CTX_NIC_RX_ID );
2375    else          channel = _get_context_slot( CTX_NIC_TX_ID );
2376
[494]2377    // check NIC channel index
2378    if ( channel >= NB_NIC_CHANNELS )
2379    {
[709]2380        _printf("\n[GIET_ERROR] in _sys_nic_move() : "
[714]2381                "NIC channel non allocated for thread %x\n", trdid );
2382
2383        return SYSCALL_CHANNEL_NON_ALLOCATED;
[494]2384    }
2385
2386    // get kernel chbuf virtual address
[725]2387    nic_chbuf_t* ker_chbuf;
[614]2388    if ( is_rx )  ker_chbuf = &_nic_ker_rx_chbuf[channel];
2389    else          ker_chbuf = &_nic_ker_tx_chbuf[channel];
[494]2390
2391    // get xmax / ymax parameters
[614]2392    unsigned int xmax = ker_chbuf->xmax;
2393    unsigned int ymax = ker_chbuf->ymax;
[494]2394
[709]2395    // get cluster coordinates for the processor running the calling thread
[478]2396    unsigned int  procid = _get_procid();
2397    unsigned int  cx     = procid >> (Y_WIDTH + P_WIDTH);
2398    unsigned int  cy     = (procid >> P_WIDTH) & ((1<<Y_WIDTH)-1);
2399   
[494]2400    // check processor coordinates / (xmax,ymax)
[714]2401    if ( (cx >= xmax) || (cy >= ymax) )
[494]2402    {
[714]2403        _printf("\n[GIET_ERROR] in _sys_nic_move(): "
2404         "processor coordinates [%d,%d] larger than (xmax,ymax) = [%d,%d]\n",
2405         cx , cy , xmax , ymax );
2406
[725]2407        return SYSCALL_ILLEGAL_ARGUMENT;
[494]2408    }
2409   
[614]2410    unsigned long long usr_buf_paddr;       // user buffer physical address
2411    unsigned long long ker_buf_paddr;       // kernel buffer physical address
2412    unsigned long long ker_sts_paddr;       // kernel buffer status physical address
2413    unsigned long long ker_buf_desc;        // kernel buffer descriptor
2414    unsigned int       ker_sts;             // kernel buffer status (full or empty)
2415    unsigned int       index;               // kernel buffer index in chbuf
2416    unsigned int       flags;               // for _v2P_translate
[459]2417
2418    // Compute user buffer physical address and check access rights
[614]2419    usr_buf_paddr = _v2p_translate( (unsigned int)buffer , &flags );
[478]2420
[440]2421    if ( (flags & PTE_U) == 0 )
2422    {
[714]2423        _printf("\n[GIET ERROR] in _sys_nic_tx_move() : "
2424                "buffer address non user accessible\n");
2425
2426        return SYSCALL_ADDRESS_NON_USER_ACCESSIBLE;
[440]2427    }
2428
[459]2429#if GIET_DEBUG_NIC
[714]2430_printf("\n[DEBUG NIC] _sys_nic_move() at cycle %d\n"
2431        "thread %x get user buffer : paddr = %l\n",
2432        _get_proctime() , trdid , usr_buf_paddr );
[459]2433#endif
[440]2434
[614]2435    // compute buffer index, buffer descriptor paddr and buffer status paddr
2436    index = (ymax * cx) + cy;
2437    ker_buf_desc = ker_chbuf->buf_desc[index];
2438    ker_sts_paddr = ((ker_buf_desc & 0xFFF0000000000000ULL) >> 20) +
2439                    ((ker_buf_desc & 0x3FFFFFFULL) << 6);
[459]2440
[614]2441#if GIET_DEBUG_NIC
[714]2442_printf("\n[DEBUG NIC] _sys_nic_move() at cycle %d\n"
2443        "thread %x get ker_buf_desc %d / paddr = %l\n",
2444        _get_proctime(), trdid , index , ker_buf_desc );
[614]2445#endif
2446
[494]2447    // poll local kernel container status until success
[478]2448    while ( 1 )
[449]2449    {
[478]2450        // inval buffer descriptor in L2 before read in L2
[614]2451        _mmc_inval( ker_sts_paddr, 4 );
2452        ker_sts = _physical_read( ker_sts_paddr );
[459]2453
2454#if GIET_DEBUG_NIC
[714]2455_printf("\n[DEBUG NIC] _sys_nic_move() at cycle %d\n"
2456        "thread %x get status %d /  paddr = %l / status = %x\n",
2457        _get_proctime() , trdid , index , ker_sts_paddr, ker_sts );
[459]2458#endif
2459
[478]2460        // test buffer status and break if found
[614]2461        if ( ( is_rx != 0 ) && ( ker_sts == 0x1 ) ) break;
2462        if ( ( is_rx == 0 ) && ( ker_sts == 0 ) ) break;
[449]2463    }
[459]2464
2465    // compute kernel buffer physical address
[614]2466    ker_buf_paddr = (ker_buf_desc & 0xFFFFFFFFFC000000ULL) >> 20;
[449]2467   
[494]2468    // move one container
2469    if ( is_rx )              // RX transfer
[459]2470    {
2471        // inval kernel buffer in L2 before read in L2
[614]2472        _mmc_inval( ker_buf_paddr, NIC_CONTAINER_SIZE );
[449]2473
[459]2474        // transfer data from kernel buffer to user buffer
[614]2475        _physical_memcpy( usr_buf_paddr, 
2476                          ker_buf_paddr, 
[478]2477                          NIC_CONTAINER_SIZE );
2478#if GIET_DEBUG_NIC
[714]2479_printf("\n[DEBUG NIC] _sys_nic_move() at cycle %d\n"
2480        "thread %x transfer kernel buffer %l to user buffer %l\n",
2481        _get_proctime() , trdid , ker_buf_paddr , usr_buf_paddr );
[478]2482#endif
[449]2483
[459]2484    }
[494]2485    else                      // TX transfer
[459]2486    {
2487        // transfer data from user buffer to kernel buffer
[614]2488        _physical_memcpy( ker_buf_paddr, 
2489                          usr_buf_paddr, 
[478]2490                          NIC_CONTAINER_SIZE );
[449]2491
[459]2492        // sync kernel buffer in L2 after write in L2
[614]2493        _mmc_sync( ker_buf_paddr, NIC_CONTAINER_SIZE );
[478]2494
2495#if GIET_DEBUG_NIC
[714]2496_printf("\n[DEBUG NIC] _sys_nic_move() at cycle %d\n"
2497        "thread %x transfer user buffer %l to kernel buffer %l\n",
2498        _get_proctime() , trdid , usr_buf_paddr , ker_buf_paddr );
[478]2499#endif
2500
[459]2501    }
2502
[478]2503    // update kernel chbuf status
[614]2504    if ( is_rx ) _physical_write ( ker_sts_paddr, 0 );
2505    else         _physical_write ( ker_sts_paddr, 0x1 );
[459]2506
2507    // sync kernel chbuf in L2 after write in L2
[614]2508    _mmc_sync( ker_sts_paddr, 4 );
[459]2509
2510#if GIET_DEBUG_NIC
[714]2511_printf("\n[DEBUG NIC] _sys_nic_move() at cycle %d\n"
2512        "thread %x exit\n",
2513        _get_proctime() , trdid );
[459]2514#endif
2515
[714]2516    return SYSCALL_OK;
[449]2517} // end _sys_nic_move()
[440]2518
[494]2519
[709]2520///////////////////////////////////////
2521int _sys_nic_stop( unsigned int is_rx )
[440]2522{
[709]2523    unsigned int trdid  = _get_context_slot( CTX_TRDID_ID );
2524
[449]2525    unsigned int nic_channel;
2526    unsigned int cma_channel;
[440]2527
[449]2528    // get NIC channel index and CMA channel index
2529    if ( is_rx )
[440]2530    {
[449]2531        nic_channel = _get_context_slot( CTX_NIC_RX_ID );
2532        cma_channel = _get_context_slot( CTX_CMA_RX_ID );
[440]2533    }
[449]2534    else
2535    {
2536        nic_channel = _get_context_slot( CTX_NIC_TX_ID );
2537        cma_channel = _get_context_slot( CTX_CMA_TX_ID );
2538    }
[440]2539
[494]2540    // check NIC and CMA channels index
[709]2541    if ( nic_channel >= NB_NIC_CHANNELS )
[440]2542    {
[709]2543        _printf("\n[GIET_ERROR] in _sys_nic_stop() : " 
[714]2544                "NIC channel non allocated for thread %x\n", trdid );
2545
2546        return SYSCALL_CHANNEL_NON_ALLOCATED;
[440]2547    }
[449]2548    if ( cma_channel >= NB_CMA_CHANNELS )
[440]2549    {
[709]2550        _printf("\n[GIET_ERROR] in _sys_nic_stop() : "
[714]2551                "CMA channel non allocated for thread %x\n", trdid );
2552 
2553        return SYSCALL_CHANNEL_NON_ALLOCATED;
[440]2554    }
2555
[709]2556    // desactivates the CMA channel
[725]2557    _cma_set_register( cma_channel, CHBUF_RUN , MODE_IDLE );
[709]2558
2559    // wait until CMA channel IDLE
2560    unsigned int volatile status;
2561    do
2562    {
2563         status = _cma_get_register( cma_channel, CHBUF_STATUS );
[714]2564    } 
2565    while ( status ); 
[709]2566
[449]2567    // desactivates the NIC channel
2568    _nic_channel_stop( nic_channel, is_rx );
[440]2569
[714]2570    return SYSCALL_OK;
[494]2571}  // end _sys_nic_stop()
[440]2572
[459]2573////////////////////////////////////////
[709]2574int _sys_nic_clear( unsigned int is_rx )
[459]2575{
[709]2576    unsigned int trdid  = _get_context_slot( CTX_TRDID_ID );
[459]2577
[709]2578    unsigned int channel;
2579
[459]2580    // get NIC channel
[709]2581    if ( is_rx )  channel = _get_context_slot( CTX_NIC_RX_ID );
2582    else          channel = _get_context_slot( CTX_NIC_TX_ID );
[459]2583
[709]2584    if ( channel >= NB_NIC_CHANNELS )
[459]2585    {
[709]2586        _printf("\n[GIET_ERROR] in _sys_nic_clear() : "
[714]2587                "NIC channel non allocated for thread %x\n", trdid );
2588
2589        return SYSCALL_CHANNEL_NON_ALLOCATED;
[459]2590    }
2591
2592    if ( is_rx )
2593    {
2594        _nic_set_global_register( NIC_G_NPKT_RX_G2S_RECEIVED       , 0 );
2595        _nic_set_global_register( NIC_G_NPKT_RX_DES_TOO_SMALL      , 0 );
2596        _nic_set_global_register( NIC_G_NPKT_RX_DES_TOO_BIG        , 0 );
2597        _nic_set_global_register( NIC_G_NPKT_RX_DES_MFIFO_FULL     , 0 );
2598        _nic_set_global_register( NIC_G_NPKT_RX_DES_CRC_FAIL       , 0 );
2599        _nic_set_global_register( NIC_G_NPKT_RX_DISPATCH_RECEIVED  , 0 );
2600        _nic_set_global_register( NIC_G_NPKT_RX_DISPATCH_BROADCAST , 0 );
2601        _nic_set_global_register( NIC_G_NPKT_RX_DISPATCH_DST_FAIL  , 0 );
2602        _nic_set_global_register( NIC_G_NPKT_RX_DISPATCH_CH_FULL   , 0 );
2603    } 
2604    else
2605    {
2606        _nic_set_global_register( NIC_G_NPKT_TX_DISPATCH_RECEIVED  , 0 );
2607        _nic_set_global_register( NIC_G_NPKT_TX_DISPATCH_TRANSMIT  , 0 );
2608        _nic_set_global_register( NIC_G_NPKT_TX_DISPATCH_TOO_BIG   , 0 );
2609        _nic_set_global_register( NIC_G_NPKT_TX_DISPATCH_TOO_SMALL , 0 );
2610        _nic_set_global_register( NIC_G_NPKT_TX_DISPATCH_SRC_FAIL  , 0 );
2611        _nic_set_global_register( NIC_G_NPKT_TX_DISPATCH_BYPASS    , 0 );
2612        _nic_set_global_register( NIC_G_NPKT_TX_DISPATCH_BROADCAST , 0 );
2613    }
[714]2614    return SYSCALL_OK;
[494]2615}  // en _sys_nic_clear()
[459]2616
2617////////////////////////////////////////
[709]2618int _sys_nic_stats( unsigned int is_rx )
[459]2619{
[709]2620    unsigned int trdid  = _get_context_slot( CTX_TRDID_ID );
2621
[459]2622    unsigned int nic_channel;
2623
2624    // get NIC channel
2625    if ( is_rx )  nic_channel = _get_context_slot( CTX_NIC_RX_ID );
2626    else          nic_channel = _get_context_slot( CTX_NIC_TX_ID );
2627
[709]2628    if ( nic_channel >= NB_NIC_CHANNELS )
[459]2629    {
[709]2630        _printf("\n[GIET_ERROR] in _sys_nic_stats() : "
[714]2631                "NIC channel non allocated for thread %x\n", trdid );
2632
2633        return SYSCALL_CHANNEL_NON_ALLOCATED;
[459]2634    }
2635
2636    if ( is_rx )
2637    {
2638        unsigned int received   = _nic_get_global_register( NIC_G_NPKT_RX_G2S_RECEIVED       );
2639        unsigned int too_small  = _nic_get_global_register( NIC_G_NPKT_RX_DES_TOO_SMALL      );
2640        unsigned int too_big    = _nic_get_global_register( NIC_G_NPKT_RX_DES_TOO_BIG        );
2641        unsigned int fifo_full  = _nic_get_global_register( NIC_G_NPKT_RX_DES_MFIFO_FULL     );
2642        unsigned int crc_fail   = _nic_get_global_register( NIC_G_NPKT_RX_DES_CRC_FAIL       );
2643        unsigned int broadcast  = _nic_get_global_register( NIC_G_NPKT_RX_DISPATCH_BROADCAST );
2644        unsigned int dst_fail   = _nic_get_global_register( NIC_G_NPKT_RX_DISPATCH_DST_FAIL  );
2645        unsigned int ch_full    = _nic_get_global_register( NIC_G_NPKT_RX_DISPATCH_CH_FULL   );
2646
2647        _printf("\n### Network Controller RX Statistics ###\n"
2648                "- packets received : %d\n"
2649                "- too small        : %d\n"
2650                "- too big          : %d\n"
2651                "- fifo full        : %d\n" 
2652                "- crc fail         : %d\n" 
2653                "- dst mac fail     : %d\n" 
2654                "- channel full     : %d\n" 
2655                "- broadcast        : %d\n",
2656                received,
2657                too_small,
2658                too_big,
2659                fifo_full,
2660                crc_fail,
2661                dst_fail,
2662                ch_full,
2663                broadcast );
2664    } 
2665    else
2666    {
2667        unsigned int received   = _nic_get_global_register( NIC_G_NPKT_TX_DISPATCH_RECEIVED  );
2668        unsigned int too_big    = _nic_get_global_register( NIC_G_NPKT_TX_DISPATCH_TOO_BIG   );
2669        unsigned int too_small  = _nic_get_global_register( NIC_G_NPKT_TX_DISPATCH_TOO_SMALL );
2670        unsigned int src_fail   = _nic_get_global_register( NIC_G_NPKT_TX_DISPATCH_SRC_FAIL  );
2671        unsigned int bypass     = _nic_get_global_register( NIC_G_NPKT_TX_DISPATCH_BYPASS    );
2672        unsigned int broadcast  = _nic_get_global_register( NIC_G_NPKT_TX_DISPATCH_BROADCAST );
2673
2674        _printf("\n### Network Controller TX Statistics ###\n"
2675                "- packets received : %d\n"
2676                "- too small        : %d\n"
2677                "- too big          : %d\n"
2678                "- src mac fail     : %d\n" 
2679                "- bypass           : %d\n" 
2680                "- broadcast        : %d\n",
2681                received,
2682                too_big,
2683                too_small,
2684                src_fail,
2685                bypass,
2686                broadcast );
2687    }
[714]2688    return SYSCALL_OK;
[494]2689}  // end _sys_nic_stats()
[459]2690
[709]2691#endif
2692
[440]2693/////////////////////////////////////////////////////////////////////////////////////////
2694//    FBF related syscall handlers
2695/////////////////////////////////////////////////////////////////////////////////////////
2696
[714]2697//////////////////////////////////////
2698int _sys_fbf_size( unsigned int* width,
2699                   unsigned int* height )
2700{
2701    if ( USE_FBF == 0 )
2702    {
2703        *width  = 0;
2704        *height = 0;
2705    }
2706    else
2707    {
2708        *width  = FBUF_X_SIZE;
2709        *height = FBUF_Y_SIZE;
2710    }
2711
2712    return SYSCALL_OK;
2713}
2714
2715////////////////////
2716int _sys_fbf_alloc()
2717{
2718    mapping_header_t  *header   = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
2719    mapping_vspace_t  *vspace   = _get_vspace_base(header);
2720    mapping_thread_t  *thread   = _get_thread_base(header);
2721   
2722    // compute number of users
2723    unsigned int   vsid  = _get_context_slot(CTX_VSID_ID);
2724    unsigned int   users = vspace[vsid].threads;
2725
2726    // access FBF allocator
2727    // register it in all threads contexts
2728    if ( _atomic_test_and_set( &_fbf_alloc , users ) == 0 )     // FBF available   
2729    {
2730        unsigned int   min   = vspace[vsid].thread_offset;
2731        unsigned int   max   = min + users;
2732        unsigned int   tid;
2733        for ( tid = min ; tid < max ; tid++ )
2734        {
2735            unsigned int y_size        = header->y_size;
2736            unsigned int cid           = thread[tid].clusterid;
2737            unsigned int x             = cid / y_size;
2738            unsigned int y             = cid % y_size;
2739            unsigned int p             = thread[tid].proclocid;
2740            unsigned int ltid          = thread[tid].ltid;
2741            static_scheduler_t* psched = (static_scheduler_t*)_schedulers[x][y][p];
2742            _atomic_or( &psched->context[ltid].slot[CTX_LOCKS_ID] , LOCKS_MASK_FBF ); 
2743        }
2744        return SYSCALL_OK;
2745    }
2746    else                                                       // FBF already allocated
2747    {
2748        return SYSCALL_SHARED_PERIPHERAL_BUSY;
2749    }
2750}
2751
2752//////////////////////
2753int _sys_fbf_release()    // not a syscall: used by _ctx_kill_thread()
2754{
2755    // get calling thread scheduler, ltid and trdid
2756    static_scheduler_t*  psched = _get_sched();
2757    unsigned int         ltid   = _get_thread_ltid();
2758    unsigned int         trdid  = _get_thread_trdid();
2759
2760    if ( (psched->context[ltid].slot[CTX_LOCKS_ID] & LOCKS_MASK_FBF) == 0 )
2761    {
2762        _printf("\n[GIET ERROR] in _sys_fbf_release() : "
2763                "FBF not allocated to thread %x\n", trdid );
2764
2765        return SYSCALL_CHANNEL_NON_ALLOCATED;
2766    }
2767
2768    // decrement FBF allocator
2769    // reset the calling thread context
2770    _atomic_increment( &_fbf_alloc , 0xFFFFFFFF );
2771    _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FBF ); 
2772
2773    return SYSCALL_OK;   
2774}
2775
[440]2776/////////////////////////////////////////////
2777int _sys_fbf_sync_write( unsigned int offset,
2778                         void*        buffer,
2779                         unsigned int length )
2780{
[714]2781    // get calling thread scheduler, ltid and trdid
2782    static_scheduler_t*  psched = _get_sched();
2783    unsigned int         ltid   = _get_thread_ltid();
2784    unsigned int         trdid  = _get_thread_trdid();
2785
2786    if ( (psched->context[ltid].slot[CTX_LOCKS_ID] & LOCKS_MASK_FBF) == 0 )
2787    {
2788        _printf("\n[GIET ERROR] in _sys_fbf_release() : "
2789                "FBF not allocated to thread %x\n", trdid );
2790
2791        return SYSCALL_CHANNEL_NON_ALLOCATED;
2792    }
2793
[440]2794    char* fbf_address = (char *)SEG_FBF_BASE + offset;
2795    memcpy( fbf_address, buffer, length);
2796
[714]2797    return SYSCALL_OK;
[440]2798}
2799
2800/////////////////////////////////////////////
2801int _sys_fbf_sync_read(  unsigned int offset,
2802                         void*        buffer,
2803                         unsigned int length )
2804{
[714]2805    // get calling thread scheduler, ltid and trdid
2806    static_scheduler_t*  psched = _get_sched();
2807    unsigned int         ltid   = _get_thread_ltid();
2808    unsigned int         trdid  = _get_thread_trdid();
2809
2810    if ( (psched->context[ltid].slot[CTX_LOCKS_ID] & LOCKS_MASK_FBF) == 0 )
2811    {
2812        _printf("\n[GIET ERROR] in _sys_fbf_release() : "
2813                "FBF not allocated to thread %x\n", trdid );
2814
2815        return SYSCALL_CHANNEL_NON_ALLOCATED;
2816    }
2817
[440]2818    char* fbf_address = (char *)SEG_FBF_BASE + offset;
2819    memcpy( buffer, fbf_address, length);
2820
[714]2821    return SYSCALL_OK;
[440]2822}
2823
[725]2824////////////////////////////////////////////
2825int _sys_fbf_cma_alloc( unsigned int nbufs )
[440]2826{
[725]2827    // compute trdid and vsid for the calling thread
2828    unsigned int vsid  = _get_context_slot( CTX_VSID_ID );
[709]2829    unsigned int trdid = _get_thread_trdid();
2830
[699]2831    if ( _get_context_slot( CTX_CMA_FB_ID ) < NB_CMA_CHANNELS )
2832    {
[709]2833        _printf("\n[GIET ERROR] in _sys_fbf_cma_alloc() : "
2834                "CMA channel already allocated for thread %x\n", trdid );
[714]2835        return SYSCALL_CHANNEL_ALREADY_ALLOCATED;
[699]2836    }
[440]2837
[725]2838    // compute number of threads in vspace from mapping
2839    mapping_header_t  *header   = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
2840    mapping_vspace_t  *vspace   = _get_vspace_base(header);
2841    mapping_thread_t  *thread   = _get_thread_base(header);
2842    unsigned int      first     = vspace[vsid].thread_offset;
2843    unsigned int      threads   = vspace[vsid].threads;
2844
[709]2845    // get a CMA channel
[699]2846    unsigned int channel;
2847    for ( channel = 0 ; channel < NB_CMA_CHANNELS ; channel++ )
2848    {
[709]2849        unsigned int*  palloc = &_cma_channel_alloc[channel];
[725]2850        if ( _atomic_test_and_set( palloc , threads ) == 0 ) break;
[699]2851    }
[725]2852
[440]2853    if ( channel >= NB_CMA_CHANNELS )
2854    {
[699]2855        _printf("\n[GIET ERROR] in _sys_fbf_cma_alloc() : no CMA channel available\n");
[714]2856        return SYSCALL_NO_CHANNEL_AVAILABLE;
[440]2857    }
[725]2858
2859    // check nbufs argument
2860    if ( nbufs > 256 )
[440]2861    {
[725]2862        _printf("\n[GIET ERROR] in _sys_fbf_cma_alloc() : nbufs larger than 256\n");
2863        return SYSCALL_ILLEGAL_ARGUMENT;
2864    }
[714]2865
[725]2866    // loop on all threads to register channel in thread contexts
2867    unsigned int      tid;
2868    for ( tid = first ; tid < (first + threads) ; tid++ )
2869    {
2870        unsigned int         y_size = header->y_size;
2871        unsigned int         cid    = thread[tid].clusterid;
2872        unsigned int         x      = cid / y_size;
2873        unsigned int         y      = cid % y_size;
2874        unsigned int         p      = thread[tid].proclocid;
2875        unsigned int         ltid   = thread[tid].ltid;
2876        static_scheduler_t* psched  = (static_scheduler_t*)_schedulers[x][y][p];
2877        psched->context[ltid].slot[CTX_CMA_FB_ID] = channel; 
[440]2878    }
[725]2879
2880    unsigned int vaddr;
2881    unsigned int flags;
2882
2883    // compute frame buffer physical addresses
2884    vaddr = (unsigned int)SEG_FBF_BASE;
2885    unsigned long long fbf_buf_paddr = _v2p_translate( vaddr , &flags );
2886
2887    // initialize the FBF chbuf
2888    // we don't register a status address in the fbf_desc, because
2889    // the CMA does not test the status for the frame buffer (no synchro)
2890    _fbf_ker_chbuf.nbufs    = nbufs;
2891    _fbf_ker_chbuf.fbf_desc = (((fbf_buf_paddr & 0xFFFFFFFFFFFULL) >> 6 ) << 26);
2892
2893    // register FBF chbuf physical address
2894    vaddr = (unsigned int)(&_fbf_ker_chbuf);
2895    _fbf_chbuf_paddr = _v2p_translate( vaddr , &flags );
2896
2897#if GIET_DEBUG_FBF_CMA
2898_printf("\n[FBF_CMA DEBUG] _sys_fbf_cma_alloc()\n"
2899        " - channel               = %d\n"
2900        " - vaddr(_ker_fbf_chbuf) = %x\n"
2901        " - paddr(_ker_fbf_chbuf) = %l\n"
2902        " - nbufs                 = %d\n" 
2903        " - fbf_desc              = %l\n",
2904        channel , vaddr , _fbf_chbuf_paddr , nbufs , _fbf_ker_chbuf.fbf_desc );
2905#endif
2906
2907    return SYSCALL_OK;
[440]2908} // end sys_fbf_cma_alloc()
2909
[709]2910//////////////////////////
[725]2911int _sys_fbf_cma_release()  // Not a syscall : used by _ctx_kill_thread()
[700]2912{
2913    unsigned int channel = _get_context_slot( CTX_CMA_FB_ID );
[709]2914    unsigned int trdid   = _get_thread_trdid();
[614]2915
[700]2916    if ( channel >= NB_CMA_CHANNELS )
2917    {
[709]2918        _printf("\n[GIET_ERROR] in _sys_fbf_cma_release() : "
[714]2919                "CMA_FB channel already released for thread %x\n", trdid );
2920
2921        return SYSCALL_CHANNEL_NON_ALLOCATED;
[700]2922    }
2923
[725]2924    if ( _cma_channel_alloc[channel] == 1 )  // the calling thread is the last user
2925    {
2926        // stop the CMA transfer
2927        _sys_fbf_cma_stop();
[700]2928
[725]2929        // reset the CMA channel allocator
2930        _cma_channel_alloc[channel] = 0;
2931    }
2932    else                                     // not the last user
2933    {
2934        // atomically decrement the CMA channel allocator
2935        _atomic_increment( &_cma_channel_alloc[channel] , -1 );
2936    }
2937
2938    // reset CTX_CMA_FB_ID slot in calling thread context
[709]2939    _set_context_slot( CTX_CMA_FB_ID, 0xFFFFFFFF );
[700]2940
[714]2941    return SYSCALL_OK;
[725]2942} // end _sys_fbf_cma_release()
[700]2943
[648]2944///////////////////////////////////////////////////
[725]2945int _sys_fbf_cma_init_buf( unsigned int index,
2946                           void*        buf_vaddr, 
2947                           void*        sts_vaddr )
[440]2948{
2949    unsigned int       vaddr;           // virtual address
[528]2950    unsigned int       flags;           // for _v2p_translate()
[725]2951    unsigned long long buf_paddr;       // user buffer physical address
2952    unsigned long long sts_paddr;       // user status physical address
[440]2953
[714]2954    // get calling thread scheduler, ltid and trdid
2955    static_scheduler_t*  psched = _get_sched();
2956    unsigned int         ltid   = _get_thread_ltid();
2957    unsigned int         trdid  = _get_thread_trdid();
2958
2959    // check FBF allocated
2960    if ( (psched->context[ltid].slot[CTX_LOCKS_ID] & LOCKS_MASK_FBF) == 0 )
2961    {
2962        _printf("\n[GIET ERROR] in _sys_fbf_cma_init_buf() : "
2963                "FBF not allocated to thread %x\n", trdid );
2964
2965        return SYSCALL_CHANNEL_NON_ALLOCATED;
2966    }
2967
[440]2968    // get channel index
[449]2969    unsigned int channel = _get_context_slot( CTX_CMA_FB_ID );
[440]2970
2971    if ( channel >= NB_CMA_CHANNELS )
2972    {
[714]2973        _printf("\n[GIET ERROR] in _sys_fbf_cma_init_buf() : "
2974                "CMA channel non allocated to thread %x\n", trdid );
2975
2976        return SYSCALL_CHANNEL_NON_ALLOCATED;
[440]2977    }
2978
2979#if GIET_DEBUG_FBF_CMA
[714]2980_printf("\n[FBF_CMA DEBUG] _sys_fbf_cma_init_buf()\n"
[725]2981        " - channel     = %d / index = %d\n"
2982        " - buf vaddr   = %x\n"
2983        " - sts vaddr   = %x\n",
2984        channel, index,
2985        (unsigned int)buf_vaddr,
2986        (unsigned int)sts_vaddr );
[440]2987#endif
2988
[725]2989    // checking index argument
2990    if ( index >= _fbf_ker_chbuf.nbufs )
[440]2991    {
[714]2992        _printf("\n[GIET ERROR] in _sys_fbf_cma_init_buf() : "
[725]2993                "user buffer index too large %x\n", trdid );
[714]2994
[725]2995        return SYSCALL_CHANNEL_NON_ALLOCATED;
[440]2996    }
2997
[725]2998    // checking user buffer and status addresses alignment
2999    if ( ((unsigned int)buf_vaddr & 0x3F) || ((unsigned int)sts_vaddr & 0x3F) )
[614]3000    {
[714]3001        _printf("\n[GIET ERROR] in _sys_fbf_cma_init_buf() : "
[725]3002                "user buffer or status not aligned for thread %x\n", trdid );
[714]3003
3004        return SYSCALL_ADDRESS_NON_ALIGNED;
[614]3005    }
3006
[725]3007    // Compute user buffer and status physical addresses
3008    vaddr = (unsigned int)buf_vaddr;
3009    buf_paddr = _v2p_translate( vaddr , &flags );
[440]3010    if ((flags & PTE_U) == 0) 
3011    {
[714]3012        _printf("\n[GIET ERROR] in _sys_fbf_cma_init_buf() : "
[725]3013                "buffer not in user space for thread %x\n", trdid );
[714]3014
3015        return SYSCALL_ADDRESS_NON_USER_ACCESSIBLE;
[440]3016    }
3017
[725]3018    vaddr = (unsigned int)sts_vaddr;
3019    sts_paddr = _v2p_translate( vaddr , &flags );
[614]3020    if ((flags & PTE_U) == 0) 
3021    {
[714]3022        _printf("\n[GIET ERROR] in _sys_fbf_cma_init_buf() : "
[725]3023                "status not in user space for thread %x\n", trdid);
[714]3024
3025        return SYSCALL_ADDRESS_NON_USER_ACCESSIBLE;
[614]3026    }
3027
[725]3028    // check user buffer and user status in same cluster
3029    if ( (buf_paddr & 0xFF00000000ULL) != (sts_paddr & 0xFF00000000ULL) ) 
[440]3030    {
[714]3031        _printf("\n[GIET ERROR] in _sys_fbf_cma_init_buf() : "
[725]3032                "user status and buffer not in same cluster for thread %x\n", trdid);
[714]3033
3034        return SYSCALL_ADDRESS_NON_USER_ACCESSIBLE;
[440]3035    }
3036
[725]3037    // initialize _fbf_ker_chbuf.usr_desc[index]
3038    _fbf_ker_chbuf.usr_desc[index] = ((sts_paddr & 0xFFFFFFFFULL) >> 6) +
3039                                     (((buf_paddr & 0xFFFFFFFFFFULL) >> 6 ) << 26);
[714]3040
[614]3041#if GIET_DEBUG_FBF_CMA
[725]3042_printf(" - buf paddr   = %l\n"
3043        " - sts paddr   = %l\n"
3044        " - usr_desc[%d] = %l\n",
3045        buf_paddr,
3046        sts_paddr,
3047        index , _fbf_ker_chbuf.usr_desc[index] );
[614]3048#endif
3049
[714]3050    return SYSCALL_OK;
[614]3051
3052} // end sys_fbf_cma_init_buf()
3053
[725]3054////////////////////////
3055int _sys_fbf_cma_start() 
[614]3056{
[714]3057    // get calling thread scheduler, ltid and trdid
3058    static_scheduler_t*  psched = _get_sched();
3059    unsigned int         ltid   = _get_thread_ltid();
3060    unsigned int         trdid  = _get_thread_trdid();
[614]3061
[714]3062    // check FBF allocated
3063    if ( (psched->context[ltid].slot[CTX_LOCKS_ID] & LOCKS_MASK_FBF) == 0 )
3064    {
3065        _printf("\n[GIET ERROR] in _sys_fbf_release() : "
3066                "FBF not allocated to thread %x\n", trdid );
3067
3068        return SYSCALL_CHANNEL_NON_ALLOCATED;
3069    }
3070
[725]3071    // get CMA channel index
[614]3072    unsigned int channel = _get_context_slot( CTX_CMA_FB_ID );
3073
3074    if ( channel >= NB_CMA_CHANNELS )
3075    {
[714]3076        _printf("\n[GIET ERROR] in _fbf_cma_start() : "
3077                "CMA channel non allocated\n");
3078
3079        return SYSCALL_CHANNEL_NON_ALLOCATED;
[614]3080    }
3081
3082    // check buffers initialization
[725]3083    if ( _fbf_ker_chbuf.nbufs == 0 )
[614]3084    {
[725]3085        _printf("\n[GIET ERROR] in _sys_fbf_cma_start(): "
3086                "FBF chbuf not initialized for thread %x\n", trdid );
[714]3087
3088        return SYSCALL_MISSING_INITIALISATION;
[614]3089    }
3090
[725]3091    // synchronize FBF chbuf that will be read by CMA peripheral
[440]3092    if ( USE_IOB )
3093    {
[505]3094        // SYNC request for fbf_chbuf descriptor
[725]3095        _mmc_sync( _fbf_chbuf_paddr , sizeof( fbf_chbuf_t ) );
[440]3096    }
3097
[505]3098    // start CMA transfer
[725]3099    unsigned long long paddr = _fbf_chbuf_paddr;
3100    unsigned int dst_chbuf_paddr_lsb = (unsigned int)(paddr & 0xFFFFFFFF);
3101    unsigned int dst_chbuf_paddr_ext = (unsigned int)(paddr >> 32);
3102    unsigned int src_chbuf_paddr_lsb = dst_chbuf_paddr_lsb + 8;
3103    unsigned int src_chbuf_paddr_ext = dst_chbuf_paddr_ext;
[505]3104
[725]3105#if GIET_DEBUG_FBF_CMA
3106_printf("\n[FBF_CMA DEBUG] _sys_fbf_cma_start()\n"
3107        " - src_chbuf_paddr_lsb = %x\n"
3108        " - src_chbuf_paddr_ext = %x\n"
3109        " - src_chbuf_nbufs     = %d\n"
3110        " - dst_chbuf_paddr_lsb = %x\n"
3111        " - dst_chbuf_paddr_ext = %x\n"
3112        " - dst_chbuf_nbufs     = 1 \n"
3113        " - buffer_size         = %d\n",
3114        src_chbuf_paddr_lsb,
3115        src_chbuf_paddr_ext,
3116        _fbf_ker_chbuf.nbufs,
3117        dst_chbuf_paddr_lsb,
3118        dst_chbuf_paddr_ext,
3119        FBUF_X_SIZE * FBUF_Y_SIZE );
3120#endif
3121
[505]3122    _cma_set_register( channel, CHBUF_SRC_DESC , src_chbuf_paddr_lsb );
3123    _cma_set_register( channel, CHBUF_SRC_EXT  , src_chbuf_paddr_ext );
[725]3124    _cma_set_register( channel, CHBUF_SRC_NBUFS, _fbf_ker_chbuf.nbufs );
[505]3125    _cma_set_register( channel, CHBUF_DST_DESC , dst_chbuf_paddr_lsb );
3126    _cma_set_register( channel, CHBUF_DST_EXT  , dst_chbuf_paddr_ext );
3127    _cma_set_register( channel, CHBUF_DST_NBUFS, 1 );
[725]3128    _cma_set_register( channel, CHBUF_BUF_SIZE , FBUF_X_SIZE*FBUF_Y_SIZE );
[733]3129    _cma_set_register( channel, CHBUF_PERIOD   , 1000 );
[725]3130    _cma_set_register( channel, CHBUF_RUN      , MODE_NO_DST_SYNC );
[505]3131
[714]3132    return SYSCALL_OK;
[440]3133
3134} // end _sys_fbf_cma_start()
3135
[725]3136////////////////////////////////////////////
3137int _sys_fbf_cma_check( unsigned int index )
[440]3138{
[714]3139    // get calling thread scheduler, ltid and trdid
3140    static_scheduler_t*  psched = _get_sched();
3141    unsigned int         ltid   = _get_thread_ltid();
3142    unsigned int         trdid  = _get_thread_trdid();
3143
3144    // check FBF allocated
3145    if ( (psched->context[ltid].slot[CTX_LOCKS_ID] & LOCKS_MASK_FBF) == 0 )
3146    {
[725]3147        _printf("\n[GIET ERROR] in _sys_fbf_cma_check() : "
[714]3148                "FBF not allocated to thread %x\n", trdid );
3149
3150        return SYSCALL_CHANNEL_NON_ALLOCATED;
3151    }
3152
[440]3153    // get channel index
[449]3154    unsigned int channel = _get_context_slot( CTX_CMA_FB_ID );
[440]3155
3156    if ( channel >= NB_CMA_CHANNELS )
3157    {
[725]3158        _printf("\n[GIET ERROR] in _sys_fbf_cma_check() : "
3159                "CMA channel non allocated to thread %x\n", trdid );
[714]3160
3161        return SYSCALL_CHANNEL_NON_ALLOCATED;
[440]3162    }
3163
[725]3164    // check buffer index
3165    if ( index >= _fbf_ker_chbuf.nbufs )
3166    {
3167        _printf("\n[GIET ERROR] in _sys_fbf_cma_check() : "
3168                "buffer index too large for thread %x\n", trdid );
[505]3169
[725]3170        return SYSCALL_CHANNEL_NON_ALLOCATED;
3171    }
3172
3173    // compute user buffer status physical addresses
3174    unsigned long long usr_sts_paddr;
3175    fbf_chbuf_t* pdesc = &_fbf_ker_chbuf;     
3176    usr_sts_paddr = ((pdesc->usr_desc[index] & 0xFFF0000000000000ULL) >> 20) + 
3177                    ((pdesc->usr_desc[index] & 0x3FFFFFFULL) << 6);         
3178
[440]3179#if GIET_DEBUG_FBF_CMA
[725]3180_printf("\n[FBF_CMA DEBUG] enters _sys_fbf_cma_check()\n"
[614]3181        " - cma channel      = %d\n"
3182        " - buffer index     = %d\n"
[725]3183        " - usr_desc value   = %l\n"
3184        " - fbf_desc value   = %l\n"
3185        " - usr status paddr = %l\n",
3186        channel,
3187        index,
3188        _fbf_ker_chbuf.usr_desc[index],
3189        _fbf_ker_chbuf.fbf_desc,
3190        usr_sts_paddr );
[440]3191#endif
3192
[725]3193    // waiting user buffer released by the CMA component)
3194    unsigned int full;
3195    do
3196    { 
3197        // INVAL L2 cache copy of user buffer status     
3198        // because it is modified in RAM by the CMA component
3199        _mmc_inval( usr_sts_paddr , 4 );       
[614]3200
[725]3201        full = _physical_read( usr_sts_paddr );
3202    }
3203    while ( full );
3204
3205    return SYSCALL_OK;
3206
3207}  // end _sys_fbf_cma_check()
3208
3209//////////////////////////////////////////////
3210int _sys_fbf_cma_display( unsigned int index )
3211{
3212    // get calling thread scheduler, ltid and trdid
3213    static_scheduler_t*  psched = _get_sched();
3214    unsigned int         ltid   = _get_thread_ltid();
3215    unsigned int         trdid  = _get_thread_trdid();
3216
3217    // check FBF allocated
3218    if ( (psched->context[ltid].slot[CTX_LOCKS_ID] & LOCKS_MASK_FBF) == 0 )
[478]3219    {
[725]3220        _printf("\n[GIET ERROR] in _sys_fbf_cma_display() : "
3221                "FBF not allocated to thread %x\n", trdid );
[505]3222
[725]3223        return SYSCALL_CHANNEL_NON_ALLOCATED;
[440]3224    }
[725]3225
3226    // get channel index
3227    unsigned int channel = _get_context_slot( CTX_CMA_FB_ID );
3228
3229    if ( channel >= NB_CMA_CHANNELS )
[478]3230    {
[725]3231        _printf("\n[GIET ERROR] in _sys_fbf_cma_display() : "
3232                "CMA channel non allocated to thread %x\n", trdid );
[505]3233
[725]3234        return SYSCALL_CHANNEL_NON_ALLOCATED;
[614]3235    }
[478]3236
[725]3237    // check buffer index
3238    if ( index >= _fbf_ker_chbuf.nbufs )
3239    {
3240        _printf("\n[GIET ERROR] in _sys_fbf_cma_display() : "
3241                "buffer index too large for thread %x\n", trdid );
[440]3242
[725]3243        return SYSCALL_CHANNEL_NON_ALLOCATED;
3244    }
3245
3246    // compute user buffer and status physical addresses
3247    unsigned long long usr_sts_paddr;
3248    unsigned long long usr_buf_paddr;
3249
3250    fbf_chbuf_t* pdesc = &_fbf_ker_chbuf;     
3251
3252    usr_sts_paddr = ((pdesc->usr_desc[index] & 0xFFF0000000000000ULL) >> 20) + 
3253                    ((pdesc->usr_desc[index] & 0x3FFFFFFULL) << 6);         
3254
3255    usr_buf_paddr = ((pdesc->usr_desc[index] & 0xFFFFFFFFFC000000ULL) >> 20); 
3256
[614]3257#if GIET_DEBUG_FBF_CMA
[725]3258_printf("\n[FBF_CMA DEBUG] enters _sys_fbf_cma_display()\n"
3259        " - cma channel      = %d\n"
3260        " - buffer index     = %d\n"
3261        " - usr buffer paddr = %l\n"
3262        " - usr status paddr = %l\n",
3263        channel,
3264        index,
3265        usr_buf_paddr, 
3266        usr_sts_paddr ); 
[614]3267#endif
3268       
[725]3269    // SYNC request, because this buffer will be read from XRAM by the CMA component
3270    _mmc_sync( usr_buf_paddr , FBUF_X_SIZE * FBUF_Y_SIZE );
[440]3271
[614]3272    // set user buffer status
[725]3273    _physical_write( usr_sts_paddr, 0x1 );
[614]3274
[725]3275    // SYNC request, because this status will be read from XRAM by the CMA component
3276    _mmc_sync( usr_sts_paddr, 4 );
[614]3277
[714]3278    return SYSCALL_OK;
[440]3279
3280} // end _sys_fbf_cma_display()
3281
3282///////////////////////
3283int _sys_fbf_cma_stop()
3284{
3285    // get channel index
[449]3286    unsigned int channel = _get_context_slot( CTX_CMA_FB_ID );
[440]3287
3288    if ( channel >= NB_CMA_CHANNELS )
3289    {
[714]3290        _printf("\n[GIET ERROR] in _sys_fbf_cma_stop() : CMA channel non allocated\n");
3291
3292        return SYSCALL_CHANNEL_NON_ALLOCATED;
[440]3293    }
3294
3295    // Desactivate CMA channel
[725]3296    _cma_set_register( channel, CHBUF_RUN, MODE_IDLE );
[440]3297
[714]3298    return SYSCALL_OK;
[440]3299
3300} // end _sys_fbf_cma_stop()
3301
3302
3303//////////////////////////////////////////////////////////////////////////////
3304//           Miscelaneous syscall handlers
3305//////////////////////////////////////////////////////////////////////////////
3306
3307///////////////
3308int _sys_ukn() 
3309{
3310    _printf("\n[GIET ERROR] Undefined System Call / EPC = %x\n", _get_epc() );
[714]3311
3312    return SYSCALL_UNDEFINED_SYSTEM_CALL;
[440]3313}
3314
3315////////////////////////////////////
3316int _sys_proc_xyp( unsigned int* x,
3317                   unsigned int* y,
3318                   unsigned int* p )
3319{
[428]3320    unsigned int gpid = _get_procid();  // global processor index from CPO register
3321
3322    *x = (gpid >> (Y_WIDTH + P_WIDTH)) & ((1<<X_WIDTH)-1);
3323    *y = (gpid >> P_WIDTH) & ((1<<Y_WIDTH)-1);
3324    *p = gpid & ((1<<P_WIDTH)-1);
[440]3325
[714]3326    return SYSCALL_OK;
[428]3327}
[440]3328
[494]3329////////////////////////////////////////////
3330int _sys_procs_number( unsigned int* x_size,
3331                       unsigned int* y_size,
3332                       unsigned int* nprocs )
[258]3333{
[494]3334    mapping_header_t * header   = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
[440]3335    mapping_cluster_t * cluster = _get_cluster_base(header);
3336
[494]3337    unsigned int x;
3338    unsigned int y;
3339    unsigned int okmin = 1;
3340    unsigned int okmax = 1;
3341
3342    // compute max values
3343    unsigned int xmax  = header->x_size;
3344    unsigned int ymax  = header->y_size;
3345    unsigned int procs = cluster[0].procs;
3346
3347    // check the (ymax-1) lower rows
3348    for ( y = 0 ; y < ymax-1 ; y++ )
[440]3349    {
[494]3350        for ( x = 0 ; x < xmax ; x++ )
3351        {
3352            if (cluster[x*ymax+y].procs != procs ) okmin = 0;
3353        }
[440]3354    }
[494]3355
3356    // check the upper row
3357    for ( x = 0 ; x < xmax ; x++ )
[440]3358    {
[494]3359        if (cluster[x*ymax+ymax-1].procs != procs ) okmax = 0;
[440]3360    }
[494]3361
3362    // return values
3363    if ( okmin && okmax )
3364    {
3365        *x_size = xmax;
3366        *y_size = ymax;
3367        *nprocs = procs;
3368    }
3369    else if ( okmin )
3370    {
3371        *x_size = xmax;
3372        *y_size = ymax-1;
3373        *nprocs = procs;
3374    }
3375    else
3376    {
3377        *x_size = 0;
3378        *y_size = 0;
3379        *nprocs = 0;
3380    }
[714]3381    return SYSCALL_OK;
[440]3382}
3383
3384///////////////////////////////////////////////////////
[516]3385int _sys_vseg_get_vbase( char*             vspace_name, 
3386                         char*             vseg_name, 
[440]3387                         unsigned int*     vbase ) 
3388{
[322]3389    mapping_header_t * header = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
[258]3390    mapping_vspace_t * vspace = _get_vspace_base(header);
[516]3391    mapping_vseg_t * vseg     = _get_vseg_base(header);
[258]3392
3393    unsigned int vspace_id;
[516]3394    unsigned int vseg_id;
[258]3395
3396    // scan vspaces
3397    for (vspace_id = 0; vspace_id < header->vspaces; vspace_id++) 
3398    {
3399        if (_strncmp( vspace[vspace_id].name, vspace_name, 31) == 0) 
3400        {
[516]3401            // scan vsegs
3402            for (vseg_id = vspace[vspace_id].vseg_offset; 
3403                 vseg_id < (vspace[vspace_id].vseg_offset + vspace[vspace_id].vsegs); 
3404                 vseg_id++) 
[258]3405            {
[516]3406                if (_strncmp(vseg[vseg_id].name, vseg_name, 31) == 0) 
[258]3407                {
[516]3408                    *vbase = vseg[vseg_id].vbase;
[714]3409                    return SYSCALL_OK;
[258]3410                }
3411            } 
3412        }
3413    } 
[714]3414    return SYSCALL_VSEG_NOT_FOUND;
[258]3415}
3416
[440]3417/////////////////////////////////////////////////////////
[516]3418int _sys_vseg_get_length( char*         vspace_name, 
3419                          char*         vseg_name,
[440]3420                          unsigned int* length ) 
[258]3421{
[440]3422    mapping_header_t * header = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
3423    mapping_vspace_t * vspace = _get_vspace_base(header);
[516]3424    mapping_vseg_t * vseg     = _get_vseg_base(header);
[258]3425
[440]3426    unsigned int vspace_id;
[516]3427    unsigned int vseg_id;
[440]3428
3429    // scan vspaces
3430    for (vspace_id = 0; vspace_id < header->vspaces; vspace_id++) 
[258]3431    {
[440]3432        if (_strncmp( vspace[vspace_id].name, vspace_name, 31) == 0) 
3433        {
[516]3434            // scan vsegs
3435            for (vseg_id = vspace[vspace_id].vseg_offset; 
3436                 vseg_id < (vspace[vspace_id].vseg_offset + vspace[vspace_id].vsegs); 
3437                 vseg_id++) 
[440]3438            {
[516]3439                if (_strncmp(vseg[vseg_id].name, vseg_name, 31) == 0) 
[440]3440                {
[516]3441                    *length = vseg[vseg_id].length;
[714]3442                    return SYSCALL_OK;
[440]3443                }
3444            } 
3445        }
3446    } 
[714]3447    return SYSCALL_VSEG_NOT_FOUND;
[258]3448}
3449
[440]3450////////////////////////////////////////
3451int _sys_xy_from_ptr( void*         ptr,
3452                      unsigned int* x,
3453                      unsigned int* y )
[396]3454{
3455    unsigned int flags;
[528]3456    unsigned long long paddr = _v2p_translate( (unsigned int)ptr , &flags );
[396]3457   
[528]3458    *x = (paddr>>36) & 0xF;
3459    *y = (paddr>>32) & 0xF;
[396]3460
[714]3461    return SYSCALL_OK;
[396]3462}
3463
[440]3464/////////////////////////////////////////
3465int _sys_heap_info( unsigned int* vaddr, 
3466                    unsigned int* length,
3467                    unsigned int  x,
3468                    unsigned int  y ) 
[258]3469{
[709]3470    // checking parameters
3471    if ( (x >= X_SIZE) || (y >= Y_SIZE) ) 
3472    {
3473        *vaddr  = 0;
3474        *length = 0;
3475        _printf("\n[GIET ERROR] in _sys_heap_info() : "
3476                "illegal (%d,%d) coordinates\n", x , y );
[714]3477        return SYSCALL_ILLEGAL_CLUSTER_COORDINATES;
[709]3478    }
3479
[440]3480    mapping_header_t * header  = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
[709]3481    mapping_thread_t * thread  = _get_thread_base(header);
[516]3482    mapping_vseg_t *   vseg    = _get_vseg_base(header);
3483    mapping_vspace_t * vspace  = _get_vspace_base(header);
[294]3484
[709]3485    unsigned int thread_id;
[440]3486    unsigned int vspace_id;
[516]3487    unsigned int vseg_id = 0xFFFFFFFF;
[258]3488
[709]3489    // get calling thread vspace index
3490    vspace_id = _get_context_slot(CTX_VSID_ID);
3491
3492    // scan all threads in vspace to find one in clyster[x,y]
3493    unsigned int min = vspace[vspace_id].thread_offset ;
3494    unsigned int max = min + vspace[vspace_id].threads ;
3495    for ( thread_id = min ; thread_id < max ; thread_id++ )
[440]3496    {
[709]3497        if ( thread[thread_id].clusterid == (x * Y_SIZE + y) )
[440]3498        {
[709]3499            vseg_id = thread[thread_id].heap_vseg_id;
3500            break;
[440]3501        }
3502    }
3503
[516]3504    // analysing the vseg_id
3505    if ( vseg_id != 0xFFFFFFFF ) 
[440]3506    {
[516]3507        *vaddr  = vseg[vseg_id].vbase;
3508        *length = vseg[vseg_id].length;
[440]3509    }
3510    else 
3511    {
3512        *vaddr  = 0;
3513        *length = 0;
[709]3514        _printf("error in _sys_heap_info() : no heap in cluster (%d,%d)\n", x , y );
[440]3515    }
[714]3516    return SYSCALL_OK;
[440]3517}  // end _sys_heap_info()
3518
3519
[258]3520// Local Variables:
3521// tab-width: 4
3522// c-basic-offset: 4
3523// c-file-offsets:((innamespace . 0)(inline-open . 0))
3524// indent-tabs-mode: nil
3525// End:
3526// vim: filetype=c:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
3527
Note: See TracBrowser for help on using the repository browser.