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

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