Changeset 657 for trunk/kernel/devices


Ignore:
Timestamp:
Mar 18, 2020, 11:16:59 PM (4 years ago)
Author:
alain
Message:

Introduce remote_buf.c/.h & socket.c/.h files.
Update dev_nic.c/.h files.

Location:
trunk/kernel/devices
Files:
11 edited

Legend:

Unmodified
Added
Removed
  • trunk/kernel/devices/dev_dma.c

    r647 r657  
    22 * dev_dma.c - DMA (Interrupt Controler Unit) generic device API implementation.
    33 *
    4  * Authors   Alain Greiner  (2016,2017,2018,2019)
     4 * Authors   Alain Greiner  (2016,2017,2018,2019,2020)
    55 *
    66 * Copyright (c) UPMC Sorbonne Universites
     
    8484
    8585////////////////////////////////////////////////
    86 error_t dev_dma_remote_memcpy( xptr_t    dst_xp,
    87                                xptr_t    src_xp,
    88                                uint32_t  size )
     86error_t dev_dma_async_memcpy( xptr_t    dst_xp,
     87                              xptr_t    src_xp,
     88                              uint32_t  size )
    8989{
    9090    thread_t * this = CURRENT_THREAD;
    9191
    92 #if CONGIG_DEBUG_DEV_DMA
     92#if DEBUG_DEV_DMA
    9393uint32_t cycle = (uint32_t)hal_get_cycles();
    9494if( CONGIG_DEBUG_DEV_DMA < cycle )
     
    107107
    108108    // register command in calling thread descriptor
     109    this->dma_cmd.sync    = false;
    109110    this->dma_cmd.dev_xp  = dev_xp;
    110111    this->dma_cmd.dst_xp  = dst_xp;
     
    112113    this->dma_cmd.size    = size;
    113114
    114     // register client thread in waiting queue, activate server thread
    115     // block client thread on THREAD_BLOCKED_IO and deschedule.
    116     // it is re-activated by the ISR signaling IO operation completion.
     115    // register the client thread in waiting queue, activate the server thread,
     116    // block the client thread on THREAD_BLOCKED_IO, and deschedule.
     117    // it is re-activated by the server thread  when the transfer is completed.
    117118    chdev_register_command( dev_xp );
    118119
    119 #if CONGIG_DEBUG_DEV_DMA
     120#if DEBUG_DEV_DMA
    120121cycle = (uint32_t)hal_get_cycles();
    121122if( CONGIG_DEBUG_DEV_DMA < cycle )
     
    127128    return this->dma_cmd.error; 
    128129
    129 }  // dev_dma_remote_memcpy()
     130}  // dev_dma_async_memcpy()
    130131
     132//////////////////////////////////////////////
     133error_t dev_dma_sync_memcpy( xptr_t    dst_xp,
     134                             xptr_t    src_xp,
     135                             uint32_t  size )
     136{
     137    thread_t * this = CURRENT_THREAD;
     138
     139#if DEBUG_DEV_DMA
     140uint32_t cycle = (uint32_t)hal_get_cycles();
     141if( CONGIG_DEBUG_DEV_DMA < cycle )
     142printk("\n[DBG] %s : thread %x enters / dst %l / src %l / size = %x\n",
     143__FUNCTION__ , this, dst_xp, src_xp, size );
     144#endif
     145
     146    // select DMA channel corresponding to core lid
     147    uint32_t channel = this->core->lid;
     148
     149    // get extended pointer on selected DMA chdev descriptor
     150    xptr_t  dev_xp = chdev_dir.dma[channel];
     151
     152// check DMA chdev definition
     153assert( (dev_xp != XPTR_NULL) , "undefined DMA chdev descriptor" );
     154
     155    // register command in calling thread descriptor
     156    this->dma_cmd.sync    = true;
     157    this->dma_cmd.dev_xp  = dev_xp;
     158    this->dma_cmd.dst_xp  = dst_xp;
     159    this->dma_cmd.src_xp  = src_xp;
     160    this->dma_cmd.size    = size;
     161
     162    // get driver command function
     163    cxy_t       dev_cxy = GET_CXY( dev_xp );
     164    chdev_t   * dev_ptr = GET_PTR( dev_xp );
     165    dev_cmd_t * cmd = (dev_cmd_t *)hal_remote_lpt( XPTR( dev_cxy , &dev_ptr->cmd ) );
     166
     167    // call directly the blocking driver function
     168    cmd( XPTR( local_cxy , this ) );
     169
     170#if DEBUG_DEV_DMA
     171cycle = (uint32_t)hal_get_cycles();
     172if( CONGIG_DEBUG_DEV_DMA < cycle )
     173printk("\n[DBG] %s : thread %x exit / dst %l / src %l / size = %x\n",
     174__FUNCTION__ , this, dst_xp, src_xp, size );
     175#endif
     176
     177    // return I/O operation status from calling thread descriptor
     178    return this->dma_cmd.error; 
     179
     180}  // dev_dma_sync_memcpy()
     181
  • trunk/kernel/devices/dev_dma.h

    r647 r657  
    22 * dev_dma.h - DMA (Direct Memory Access) generic device API definition.
    33 *
    4  * Authors   Alain Greiner  (2016,2017,2018)
     4 * Authors   Alain Greiner  (2016,2017,2018,2019,2020)
    55 *
    66 * Copyright (c) UPMC Sorbonne Universites
     
    3636 * to/from remote clusters. The burst size is defined by the cache line size.
    3737 * Each DMA channel is described by a specific chdev descriptor, handling its private
    38  * waiting threads queue. It implement one single command : move data from a (remote)
    39  * source buffer to a (remote) destination buffer.
     38 * waiting threads queue. It implements two blocking commands :
     39 * - move synchronously data from a remote source buffer to a remote destination buffer,
     40 *   using a polling policy to wait completion (No DMA_IRQ use).
     41 * - move synchronously data from a remote source buffer to a remote destination buffer,
     42 *   using a descheduling policy to wait completion (reactivated bythe IDMA_IRQ).
    4043 ****************************************************************************************/
    4144 
     
    5053typedef struct dma_command_s
    5154{
    52     xptr_t      dev_xp;    /*! extended pointer on the DMA chdev descriptor             */
     55    bool_t      sync;      /*! polling policy if true / descheduling policy if false     */
     56    xptr_t      dev_xp;    /*! extended pointer on the DMA chdev descriptor              */
    5357    xptr_t      src_xp;    /*! extended pointer on source buffer.                        */
    5458    xptr_t      dst_xp;    /*! extended pointer on destination buffer.                   */
     
    8387/*****************************************************************************************
    8488 * This blocking function register a DMA request in the device queue.
    85  * It uses a descheduling policy to wait completion, and return an error status
    86  * when the transfer is completed.
     89 * It uses a descheduling policy to wait completion,
     90 * It return an error status when the transfer is completed.
    8791 *****************************************************************************************
    88  * @ dst        : extended pointer on destination buffer.
    89  * @ src        : extended pointer on Rsource buffer.
     92 * @ dst_xp     : extended pointer on destination buffer.
     93 * @ src_xp     : extended pointer on source buffer.
    9094 * @ size       : number of bytes to move.
    9195 ****************************************************************************************/
    92 error_t dev_dma_remote_memcpy( xptr_t     dst_xp,
    93                                xptr_t     src_xp,
    94                                uint32_t   size );   
     96error_t dev_dma_async_memcpy( xptr_t     dst_xp,
     97                              xptr_t     src_xp,
     98                              uint32_t   size );   
     99
     100/*****************************************************************************************
     101 * This blocking function register a DMA request in the device queue.
     102 * It uses a polling policy to wait completion.
     103 * It return an error status when the transfer is completed.
     104 *****************************************************************************************
     105 * @ dst_xp     : extended pointer on destination buffer.
     106 * @ src_xp     : extended pointer on source buffer.
     107 * @ size       : number of bytes to move.
     108 ****************************************************************************************/
     109error_t dev_dma_sync_memcpy( xptr_t     dst_xp,
     110                             xptr_t     src_xp,
     111                             uint32_t   size );   
    95112
    96113
  • trunk/kernel/devices/dev_fbf.c

    r647 r657  
    22 * dev_fbf.c - FBF (Frame Buffer) generic device API implementation.
    33 *
    4  * Author  Alain Greiner    (2016,2017,2018,2019)
     4 * Author  Alain Greiner    (2016,2017,2018,2019,2020)
    55 *
    66 * Copyright (c) UPMC Sorbonne Universites
     
    2626#include <hal_gpt.h>
    2727#include <hal_drivers.h>
     28#include <hal_irqmask.h>
     29#include <hal_macros.h>
     30#include <hal_uspace.h>
     31#include <hal_vmm.h>
    2832#include <thread.h>
    2933#include <printk.h>
    3034#include <string.h>
     35#include <memcpy.h>
    3136#include <chdev.h>
    3237#include <dev_fbf.h>
     
    4146char * dev_fbf_cmd_str( uint32_t cmd_type )
    4247{
    43     if     ( cmd_type == FBF_READ       )  return "READ";
    44     else if( cmd_type == FBF_WRITE      )  return "WRITE";
    45     else if( cmd_type == FBF_GET_CONFIG )  return "GET_CONFIG";
    46     else                                   return "undefined";
     48    if     ( cmd_type == FBF_GET_CONFIG     )  return "GET_CONFIG";
     49    else if( cmd_type == FBF_CREATE_WINDOW  )  return "CREATE_WINDOW";
     50    else if( cmd_type == FBF_DELETE_WINDOW  )  return "DELETE_WINDOW";
     51    else if( cmd_type == FBF_MOVE_WINDOW    )  return "MOVE_WINDOW";
     52    else if( cmd_type == FBF_REFRESH_WINDOW )  return "REFRESH_WINDOW";
     53    else if( cmd_type == FBF_DIRECT_WRITE   )  return "DIRECT_WRITE";
     54    else if( cmd_type == FBF_DIRECT_READ    )  return "DIRECT_READ";
     55    else                                       return "undefined";
    4756}
    4857
     
    5059void dev_fbf_init( chdev_t  * fbf )
    5160{
     61    uint32_t wid;
     62
    5263    // set chdev name
    5364    strcpy( fbf->name, "fbf" );
    5465
    55     // call driver init function
     66    // initialize lock protecting the windows
     67    remote_rwlock_init( XPTR( local_cxy , &fbf->ext.fbf.windows_lock ),
     68                        LOCK_FBF_WINDOWS );
     69
     70    // initialize root of windows xlist
     71    xlist_root_init( XPTR( local_cxy , &fbf->ext.fbf.windows_root ) );
     72
     73    // initialize windows_tbl[] array
     74    for( wid = 0 ; wid < CONFIG_FBF_WINDOWS_MAX_NR ; wid++ )
     75    {
     76        fbf->ext.fbf.windows_tbl[wid] = XPTR_NULL;
     77    }
     78
     79    // initialize wid allocator bitmap
     80    bitmap_init( fbf->ext.fbf.windows_bitmap , CONFIG_FBF_WINDOWS_MAX_NR );
     81
     82    // call driver init function to initialize the harware FBF
     83    // and initialize the width, height, and subsampling FBF chdev fields
    5684    hal_drivers_fbf_init( fbf );
    5785
     
    6694    xptr_t  dev_xp = chdev_dir.fbf[0];
    6795
    68     assert( (dev_xp != XPTR_NULL) , "undefined FBF chdev descriptor" );
     96assert( (dev_xp != XPTR_NULL) , "undefined FBF chdev descriptor" );
    6997
    7098    // get FBF chdev cluster and local pointer
     
    79107}  // end dev_fbf_get_config()
    80108
    81 /////////////////////////////////////////////////////
    82 error_t dev_fbf_move_data( uint32_t   cmd_type,
    83                            void     * user_buffer,
    84                            uint32_t   length,
    85                            uint32_t   offset )
    86 {
    87     // get pointer on calling thread
    88     thread_t * this = CURRENT_THREAD;
     109///////////////////////////////////////////////
     110uint32_t dev_fbf_create_window( uint32_t   nlines,
     111                                uint32_t   npixels,
     112                                uint32_t   l_min,
     113                                uint32_t   p_min,
     114                                intptr_t * user_buffer )
     115{
     116    kmem_req_t     req;
     117    fbf_window_t * window;      // window descriptor (created in local cluster)
     118    vseg_t       * vseg;        // vseg descriptor (created in reference cluster)
     119    intptr_t       vseg_base;   // vseg base address in user space 
     120
     121    // get local pointers on calling thread and process
     122    thread_t  * this    = CURRENT_THREAD;
     123    process_t * process = this->process;
    89124
    90125#if DEBUG_DEV_FBF
    91126uint32_t   cycle = (uint32_t)hal_get_cycles();
    92127if( DEBUG_DEV_FBF < cycle )
    93 printk("\n[%s] thread[%x,%x] : %s / buffer %x / length %d / offset %x / cycle %d\n",
    94 __FUNCTION__ , this->process->pid, this->trdid, 
    95 dev_fbf_cmd_str(cmd_type), user_buffer, length, offset, cycle );
     128printk("\n[%s] thread[%x,%x] enter : nlines %d / npixels %d / l_min %d / p_min %d / cycle %d\n",
     129__FUNCTION__ , process->pid, this->trdid, nlines, npixels, l_min, p_min, cycle );
     130#endif
     131
     132    // get cluster and pointers on FBF chdev
     133    xptr_t      fbf_xp  = chdev_dir.fbf[0];
     134    cxy_t       fbf_cxy = GET_CXY( fbf_xp );
     135    chdev_t   * fbf_ptr = GET_PTR( fbf_xp );
     136
     137// check fbf_xp definition
     138assert( (fbf_xp != XPTR_NULL) , "undefined FBF chdev descriptor" );
     139
     140    // get FBF width and height
     141    uint32_t fbf_width  = hal_remote_l32( XPTR( fbf_cxy , &fbf_ptr->ext.fbf.width ) );
     142    uint32_t fbf_height = hal_remote_l32( XPTR( fbf_cxy , &fbf_ptr->ext.fbf.height ) );
     143
     144    // check new window size and coordinates
     145    if( (((l_min + nlines) > fbf_height) || ((p_min + npixels) > fbf_width)) )
     146    {
     147        printk("\n[ERROR] in %s / thread[%x,%x]"
     148        "illegal new coordinates (%d,%d) for window (%d,%d) in fbf (%d,%d)\n",
     149        process->pid, this->trdid, p_min, l_min, npixels, nlines, fbf_width, fbf_height );
     150        return -1;
     151    }
     152
     153    // build extended pointers on windows lock, root, and wid allocator
     154    xptr_t windows_lock_xp   = XPTR( fbf_cxy , &fbf_ptr->ext.fbf.windows_lock );
     155    xptr_t windows_root_xp   = XPTR( fbf_cxy , &fbf_ptr->ext.fbf.windows_root );
     156    xptr_t windows_bitmap_xp = XPTR( fbf_cxy ,  fbf_ptr->ext.fbf.windows_bitmap );
     157 
     158    // allocate memory for the window descriptor in local cluster
     159    req.type   = KMEM_KCM;
     160    req.order  = bits_log2( sizeof(fbf_window_t) );
     161    req.flags  = AF_ZERO | AF_KERNEL;
     162    window     = kmem_alloc( &req );
     163
     164    if( window == NULL )
     165    {
     166        printk("\n[ERROR] in %s / thread[%x,%x] cannot allocate window descriptor\n",
     167        __FUNCTION__, process->pid, this->trdid );
     168        return -1;
     169    }
     170
     171#if (DEBUG_DEV_FBF & 1)
     172cycle = (uint32_t)hal_get_cycles();
     173if( DEBUG_DEV_FBF < cycle )
     174printk("\n[%s] thread[%x,%x] created window descriptor %x / cycle %d\n",
     175__FUNCTION__ , process->pid, this->trdid, window, cycle );
     176#endif
     177
     178    // getpointers on reference process
     179    xptr_t      ref_xp  = process->ref_xp;
     180    process_t * ref_ptr = GET_PTR( ref_xp );
     181    cxy_t       ref_cxy = GET_CXY( ref_xp );
     182
     183    // allocate a new vseg, and introduce it in the reference process VSL
     184    if( ref_cxy == local_cxy )
     185    {
     186        vseg = vmm_create_vseg( process,            // owner process
     187                                VSEG_TYPE_ANON,     // localised, public
     188                                0,                  // base, unused for ANON
     189                                nlines * npixels,   // size
     190                                0,                  // file_offset, unused for ANON
     191                                0,                  // file_size, unused for ANON
     192                                XPTR_NULL,          // mapper_xp, unused for ANON
     193                                local_cxy );        // mapping cluster
     194    }
     195    else
     196    {
     197        rpc_vmm_create_vseg_client( ref_cxy,
     198                                    ref_ptr,
     199                                    VSEG_TYPE_ANON,
     200                                    0,                 // base, unused for ANON
     201                                    nlines * npixels,  // size
     202                                    0,                 // file_offset, unused for ANON
     203                                    0,                 // file size, unused for ANON
     204                                    XPTR_NULL,         // mapper_xp, unused for ANON
     205                                    local_cxy,
     206                                    &vseg );
     207    }
     208       
     209    if( vseg == NULL )
     210    {
     211        printk("\n[ERROR] in %s / thread[%x,%x] cannot create vseg in reference cluster\n",
     212        __FUNCTION__, process->pid, this->trdid );
     213        req.ptr = (void *)window;
     214        kmem_free( &req );
     215        return -1;
     216    }
     217
     218    // get vseg base
     219    vseg_base = (intptr_t)hal_remote_lpt( XPTR( ref_cxy , &vseg->min ) );
     220
     221#if (DEBUG_DEV_FBF & 1)
     222cycle = (uint32_t)hal_get_cycles();
     223if( DEBUG_DEV_FBF < cycle )
     224printk("\n[%s] thread[%x,%x] allocated vseg / base %x / cycle %d\n",
     225__FUNCTION__ , process->pid, this->trdid, vseg_base, cycle );
     226#endif
     227
     228    // take the lock protecting windows in write mode
     229    remote_rwlock_wr_acquire( windows_lock_xp );
     230
     231    // allocate a wid from allocator in FBF descriptor extension
     232    uint32_t wid = bitmap_remote_alloc( windows_bitmap_xp , CONFIG_FBF_WINDOWS_MAX_NR );
     233
     234    if( wid == 0xFFFFFFFF )
     235    {
     236        printk("\n[ERROR] in %s / thread[%x,%x] cannot allocate buffer for window\n",
     237        __FUNCTION__, process->pid, this->trdid );
     238        req.ptr = (void *)window;
     239        kmem_free( &req );
     240        vmm_remove_vseg( process , vseg );
     241        return -1;
     242    }
     243 
     244    // initialize window descriptor
     245    window->pid     = process->pid;
     246    window->wid     = wid;
     247    window->height  = nlines;
     248    window->width   = npixels;
     249    window->l_min   = l_min;
     250    window->p_min   = p_min;
     251    window->hidden  = false;
     252    window->buffer  = (uint8_t *)vseg_base;
     253
     254    // register new window in xlist rooted in FBF extension
     255    xlist_add_last( windows_root_xp , XPTR( local_cxy , &window->xlist ) );
     256
     257    // build extended pointer on relevant entry in windows_tbl[] array
     258    xptr_t windows_tbl_xp = XPTR( fbf_cxy , &fbf_ptr->ext.fbf.windows_tbl[wid] );
     259
     260    // register new window in windows_tbl[] stored in FBF extension
     261    hal_remote_s64( windows_tbl_xp , XPTR( local_cxy , window ) );
     262
     263    // release the lock protecting windows in write mode
     264    remote_rwlock_wr_release( windows_lock_xp );
     265
     266#if DEBUG_DEV_FBF
     267cycle = (uint32_t)hal_get_cycles();
     268if( DEBUG_DEV_FBF < cycle )
     269printk("\n[%s] thread[%x,%x] exit / wid %d / buffer %x / cycle %d\n",
     270__FUNCTION__ , this->process->pid, this->trdid, wid , window->buffer, cycle );
     271#endif
     272
     273#if (DEBUG_DEV_FBF & 1)
     274hal_vmm_display( ref_xp , true );
     275#endif
     276
     277    // return pointer on allocated buffer
     278    *user_buffer = vseg_base;
     279
     280    return wid;
     281
     282}  // end dev_fbf_create_window()
     283
     284////////////////////////////////////////////////////////////////////////////////////////
     285// This static function is called by the dev_fbf_display() function.
     286// For a partial FBF line, identified by the <f_line>, <f_p_min>, <f_p_max> arguments
     287// in FBF reference, and for one remote window, identified by the <window_xp> argument,
     288// it updates the target buffer identified by <t_buffer>, and containing exactly
     289// (f_p_max - f_p_min) pixels.
     290// Depending on the actual overlap between the window and the <t_buffer> representing
     291// the partial FBF line, it moves up to (f_p_max - f_p_min) pixels from the window
     292// buffer to the target buffer. The number of moved pixels can be nul if no overlap.
     293////////////////////////////////////////////////////////////////////////////////////////
     294// @ f_line     : [in]  line index in FBF reference (from 0 to fbf_height-1).
     295// @ f_p_min    : [in]  first pixel in FBF line.
     296// @ f_p_max    : [in]  last pixel in FBF line (excluded).
     297// @ window_xp  : [in]  extended pointer on checked window .
     298// @ t_buffer   : [out] local pointer on target buffer to be updated.
     299///////////////////////////////////////////////////////////////////////////////////////
     300__attribute__ ((noinline)) static void handle_one_window( uint32_t  f_line,
     301                                                          uint32_t  f_p_min,
     302                                                          uint32_t  f_p_max,
     303                                                          xptr_t    window_xp,
     304                                                          uint8_t * t_buffer )
     305{
     306    // get remote window descriptor cluster and local pointer
     307    cxy_t          window_cxy = GET_CXY( window_xp );
     308    fbf_window_t * window_ptr = GET_PTR( window_xp );
     309
     310    // get remote window min/max coordinates in FBF reference
     311    uint32_t  w_l_min    = hal_remote_l32( XPTR( window_cxy , &window_ptr->l_min ) );
     312    uint32_t  w_p_min    = hal_remote_l32( XPTR( window_cxy , &window_ptr->p_min ) );
     313    uint32_t  w_height   = hal_remote_l32( XPTR( window_cxy , &window_ptr->height ) );
     314    uint32_t  w_width    = hal_remote_l32( XPTR( window_cxy , &window_ptr->width  ) );
     315    uint32_t  w_l_max    = w_l_min + w_height;
     316    uint32_t  w_p_max    = w_p_min + w_width;
     317
     318    // does nothing if partial FBF line does not overlap the window
     319    if( (f_line < w_l_min)  || (f_line >= w_l_max) ||
     320        (f_p_max < w_p_min) || (f_p_min >= w_p_max) ) return;
     321
     322    // get pointer on window buffer in user space
     323    uint8_t * w_buffer = hal_remote_lpt( XPTR( window_cxy , &window_ptr->buffer ) );
     324
     325    // get min & max indexes for pixels to be moved in FBF reference
     326    uint32_t f_pixel_min = (f_p_min < w_p_min) ? w_p_min : f_p_min;
     327    uint32_t f_pixel_max = (f_p_max < w_p_max) ? f_p_max : w_p_max;
     328
     329    // compute number of pixels to move from w_buffer to f_buffer
     330    uint32_t npixels = f_pixel_max - f_pixel_min;
     331
     332    // compute offset in target buffer
     333    uint32_t t_offset = f_pixel_min - f_p_min;
     334
     335    // compute line index in window 
     336    uint32_t w_line = f_line - w_l_min;
     337
     338    // compute offset in window buffer
     339    uint32_t w_offset = (w_line * w_height) + f_pixel_min - w_p_min;
     340
     341    // move pixels from w_buffer (user space) to t_buffer in kernel space
     342    hal_copy_from_uspace( XPTR( local_cxy  , &t_buffer[t_offset]  ),
     343                          &w_buffer[w_offset],
     344                          npixels );
     345
     346}  // end handle_one_window()
     347
     348////////////////////////////////////////////////////////////////////////////////////////
     349// This static function is called by dev_fbf_refresh_window(), dev_fbf_move_window(),
     350// dev_fbf_resize_window(), and dev_fbf_delete_window(). It updates all lines of the
     351// window identified by the <window_xp>, <line_first>, and <line_last>> arguments.
     352// It scan all registered windows to take into account the overlap priorities defined
     353// by the windows xlist. It does not take the lock protecting the xlist, that must be
     354// taken by the calling function.
     355////////////////////////////////////////////////////////////////////////////////////////
     356// @ window_xp  : [in]  extended pointer on window defining the FBF pixels to refresh.
     357// @ line_first : [in]  first line index.
     358// @ line_last  : [in]  last line index (excluded).
     359////////////////////////////////////////////////////////////////////////////////////////
     360error_t fbf_update( xptr_t    window_xp,
     361                    uint32_t  line_first,
     362                    uint32_t  line_last )
     363{
     364    uint32_t       line;                // iterator to scan the FBF lines
     365    uint32_t       pixel;               // iterator to scan pixels in one FBF line
     366    xptr_t         iter_xp;             // iterator to scan the list of windows
     367    error_t        error;
     368
     369    // this intermediate buffer stores one line in
     370    // target window, to handle other windows overlap
     371    uint8_t       line_buffer[CONFIG_FBF_WINDOWS_MAX_WIDTH];
     372
     373    // get pointer on calling thread and core lid
     374    thread_t  * this = CURRENT_THREAD;
     375
     376    // get window cluster and local pointer
     377    cxy_t          window_cxy = GET_CXY( window_xp );
     378    fbf_window_t * window_ptr = GET_PTR( window_xp );
     379
     380#if DEBUG_DEV_FBF
     381uint32_t wid   = hal_remote_l32( XPTR( window_cxy , &window_ptr->wid ) );
     382uint32_t lid   = this->core->lid;
     383uint32_t cycle = (uint32_t)hal_get_cycles();
     384if( DEBUG_DEV_FBF < cycle )
     385printk("\n[%s] core[%x,%d] enter / wid %d / cycle %d\n",
     386__FUNCTION__, local_cxy, lid, wid, cycle );
    96387#endif
    97388
     
    101392    chdev_t   * fbf_ptr = GET_PTR( fbf_xp );
    102393
    103 // check fbf_xp definition
    104 assert( (fbf_xp != XPTR_NULL) , "undefined FBF chdev descriptor" );
     394    // get frame buffer width
     395    uint32_t fbf_width  = hal_remote_l32( XPTR( fbf_cxy , &fbf_ptr->ext.fbf.width ) );
     396
     397    // get pointer on driver command function
     398    dev_cmd_t * cmd = hal_remote_lpt( XPTR( fbf_cxy , &fbf_ptr->cmd ) );
     399
     400    // build extended pointers on windows xlist root
     401    xptr_t  windows_root_xp = XPTR( fbf_cxy , &fbf_ptr->ext.fbf.windows_root );
     402
     403    // get window size and coordinates
     404    uint32_t  p_min     = hal_remote_l32( XPTR( window_cxy , &window_ptr->p_min ) );
     405    uint32_t  l_min     = hal_remote_l32( XPTR( window_cxy , &window_ptr->l_min ) );
     406    uint32_t  w_pixels  = hal_remote_l32( XPTR( window_cxy , &window_ptr->width  ) );
     407
     408    error = 0;
     409
     410    // loop on target window lines (FBF coordinates)
     411    for( line = l_min + line_first ; line < (l_min + line_last) ; line++ )
     412    {
     413        // reset the line buffer to default value
     414        for( pixel = 0 ; pixel < w_pixels ; pixel++ ) line_buffer[pixel] = 127;
     415
     416        // loop on all windows
     417        XLIST_FOREACH( windows_root_xp , iter_xp )
     418        {
     419            // get pointers on remote window
     420            xptr_t         tgt_xp  = XLIST_ELEMENT( iter_xp , fbf_window_t , xlist );
     421            fbf_window_t * tgt_ptr = GET_PTR( window_xp );
     422            cxy_t          tgt_cxy = GET_CXY( window_xp );
     423
     424            bool_t hidden = hal_remote_l32( XPTR( tgt_cxy , &tgt_ptr->hidden ) );
     425
     426            // fill the line_buf for this window if not hidden
     427            if( hidden == false ) handle_one_window( line,               // line index
     428                                                     p_min,              // pixel_min
     429                                                     p_min + w_pixels,   // pixel_max
     430                                                     tgt_xp,             // window_xp     
     431                                                     line_buffer );     
     432        }  // end for windows
     433
     434        // compute offset in FBF
     435        uint32_t fbf_offset = p_min + (line * fbf_width);
     436
     437        // register command in calling thread descriptor
     438        this->fbf_cmd.dev_xp    = fbf_xp;
     439        this->fbf_cmd.type      = FBF_DRIVER_KERNEL_WRITE;
     440        this->fbf_cmd.buffer    = line_buffer;
     441        this->fbf_cmd.npixels   = w_pixels;
     442        this->fbf_cmd.offset    = fbf_offset;
     443
     444        // call driver to display one line
     445        cmd( XPTR( local_cxy , this ) );
     446
     447        error |= this->fbf_cmd.error;
     448   
     449    }  // end for lines
     450
     451#if DEBUG_DEV_FBF
     452cycle = (uint32_t)hal_get_cycles();
     453if( DEBUG_DEV_FBF < cycle )
     454printk("\n[%s] core[%x,%d] exit / wid %d / cycle %d\n",
     455__FUNCTION__, local_cxy, this->core->lid, wid, cycle );
     456#endif
     457
     458    // return I/O operation status
     459    return error;
     460
     461}  // end fbf_update()
     462
     463//////////////////////////////////////////////
     464error_t dev_fbf_delete_window( uint32_t  wid )
     465{
     466    kmem_req_t     req;
     467
     468    thread_t  * this    = CURRENT_THREAD;
     469    process_t * process = this->process;
     470
     471#if DEBUG_DEV_FBF
     472uint32_t   cycle = (uint32_t)hal_get_cycles();
     473if( DEBUG_DEV_FBF < cycle )
     474printk("\n[%s] thread[%x,%x] enters : wid %d / cycle %d\n",
     475__FUNCTION__ , process->pid, this->trdid, wid, cycle );
     476#endif
     477
     478    // get cluster and pointers on FBF chdev
     479    xptr_t      fbf_xp  = chdev_dir.fbf[0];
     480    cxy_t       fbf_cxy = GET_CXY( fbf_xp );
     481    chdev_t   * fbf_ptr = GET_PTR( fbf_xp );
     482
     483    // build extended pointers on windows lock, and wid allocator
     484    xptr_t windows_lock_xp = XPTR( fbf_cxy , &fbf_ptr->ext.fbf.windows_lock );
     485    xptr_t wid_bitmap_xp   = XPTR( fbf_cxy ,  fbf_ptr->ext.fbf.windows_bitmap );
     486
     487    // build extended pointer on relevant entry in windows_tbl[] array
     488    xptr_t  windows_tbl_xp = XPTR( fbf_cxy , &fbf_ptr->ext.fbf.windows_tbl[wid] );
     489
     490    // get extended pointer on remote window descriptor
     491    xptr_t window_xp  = hal_remote_l64( windows_tbl_xp );
     492
     493    if( window_xp == XPTR_NULL )
     494    {
     495        printk("\n[ERROR] in %s / thread[%x,%x] / wid %d non registered\n",
     496        __FUNCTION__, process->pid, this->trdid, wid );
     497        return -1;
     498    }
     499
     500    // get cluster and local pointer on remote window
     501    cxy_t          window_cxy = GET_CXY( window_xp );
     502    fbf_window_t * window_ptr = GET_PTR( window_xp );
     503
     504    // get process owner PID
     505    pid_t owner_pid = hal_remote_l32( XPTR( window_cxy , &window_ptr->pid ) );
     506
     507    // check caller PID / owner PID
     508    if( owner_pid != process->pid )
     509    {
     510        printk("\n[ERROR] in %s : caller PID (%x) != owner PID (%x)\n",
     511        __FUNCTION__, process->pid , owner_pid );
     512        return -1;
     513    }
     514
     515    // get associated buffer, and number of lines
     516    uint8_t  * buffer = hal_remote_lpt( XPTR( window_cxy , &window_ptr->buffer ) );
     517    uint32_t   nlines = hal_remote_l32( XPTR( window_cxy , &window_ptr->height ) );
     518
     519    // 1. take the lock protecting windows in write mode
     520    remote_rwlock_wr_acquire( windows_lock_xp );
     521
     522    // 2. update the FBF window
     523    fbf_update( window_xp , 0 , nlines );
     524
     525    // 3. remove the window from windows_tbl[] array
     526    hal_remote_s64( windows_tbl_xp , XPTR_NULL );
     527
     528    // 4. remove the window from xlist     
     529    xlist_unlink( XPTR( window_cxy , &window_ptr->xlist ) );
     530
     531    // 5. release wid to bitmap
     532    bitmap_remote_clear( wid_bitmap_xp , wid );
     533
     534    // 6. release the lock protecting windows in write mode
     535    remote_rwlock_wr_release( windows_lock_xp );
     536 
     537    // 7. release memory allocated for window descriptor
     538    req.type = KMEM_KCM;
     539    req.ptr  = window_ptr;
     540    kmem_remote_free( window_cxy , &req );
     541
     542    // 8. release the associated vseg
     543    vmm_global_delete_vseg( process , (intptr_t)buffer );
     544   
     545#if DEBUG_DEV_FBF
     546cycle = (uint32_t)hal_get_cycles();
     547if( DEBUG_DEV_FBF < cycle )
     548printk("\n[%s] thread[%x,%x] exit / cycle %d\n",
     549__FUNCTION__ , process->pid, this->trdid, cycle );
     550#endif
     551
     552    return 0;
     553
     554}  // end dev_fbf_delete_window()
     555
     556////////////////////////////////////////////
     557error_t dev_fbf_move_window( uint32_t  wid,
     558                             uint32_t  l_min,
     559                             uint32_t  p_min )
     560{
     561    thread_t  * this    = CURRENT_THREAD;
     562    process_t * process = this->process;
     563
     564#if DEBUG_DEV_FBF
     565uint32_t   cycle = (uint32_t)hal_get_cycles();
     566if( DEBUG_DEV_FBF < cycle )
     567printk("\n[%s] thread[%x,%x] enters : wid %d / l_min %d / p_min %d / cycle %d\n",
     568__FUNCTION__ , process->pid, this->trdid, wid, l_min, p_min, cycle );
     569#endif
     570
     571    // get cluster and pointers on FBF chdev
     572    xptr_t      fbf_xp  = chdev_dir.fbf[0];
     573    cxy_t       fbf_cxy = GET_CXY( fbf_xp );
     574    chdev_t   * fbf_ptr = GET_PTR( fbf_xp );
     575
     576    // build extended pointers on windows lock and root
     577    xptr_t windows_lock_xp = XPTR( fbf_cxy , &fbf_ptr->ext.fbf.windows_lock );
     578    xptr_t windows_root_xp = XPTR( fbf_cxy , &fbf_ptr->ext.fbf.windows_root );
     579
     580    // build extended pointer on relevant entry in windows_tbl[] array
     581    xptr_t  windows_tbl_xp = XPTR( fbf_cxy , &fbf_ptr->ext.fbf.windows_tbl[wid] );
     582
     583    // get extended pointer on remote window descriptor
     584    xptr_t window_xp  = hal_remote_l64( windows_tbl_xp );
     585
     586    if( window_xp == XPTR_NULL )
     587    {
     588        printk("\n[ERROR] in %s / thread[%x,%x] / wid %d non registered\n",
     589        __FUNCTION__, process->pid, this->trdid, wid );
     590        return -1;
     591    }
     592
     593    // get cluster and local pointer for remote window
     594    cxy_t          window_cxy = GET_CXY( window_xp );
     595    fbf_window_t * window_ptr = GET_PTR( window_xp );
     596
     597    // get process owner PID, coordinates, and number of lines
     598    pid_t    owner_pid = hal_remote_l32( XPTR( window_cxy , &window_ptr->pid ) );
     599    uint32_t p_zero    = hal_remote_l32( XPTR( window_cxy , &window_ptr->p_min ) );
     600    uint32_t l_zero    = hal_remote_l32( XPTR( window_cxy , &window_ptr->l_min ) );
     601    uint32_t nlines    = hal_remote_l32( XPTR( window_cxy , &window_ptr->height ) );
     602
     603    // check caller PID / owner PID
     604    if( owner_pid != process->pid )
     605    {
     606        printk("\n[ERROR] in %s : caller PID (%x) != owner PID (%x)\n",
     607        __FUNCTION__, process->pid , owner_pid );
     608        return -1;
     609    }
     610
     611    // does nothing if no change
     612    if( (p_zero == p_min) && (l_zero == l_min) )  return 0;
     613
     614    // 1. take the lock protecting windows in write mode
     615    remote_rwlock_wr_acquire( windows_lock_xp );
     616
     617#if ( DEBUG_DEV_FBF & 1 )
     618printk("\n[%s] lock taken\n", __FUNCTION__ );
     619#endif
     620
     621    // 2. gives the window the lowest priority
     622    xptr_t xlist_entry_xp =  XPTR( window_cxy , &window_ptr->xlist );
     623    xlist_unlink( xlist_entry_xp );
     624    xlist_add_first( windows_root_xp , xlist_entry_xp );
     625
     626#if ( DEBUG_DEV_FBF & 1 )
     627printk("\n[%s] set low priority \n", __FUNCTION__ );
     628#endif
     629
     630    // 3. set the "hidden" flag in window descriptor
     631    hal_remote_s32( XPTR( window_cxy , &window_ptr->hidden ) , true );
     632
     633#if ( DEBUG_DEV_FBF & 1 )
     634printk("\n[%s] hidden set\n", __FUNCTION__ );
     635#endif
     636
     637    // 4. refresh the FBF for the current window position
     638    fbf_update( window_xp , 0 , nlines );
     639
     640#if ( DEBUG_DEV_FBF & 1 )
     641printk("\n[%s] refreshed old position\n", __FUNCTION__ );
     642#endif
     643
     644    // 5. set the new coordinates in the window descriptor,
     645    hal_remote_s32( XPTR( window_cxy , &window_ptr->l_min ), l_min );
     646    hal_remote_s32( XPTR( window_cxy , &window_ptr->p_min ), p_min );
     647
     648#if ( DEBUG_DEV_FBF & 1 )
     649printk("\n[%s] l_min & p_min updated\n", __FUNCTION__ );
     650#endif
     651
     652    // 6. gives the window the highest priority
     653    xlist_unlink( xlist_entry_xp );
     654    xlist_add_last( windows_root_xp , xlist_entry_xp );
     655
     656#if ( DEBUG_DEV_FBF & 1 )
     657printk("\n[%s] set high priority\n", __FUNCTION__ );
     658#endif
     659
     660    // 7. reset the "hidden" flag in window descriptor
     661    hal_remote_s32( XPTR( window_cxy , &window_ptr->hidden ) , false );
     662
     663#if ( DEBUG_DEV_FBF & 1 )
     664printk("\n[%s] hidden reset\n", __FUNCTION__ );
     665#endif
     666
     667    // 8. refresh the FBF for the new window position
     668    fbf_update( window_xp , 0 , nlines );
     669
     670#if ( DEBUG_DEV_FBF & 1 )
     671printk("\n[%s] refresh new position\n", __FUNCTION__ );
     672#endif
     673
     674    // 9. release the lock protecting windows in write mode
     675    remote_rwlock_wr_release( windows_lock_xp );
     676 
     677#if DEBUG_DEV_FBF
     678cycle = (uint32_t)hal_get_cycles();
     679if( DEBUG_DEV_FBF < cycle )
     680printk("\n[%s] thread[%x,%x] exit / cycle %d\n",
     681__FUNCTION__ , process->pid, this->trdid, cycle );
     682#endif
     683
     684    return 0;
     685
     686}  // end dev_fbf_move_window()
     687
     688/////////////////////////////////////////////
     689error_t dev_fbf_resize_window( uint32_t  wid,
     690                               uint32_t  width,
     691                               uint32_t  height )
     692{
     693    thread_t  * this    = CURRENT_THREAD;
     694    process_t * process = this->process;
     695
     696#if DEBUG_DEV_FBF
     697uint32_t   cycle = (uint32_t)hal_get_cycles();
     698if( DEBUG_DEV_FBF < cycle )
     699printk("\n[%s] thread[%x,%x] enters : wid %d / width %d / height %d / cycle %d\n",
     700__FUNCTION__ , process->pid , this->trdid , wid, width , height , cycle );
     701#endif
     702
     703    // get cluster and pointers on FBF chdev
     704    xptr_t      fbf_xp  = chdev_dir.fbf[0];
     705    cxy_t       fbf_cxy = GET_CXY( fbf_xp );
     706    chdev_t   * fbf_ptr = GET_PTR( fbf_xp );
     707
     708    // build extended pointers on windows lock and root
     709    xptr_t windows_lock_xp = XPTR( fbf_cxy , &fbf_ptr->ext.fbf.windows_lock );
     710    xptr_t windows_root_xp = XPTR( fbf_cxy , &fbf_ptr->ext.fbf.windows_root );
     711
     712    // build extended pointer on relevant entry in windows_tbl[] array
     713    xptr_t  windows_tbl_xp = XPTR( fbf_cxy , &fbf_ptr->ext.fbf.windows_tbl[wid] );
     714
     715    // get extended pointer on remote window descriptor
     716    xptr_t window_xp  = hal_remote_l64( windows_tbl_xp );
     717
     718    if( window_xp == XPTR_NULL )
     719    {
     720        printk("\n[ERROR] in %s / thread[%x,%x] / wid %d non registered\n",
     721        __FUNCTION__, process->pid, this->trdid, wid );
     722        return -1;
     723    }
     724
     725    // get cluster and local pointer for remote window
     726    cxy_t          window_cxy = GET_CXY( window_xp );
     727    fbf_window_t * window_ptr = GET_PTR( window_xp );
     728
     729    // get process owner PID, width, height, and buffer
     730    pid_t    owner_pid = hal_remote_l32( XPTR( window_cxy , &window_ptr->pid ) );
     731    uint32_t nlines    = hal_remote_l32( XPTR( window_cxy , &window_ptr->height ) );
     732    uint32_t npixels   = hal_remote_l32( XPTR( window_cxy , &window_ptr->width ) );
     733    void   * base      = hal_remote_lpt( XPTR( window_cxy , &window_ptr->buffer ) );
     734
     735    // check caller PID / owner PID
     736    if( owner_pid != process->pid )
     737    {
     738        printk("\n[ERROR] in %s : caller PID (%x) != owner PID (%x)\n",
     739        __FUNCTION__, process->pid , owner_pid );
     740        return -1;
     741    }
     742
     743    // does nothing if no change
     744    if( (width == npixels) && (height == nlines) ) return 0;
     745
     746    // compute old_size and new size
     747    uint32_t old_size = nlines * npixels;
     748    uint32_t new_size = width * height;
     749
     750    // 1. take the lock protecting windows in write mode
     751    remote_rwlock_wr_acquire( windows_lock_xp );
     752
     753#if ( DEBUG_DEV_FBF & 1 )
     754printk("\n[%s] lock taken\n", __FUNCTION__ );
     755#endif
     756
     757    // 2. gives the window the lowest priority (remove, then add first)
     758    xptr_t xlist_entry_xp =  XPTR( window_cxy , &window_ptr->xlist );
     759    xlist_unlink( xlist_entry_xp );
     760    xlist_add_first( windows_root_xp , xlist_entry_xp );
     761
     762#if ( DEBUG_DEV_FBF & 1 )
     763printk("\n[%s] set low priority\n", __FUNCTION__ );
     764#endif
     765
     766    // 3. set the "hidden" flag in window descriptor
     767    hal_remote_s32( XPTR( window_cxy , &window_ptr->hidden ) , true );
     768
     769#if ( DEBUG_DEV_FBF & 1 )
     770printk("\n[%s] hidden set\n", __FUNCTION__ );
     771#endif
     772
     773    // 4. refresh the FBF for the current window size
     774    fbf_update( window_xp , 0 , nlines );
     775
     776#if ( DEBUG_DEV_FBF & 1 )
     777printk("\n[%s] refreshed old window\n", __FUNCTION__ );
     778#endif
     779
     780    // 5. set the new width & height in the window descriptor,
     781    hal_remote_s32( XPTR( window_cxy , &window_ptr->width  ), width );
     782    hal_remote_s32( XPTR( window_cxy , &window_ptr->height ), height );
     783
     784#if ( DEBUG_DEV_FBF & 1 )
     785printk("\n[%s] width & height updated\n", __FUNCTION__ );
     786#endif
     787
     788    // 6. resize vseg if required
     789    vmm_global_resize_vseg( process, (intptr_t)base, (intptr_t)base, width * height );
     790
     791#if ( DEBUG_DEV_FBF & 1 )
     792printk("\n[%s] vseg resized\n", __FUNCTION__ );
     793#endif
     794
     795    // 7. fill buffer extension if required
     796    if( new_size > old_size )  memset( base + old_size , 0 , new_size - old_size );
     797
     798#if ( DEBUG_DEV_FBF & 1 )
     799printk("\n[%s] buffer extension initialized\n", __FUNCTION__ );
     800#endif
     801
     802    // 8. gives the window the highest priority
     803    xlist_unlink( xlist_entry_xp );
     804    xlist_add_last( windows_root_xp , xlist_entry_xp );
     805
     806#if ( DEBUG_DEV_FBF & 1 )
     807printk("\n[%s] set high priority\n", __FUNCTION__ );
     808#endif
     809
     810    // 9. reset the "hidden" flag in window descriptor
     811    hal_remote_s32( XPTR( window_cxy , &window_ptr->hidden ) , false );
     812
     813#if ( DEBUG_DEV_FBF & 1 )
     814printk("\n[%s] hidden reset\n", __FUNCTION__ );
     815#endif
     816
     817    // 10. refresh the FBF for the new window position
     818    fbf_update( window_xp , 0 , height );
     819
     820#if ( DEBUG_DEV_FBF & 1 )
     821printk("\n[%s] refresh new position\n", __FUNCTION__ );
     822#endif
     823
     824    // 11. release the lock protecting windows in write mode
     825    remote_rwlock_wr_release( windows_lock_xp );
     826 
     827#if DEBUG_DEV_FBF
     828cycle = (uint32_t)hal_get_cycles();
     829if( DEBUG_DEV_FBF < cycle )
     830printk("\n[%s] thread[%x,%x] exit / cycle %d\n",
     831__FUNCTION__ , process->pid, this->trdid, cycle );
     832#endif
     833
     834    return 0;
     835
     836}  // end dev_fbf_resize_window()
     837
     838///////////////////////////////////////////////
     839error_t dev_fbf_refresh_window( uint32_t  wid,
     840                                uint32_t  line_first,
     841                                uint32_t  line_last )
     842{
     843    // get local pointers on calling thread and process
     844    thread_t  * this    = CURRENT_THREAD;
     845    process_t * process = this->process;
     846
     847#if DEBUG_DEV_FBF
     848uint32_t   cycle = (uint32_t)hal_get_cycles();
     849if( DEBUG_DEV_FBF < cycle )
     850printk("\n[%s] thread[%x,%x] enters for wid %d / first %d / last %d / cycle %d\n",
     851__FUNCTION__ , process->pid, this->trdid, wid, line_first, line_last, cycle );
     852#endif
     853
     854    // get cluster and pointers on FBF chdev
     855    xptr_t      fbf_xp  = chdev_dir.fbf[0];
     856    cxy_t       fbf_cxy = GET_CXY( fbf_xp );
     857    chdev_t   * fbf_ptr = GET_PTR( fbf_xp );
     858
     859    // build extended pointer on windows lock
     860    xptr_t  windows_lock_xp = XPTR( fbf_cxy , &fbf_ptr->ext.fbf.windows_lock );
     861
     862    // build extended pointer on relevant entry in windows_tbl[] array
     863    xptr_t  windows_tbl_xp  = XPTR( fbf_cxy , &fbf_ptr->ext.fbf.windows_tbl[wid] );
     864
     865    // get pointers on remote window descriptor
     866    xptr_t         window_xp  = hal_remote_l64( windows_tbl_xp );
     867    cxy_t          window_cxy = GET_CXY( window_xp );
     868    fbf_window_t * window_ptr = GET_PTR( window_xp );
     869
     870    // check <wid> argument
     871    if( window_xp == XPTR_NULL )
     872    {
     873        printk("\n[ERROR] in %s / thread[%x,%x] / wid %d non registered\n",
     874        __FUNCTION__, process->pid, this->trdid, wid );
     875        return -1;
     876    }
     877
     878    // get process owner PID
     879    pid_t owner_pid = hal_remote_l32( XPTR( window_cxy , &window_ptr->pid ) );
     880
     881    // check caller PID / owner PID
     882    if( owner_pid != process->pid )
     883    {
     884        printk("\n[ERROR] in %s : caller PID (%x) != owner PID (%x)\n",
     885        __FUNCTION__, process->pid , owner_pid );
     886        return -1;
     887    }
     888
     889    // get number of lines in window
     890    uint32_t nlines = hal_remote_l32( XPTR( window_cxy , &window_ptr->height ) );
     891
     892    // check <line_first> and <line_last> arguments
     893    if( (line_first >= nlines) || (line_last > nlines) || (line_first >= line_last) )
     894    {
     895        printk("\n[ERROR] in %s : illegal (l_first %d , l_last %d) / height %d\n",
     896        __FUNCTION__, line_first, line_last, nlines );
     897        return -1;
     898    }
     899
     900    // take the lock protecting windows xlist in read mode
     901    remote_rwlock_rd_acquire( windows_lock_xp );
     902
     903    // update FBF
     904    fbf_update( window_xp , line_first , line_last );
     905
     906    // release the lock protecting windows xlist in write mode
     907    remote_rwlock_rd_release( windows_lock_xp );
     908
     909#if DEBUG_DEV_FBF
     910cycle = (uint32_t)hal_get_cycles();
     911if( DEBUG_DEV_FBF < cycle )
     912printk("\n[%s] thread[%x,%x] exit for wid %d / cycle %d\n",
     913__FUNCTION__, process->pid, this->trdid, wid, cycle );
     914#endif
     915
     916    return 0;
     917
     918}  // end dev_fbf_refresh_window()
     919
     920///////////////////////////////////////////////
     921// TODO Deprecated : january 2020 [AG]
     922///////////////////////////////////////////////
     923error_t dev_fbf_move_data( bool_t     is_write,
     924                           void     * user_buffer,
     925                           uint32_t   npixels,
     926                           uint32_t   offset )
     927{
     928    // get pointer on calling thread
     929    thread_t * this = CURRENT_THREAD;
     930
     931#if DEBUG_DEV_FBF
     932uint32_t   cycle = (uint32_t)hal_get_cycles();
     933if( DEBUG_DEV_FBF < cycle )
     934printk("\n[%s] thread[%x,%x] :  buffer %x / npixels %d / offset %x / cycle %d\n",
     935__FUNCTION__ , this->process->pid, this->trdid, 
     936user_buffer, npixels, offset, cycle );
     937#endif
     938
     939    // get pointers on FBF chdev
     940    xptr_t      fbf_xp  = chdev_dir.fbf[0];
     941    cxy_t       fbf_cxy = GET_CXY( fbf_xp );
     942    chdev_t   * fbf_ptr = GET_PTR( fbf_xp );
    105943
    106944    // get frame buffer width and height
     
    108946    uint32_t height = hal_remote_l32 ( XPTR( fbf_cxy , &fbf_ptr->ext.fbf.height ) );
    109947
    110 // check offset and length versus FBF size
    111 assert( ((offset + length) <= (width * height)) ,
    112 "offset %d / length %d / width %d / height %d\n", offset, length, width, height );
     948    // check offset and npixels versus FBF size
     949    if( ((offset + npixels) > (width * height)) )
     950    {
     951        printk("\n[ERROR] in %s : offset (%d) + npixels (%d) / width (%d) / height (%d)\n",
     952        __FUNCTION__, offset, npixels, width, height );
     953        return -1;
     954    }
    113955
    114956    // register command in calling thread descriptor
    115957    this->fbf_cmd.dev_xp    = fbf_xp;
    116     this->fbf_cmd.type      = cmd_type;
     958    this->fbf_cmd.type      = is_write ? FBF_DRIVER_USER_WRITE : FBF_DRIVER_USER_READ;
    117959    this->fbf_cmd.buffer    = user_buffer;
    118960    this->fbf_cmd.offset    = offset;
    119     this->fbf_cmd.length    = length;
     961    this->fbf_cmd.npixels   = npixels;
    120962
    121963    // get driver command function
     
    130972cycle = (uint32_t)hal_get_cycles();
    131973if( DEBUG_DEV_FBF < cycle )
    132 printk("\n[%s] thread[%x,%x] completes %s / error = %d / cycle %d\n",
    133 __FUNCTION__ , this->process->pid, this->trdid, 
    134 dev_fbf_cmd_str(cmd_type), error , cycle );
     974printk("\n[%s] thread[%x,%x] exit / cycle %d\n",
     975__FUNCTION__ , this->process->pid, this->trdid, cycle );
    135976#endif
    136977
     
    139980
    140981}  // end dev_fbf_move_data()
     982
     983
  • trunk/kernel/devices/dev_fbf.h

    r647 r657  
    11/*
    2  * dev_fbf.h - FBF (Block Device Controler) generic device API definition.
     2 * dev_fbf.h - FBF (Frame Buffer) generic device API definition.
    33 *
    4  * Author  Alain Greiner    (2016,2017,2018,2019)
     4 * Author  Alain Greiner    (2016,2017,2018,2019,2020)
    55 *
    66 * Copyright (c) UPMC Sorbonne Universites
     
    2727#include <hal_kernel_types.h>
    2828#include <shared_fbf.h>
     29#include <remote_rwlock.h>
     30#include <bits.h>
    2931
    3032/****  Forward declarations  ****/
     
    3335
    3436/*****************************************************************************************
    35  *     Generic Frame Buffer Controler definition
     37 *      Frame Buffer Controler API definition
    3638 *
    3739 * This device provide access to an external graphic display, that is seen
    3840 * as a fixed size frame buffer, mapped in the kernel address space.
    39  * The supported  pixel encoding types are defined in the <shared_fbf.h> file.
    40  *
    41  * It supports three command types:
    42  * GET_CONFIG : return frame buffer size and type.
    43  * READ       : move bytes from frame buffer to memory / deschedule the calling thread.
    44  * WRITE      : move bytes from memory to frame buffer / deschedule the calling thread.
    45  *
    46  * The READ and WRITE operations do not use the FBF device waiting queue,
    47  * the server thread, and the IOC IRQ. The client thread does not deschedule:
    48  * it registers the command in the thread descriptor, and calls directly the FBF driver.
    49  * that makes a (user <-> kernel) memcpy.
     41 * The only pixel encoding type in the current implementation is one byte per pixel
     42 * (256 levels of gray).
     43 *
     44 * It supports a first API, for the user syscalls, implementing a simple windows manager.
     45 * This windows manager allows any process to create and use for display one (or several)
     46 * window(s). Each window defines a private buffer, dynamically allocated in user space,
     47 * that can be directly accessed by the owner process.
     48 * These windows can be moved in the frame buffer, they can be resized, they can overlap
     49 * other windows, but a window must be entirely contained in the frame buffer.
     50 *
     51 * To avoid contention, the window descriptor, and the associated user buffer are not
     52 * allocated in the cluster containing the FBF chdev, but are distributed: each window
     53 * is allocated in the cluster defined by the thread that required the window creation.
     54 *
     55 * Each window has a single process owner, but all the windows are registered in the FBF
     56 * chdev as a windows_tbl[] array, indexed by the window identifier (wid), and each entry
     57 * contains an extended pointer on the window descriptor. All windows are also registered
     58 * in a trans-cluster xlist, defining the overlapping order (last window in xlist has the
     59 * highest priority).
     60 *
     61 * To refresh a window <wid>, the owner process calls the dev_fbf_refresh_window()
     62 * function, that sends parallel RPC_FBF_DISPLAY requests to other cores. All cores
     63 * synchronously execute the dev_fbf_display() function. This function scan all windows
     64 * to respect the overlaping order, and updates all pixels of the <wid> window.
    5065 *
    51  * Note: As we don't use any external DMA to move data, but a purely software approach,
    52  * there is no L2/L3 coherence issue.
     66 * 1) This "syscall" API defines five syscalls :
     67 * - FBF_GET_CONFIG     : returns the FBF width, height, and pixel encoding type.
     68 * - FBF_CREATE_WINDOW  : create a new window , owned by the calling process.
     69 * - FBF_DELETE_WINDOW  : delete a registered window.
     70 * - FBF_MOVE_WINDOW    : move in FBF a registered window.
     71 * - FBF_REFRESH_WINDOW : request refresh of a given window.
     72 *
     73 * These 5 operations do not use the FBF device waiting queue, the associated
     74 * device thread and the FBF IRQ, as the client thread does NOT deschedule,
     75 * and does NOT call the FBF driver.
     76 *
     77 * 2) Two extra syscalls exist but are deprecated:
     78 * - FBF_DIRECT_WRITE   : move synchronously pixels from an user buffer to the FBF.
     79 * - FBF_DIRECT_READ    : move synchronously pixels from the FBF to an user buffer.
     80 *
     81 * For these deprecated operations, the client thread calls
     82 * directly the driver to move data between the user buffer and the FBF.
     83 *
     84 * 3) The FBF device defines defines four command types to access FBF driver(s) :
     85 * - FBF_DRIVER_KERNEL_WRITE : move pixels from a kernel window to the FBF.
     86 * - FBF_DRIVER_KERNEL_READ  : move pixels from the FBF to a kernel window.
     87 * - FBF_DRIVER_USER_WRITE   : move bytes from an user buffer to the FBF.
     88 * - FBF_DRIVER_USER_READ    : move bytes from the FBF to an user buffer.
     89 *
     90 * Note: As we don't use any external DMA to move data to or from the frame buffer,
     91 * but only software memcpy, there is no L2/L3 coherence issue for this device.
     92 *
    5393 *****************************************************************************************/
    5494
     
    5999typedef struct fbf_extend_s
    60100{
    61     uint32_t           width;         /*! number of pixels per line.                     */
    62     uint32_t           height;        /*! total number of lines.                         */
    63     uint32_t           subsampling;   /*! pixel encoding type.                           */
     101    remote_rwlock_t windows_lock;        /*! lock protecting windows xlist               */
     102    xlist_entry_t   windows_root;        /*! root of the windows xlist                   */
     103
     104    xptr_t          windows_tbl[CONFIG_FBF_WINDOWS_MAX_NR];         /*! window desc.     */
     105    bitmap_t        windows_bitmap[CONFIG_FBF_WINDOWS_MAX_NR >> 5]; /*! wid allocator    */
     106
     107    uint32_t        width;               /*! number of pixels per line.                  */
     108    uint32_t        height;              /*! total number of lines.                      */
     109    uint32_t        subsampling;         /*! pixel encoding type.                        */
    64110}
    65111fbf_extend_t;
     
    70116 *****************************************************************************************/
    71117
    72 enum fbf_impl_e
     118typedef enum
    73119{
    74120    IMPL_FBF_SCL =   0,     
     
    77123fbf_impl_t;
    78124
     125/******************************************************************************************
     126 * This structure defines the FBF command for all drivers implementing the FBF device.
     127 *****************************************************************************************/
     128
     129typedef enum
     130{
     131    FBF_DRIVER_USER_READ     = 1,
     132    FBF_DRIVER_USER_WRITE    = 2,
     133    FBF_DRIVER_KERNEL_READ   = 3,
     134    FBF_DRIVER_KERNEL_WRITE  = 4,
     135}
     136fbf_driver_cmd_type_t;
     137
    79138typedef struct fbf_command_s
    80139{
    81140    xptr_t      dev_xp;        /*! extended pointer on device descriptor                 */
    82     uint32_t    type;          /*! requested operation type.                             */
    83     uint32_t    length;        /*! number of bytes.                                      */
    84     uint32_t    offset;        /*! offset in frame buffer (bytes)                        */
    85     void      * buffer;        /*! pointer on memory buffer in user space                */
     141    uint32_t    type;          /*! requested driver operation type.                      */
     142    uint32_t    npixels;       /*! number of bytes.                                      */
     143    uint32_t    offset;        /*! offset in frame buffer (pixels)                       */
     144    void      * buffer;        /*! pointer on memory buffer (kernel or user)             */
    86145    uint32_t    error;         /*! operation status (0 if success)                       */
    87146}
    88147fbf_command_t;
    89148
    90 
    91 /******************************************************************************************
    92  * This function returns a printable string for a given FBF command  <cmd_type>.
    93  ******************************************************************************************
    94  * @ cmd_type   :  FBF command type (defined in shared_fbf.h file).
     149/******************************************************************************************
     150 * This structure defines an FBF window descriptor, allocated to a given user process.
     151 * The window descriptor and the associated buffer are allocated in the cluster where
     152 * is running the thread requesting the window creation.
     153 * The <wid> allocator, the window_tbl[] array, and the root of the xlist of windows are
     154 * imlemented in the FBF device extension.
     155 *****************************************************************************************/
     156
     157typedef struct fbf_window_s
     158{
     159    pid_t          pid;         /*! owner process identifier                             */
     160    uint32_t       wid;         /*! window identifier                                    */
     161    uint32_t       height;      /*! number of lines in window                            */
     162    uint32_t       width;       /*! number of pixels per line in window                  */
     163    uint32_t       l_min;       /*! first line index in FBF                              */
     164    uint32_t       p_min;       /*! first pixel index in FBF                             */
     165    uint8_t      * buffer;      /*! pointer on buffer in user space                      */
     166    bool_t         hidden;      /*! no display on FBF when true                          */
     167    xlist_entry_t  xlist;       /*! member of registered FBF windows list                */
     168}
     169fbf_window_t;
     170
     171/******************************************************************************************
     172 * This function returns a printable string for a given FBF user command  <cmd_type>.
     173 * WARNING : It must be kept consistent with the enum in the <shared_fbf.h> file
     174 ******************************************************************************************
     175 * @ cmd_type   :  FBF user command type (defined in shared_fbf.h file).
    95176 * @ returns a string pointer.
    96177 *****************************************************************************************/
     
    100181 * This function completes the FBF chdev descriptor initialisation.
    101182 * It calls the specific driver initialisation function, to initialise the hardware
    102  * device and the chdev extension. It must be called by a local thread.
     183 * device, and the chdev extension. It must be called by a local thread.
    103184 ******************************************************************************************
    104185 * @ chdev      : pointer on FBF chdev descriptor.
     
    107188
    108189/******************************************************************************************
    109  * This function returns the frame buffer size and type.
     190 * This function implements the fbf_get_config() syscall, and returns the FBF
     191 * size and type. It can be called by a client thread running in any cluster.
    110192 * It does NOT access the hardware, as the size and type have been registered
    111  * in the chdev descriptor extension.
     193 * in the chdev descriptor extension by the dev_fbf_init() function.
     194 * It can be called by any thread running in any cluster.
    112195 ******************************************************************************************
    113196 * @ width     : [out] number of pixels per line.
     
    120203
    121204/******************************************************************************************
    122  * This blocking function moves <length> bytes between the frame buffer, starting from
    123  * byte defined by <offset>, and an user buffer defined by the <user_buffer> argument.
    124  * It can be called by a client thread running in any cluster.
    125  * The transfer direction are defined by the <cmd_type> argument.
     205 * This function implements the fbf_create_window() syscall.
     206 * It registers a new window in the windows_tbl[] array, and the windows list,
     207 * registers in the reference cluster an ANON vseg, that will be mapped in local cluster.
     208 * The window index <wid> is dynamically allocated. The owner is the calling process.
     209 * The FBF window is defined by the <nlines>, <npixels>, <l_min>, <p_min> arguments.
     210 * It can be called by any thread running in any cluster. As this vseg is not directly
     211 * mapped to the frame buffer, the owner process can access this private buffer without
     212 * syscall. As for any vseg, the physical memory is allocated on demand at each page fault.
     213* The created vseg base address in user space is returned in the <user_base> argument.
     214 *
     215 * Implementation note:
     216 * 1. it allocates memory in the local cluster for the window,
     217 * 2. it creates in the associated vseg,
     218 * 3. it initializes the window descriptor,
     219 * 4. it takes the lock protecting the windows in write mode,
     220 * 5. it allocates a new  <wid>,
     221 * 6. it registers the window in the window_tbl[] array,
     222 * 7. it registers the window in the windows list,
     223 * 8. it releases the lock protecting windows.
     224 * It does not call the FBF driver.
     225 ******************************************************************************************
     226 * @ nlines      : [in]  number of lines in window.
     227 * @ npixels     : [in]  number of pixels per line in window.
     228 * @ l_min       : [in]  first pixel index in FBF.
     229 * @ p_min       : [in]  first line index in FBF.
     230 * @ user_base   : [out] pointer on allocated buffer base in user space.
     231 * @ return the <wid> index if success / returns -1 if failure
     232 *****************************************************************************************/
     233uint32_t dev_fbf_create_window( uint32_t   nlines,
     234                                uint32_t   npixels,
     235                                uint32_t   l_min,
     236                                uint32_t   p_min,
     237                                intptr_t * user_base );
     238
     239/******************************************************************************************
     240 * This function implements the fbf_delete_window() syscall to delete a FBF window,
     241 * and release all memory allocated for this window and for the associated vseg.
     242 * releases the memory allocated for the window buffer and for the window descriptor.
     243 * It can be called by any thread running in any cluster.
     244 *
     245 * Implementation note:
     246 * 1. it takes the lock protecting windows in write mode,
     247 * 2. it set the hidden flag in deleted window descriptor,
     248 * 3. it refresh the FBF window,
     249 * 4. it removes the window from windows_tbl[] array,
     250 * 5. it removes the window from xlist,     
     251 * 6. it releases the wid to bitmap,
     252 * 7. it releases the lock protecting windows,
     253 * 8. it releases the memory allocated for window descriptor,
     254 * 9. it deletes the associated vseg in all clusters
     255 * It does not call directly the FBF driver.
     256 ******************************************************************************************
     257 * @ wid       : [in] window index in window_tbl[].
     258 * @ returns 0 if success / returns -1 if wid not registered.
     259 *****************************************************************************************/
     260error_t dev_fbf_delete_window( uint32_t wid );
     261                               
     262/******************************************************************************************
     263 * This function implements the fbf_move_window() syscall.
     264 * It moves a window identified by the <wid> argument to a new position in the FBF,
     265 * defined by the <l_min> and <p_min> arguments.
     266 * It can be called by any thread running in any cluster.
     267 *
     268 * Implementation note:
     269 * 1. it takes the lock protecting windows in write mode,
     270 * 2. it gives the modified window the lowest priority,
     271 * 3. it set the "hidden" flag in window descriptor,
     272 * 4. it refresh the FBF for the current window position,
     273 * 5. it set the new coordinates in the window descriptor,
     274 * 6. it gives the modified window the highest priority,
     275 * 7. it reset the "hidden" flag in window descriptor,
     276 * 8. it refresh the FBF for the new window position,
     277 * 9. it releases the lock protecting windows,
     278 * It does not call directly the FBF driver.
     279 ******************************************************************************************
     280 * @ wid       : [in] window index in window_tbl[].
     281 * @ l_min     : [in] new first pixel index in FBF.
     282 * @ p_min     : [in] new first line index in FBF.
     283 * @ returns 0 if success / returns -1 if illegal arguments.
     284 *****************************************************************************************/
     285error_t dev_fbf_move_window( uint32_t wid,
     286                             uint32_t l_min,
     287                             uint32_t p_min );
     288
     289/******************************************************************************************
     290 * This function implements the fbf_resize_window() syscall.
     291 * It changes the <width> and <height> of a window identified by the <wid> argument.
     292 * It updates the associated vseg "size" if required, but does not change the vseg "base".
     293 * When the new window buffer is larger than the existing one, it is 0 filled.
     294 * It can be called by any thread running in any cluster.
     295 *
     296 * Implementation note:
     297 * 1.  it takes the lock protecting windows in write mode,
     298 * 2.  it gives the modified window the lowest priority,
     299 * 3.  it set the "hidden" flag in window descriptor,
     300 * 4.  it refresh the FBF for the current window,
     301 * 5.  it set the new size in the window descriptor,
     302 * 6.  it resizes the associated vseg if required,
     303 * 7.  if fill the window buffer extension with 0 if required,
     304 * 8.  it gives the modified window the highest priority,
     305 * 9.  it reset the "hidden" flag in window descriptor,
     306 * 10. it refresh the FBF for the new window,
     307 * 11. it releases the lock protecting windows,
     308 * It does not call directly the FBF driver.
     309 ******************************************************************************************
     310 * @ wid       : [in] window index in window_tbl[].
     311 * @ width     : [in] new number of pixels per line.
     312 * @ height    : [in] new number of lines.
     313 * @ returns 0 if success / returns -1 if illegal arguments.
     314 *****************************************************************************************/
     315error_t dev_fbf_resize_window( uint32_t wid,
     316                               uint32_t width,
     317                               uint32_t height );
     318
     319/******************************************************************************************
     320 * This function implements the fbf_refresh_window() syscall.
     321 * It allows an owner process to signal the windows manager that some lines of a window
     322 * identified by the <wid>, <line_min>, and <line_max> argument have been modified, and
     323 * must be refreshed in the FBF. It scans all the registered FBF windows to respect the
     324 * overlap order defined by the windows xlist.
     325 * It can be called by any thread running in any cluster.
     326 *
     327 * Implementation note:
     328 * 1. it takes the lock protecting windows in read mode,
     329 * 2. it refresh the FBF,
     330 * 3. it releases the lock protecting windows,
     331 * It does not call directly the FBF driver.
     332 ******************************************************************************************
     333 * @ wid        : [in] window index in window_tbl[]
     334 * @ line_first : [in] first line index in window.
     335 * @ line_last  : [in] last line index (excluded).
     336 * @ returns 0 if success / returns -1 if wid not registered.
     337 *****************************************************************************************/
     338error_t dev_fbf_refresh_window( uint32_t wid,
     339                                uint32_t line_first,
     340                                uint32_t line_last );
     341
     342/******************************************************************************************
     343 * WARNING : This function is deprecated ( january 2020 [AG] ). It was defined
     344 * to implement the fbf_read() and fbf_write() deprecated syscalls.
     345 *
     346 * It  moves <length> bytes between the frame buffer, starting from pixel defined
     347 * by the <offset> argument, and an user buffer defined by the <user_buffer> argument.
     348 * The transfer direction are defined by the <is_write> argument.
     349 * An error is returned when <offset> + <npixels> is larger than the FBF size.
    126350 * The request is registered in the client thread descriptor, but the client thread is
    127351 * not descheduled, and calls directly the FBF driver.
    128  ******************************************************************************************
    129  * @ cmd_type    : FBF_READ / FBF_WRITE / FBF_SYNC_READ / FBF_SYN_WRITE.
    130  * @ user_buffer : pointer on memory buffer in user space.
    131  * @ length      : number of bytes.
    132  * @ offset      : first byte in frame buffer.   
    133  * @ returns 0 if success / returns EINVAL if error.
    134  *****************************************************************************************/
    135 error_t dev_fbf_move_data( uint32_t   cmd_type,
     352 * It can be called by a client thread running in any cluster.
     353 ******************************************************************************************
     354 * @ is_write    : [in] write FBF weh true / read FBF when false
     355 * @ user_buffer : [in] pointer on memory buffer in user space.
     356 * @ npixels     : [in] number of bytes.
     357 * @ offset      : [in] first byte in frame buffer.   
     358 * @ returns 0 if success / returns -1 if error.
     359 *****************************************************************************************/
     360error_t dev_fbf_move_data( bool_t     is_write,
    136361                           void     * user_buffer,
    137                            uint32_t   length,
     362                           uint32_t   npixels,
    138363                           uint32_t   offset );
    139364
  • trunk/kernel/devices/dev_ioc.c

    r647 r657  
    22 * dev_ioc.c - IOC (Block Device Controler) generic device API implementation.
    33 *
    4  * Author  Alain Greiner    (2016,2017,2018,2019)
     4 * Author  Alain Greiner    (2016,2017,2018,2019,2020)
    55 *
    66 * Copyright (c) UPMC Sorbonne Universites
     
    3737extern chdev_directory_t  chdev_dir;     // allocated in kernel_init.c
    3838
    39 ////////////////////////////////////////
    40 char * dev_ioc_cmd_str( cmd_type_t cmd )
     39////////////////////////////////////////////
     40char * dev_ioc_cmd_str( ioc_cmd_type_t cmd )
    4141{
    4242    if     ( cmd == IOC_READ       )  return "READ";
     
    9191}  // end dev_ioc_init()
    9292
    93 ///////////////////////////////////////////////
    94 error_t dev_ioc_move_data( uint32_t   cmd_type,
     93////////////////////////////////////////////////////////////////////////////////////
     94// This static function executes an asynchronous SYNC_READ or SYNC_WRITE request.
     95// thread in the IOC device waiting queue, activates the server thread, blocks on
     96// the THREAD_BLOCKED_IO condition and deschedules.
     97// The clent is re-activated by the server thread after IO operation completion.
     98////////////////////////////////////////////////////////////////////////////////////
     99static error_t dev_ioc_move( uint32_t   cmd_type,
     100                             xptr_t     buffer_xp,
     101                             uint32_t   lba,
     102                             uint32_t   count )
     103{
     104    thread_t * this = CURRENT_THREAD;              // pointer on client thread
     105
     106    // get extended pointer on IOC chdev descriptor
     107    xptr_t      ioc_xp  = chdev_dir.ioc[0];
     108
     109// check dev_xp
     110assert( (ioc_xp != XPTR_NULL) , "undefined IOC chdev descriptor" );
     111
     112    // register command in client thread 
     113    this->ioc_cmd.dev_xp    = ioc_xp;
     114    this->ioc_cmd.type      = cmd_type;
     115    this->ioc_cmd.buf_xp    = buffer_xp;
     116    this->ioc_cmd.lba       = lba;
     117    this->ioc_cmd.count     = count;
     118
     119    // register client thread in IOC queue, blocks and deschedules
     120    chdev_register_command( ioc_xp );
     121
     122    // return I/O operation status
     123    return this->ioc_cmd.error;
     124
     125}  // end dev_ioc_move()
     126
     127////////////////////////////////////////////////////////////////////////////////////
     128// This static function executes a synchronous READ or WRITE request.
     129// It register the command in the client thread descriptor, and calls directly
     130// the driver cmd function.
     131////////////////////////////////////////////////////////////////////////////////////
     132error_t dev_ioc_sync_move( uint32_t   cmd_type,
    95133                           xptr_t     buffer_xp,
    96134                           uint32_t   lba,
     
    98136{
    99137    thread_t * this = CURRENT_THREAD;              // pointer on client thread
    100 
    101 #if ( DEBUG_DEV_IOC_RX  || DEBUG_DEV_IOC_TX )
    102 uint32_t   cycle = (uint32_t)hal_get_cycles();
    103 #endif
    104 
    105     // software L2/L3 cache coherence for memory buffer
    106     if( chdev_dir.iob )
    107     {
    108         if( (cmd_type == IOC_SYNC_READ) || (cmd_type == IOC_READ) )
    109         {
    110             dev_mmc_inval( buffer_xp , count<<9 );
    111         }
    112         else  // (cmd_type == IOC_SYNC_WRITE) or (cmd_type == IOC_WRITE)
    113         {
    114             dev_mmc_sync ( buffer_xp , count<<9 );
    115         }
    116     }
    117138
    118139    // get extended pointer on IOC chdev descriptor
     
    129150    this->ioc_cmd.count     = count;
    130151
    131     // for a synchronous acces, the driver is directly called by the client thread
    132     if( (cmd_type == IOC_SYNC_READ) || (cmd_type == IOC_SYNC_WRITE) )
    133     {
    134 
    135 #if DEBUG_DEV_IOC_RX
    136 uint32_t   cycle = (uint32_t)hal_get_cycles();
    137 if( (DEBUG_DEV_IOC_RX < cycle) && (cmd_type == IOC_SYNC_READ) )
    138 printk("\n[%s] thread[%x,%x] enters for SYNC_READ / lba  %x / buffer[%x,%x] / cycle %d\n",
    139 __FUNCTION__ , this->process->pid, this->trdid, lba,
    140 GET_CXY(buffer_xp), GET_PTR(buffer_xp), cycle );
    141 #endif
    142 
    143 #if DEBUG_DEV_IOC_TX
    144 uint32_t   cycle = (uint32_t)hal_get_cycles();
    145 if( (DEBUG_DEV_IOC_TX < cycle) && (cmd_type == IOC_SYNC_WRITE) )
    146 printk("\n[%s] thread[%x,%x] enters for SYNC_WRITE / lba  %x / buffer[%x,%x] / cycle %d\n",
    147 __FUNCTION__ , this->process->pid, this->trdid, lba,
    148 GET_CXY(buffer_xp), GET_PTR(buffer_xp), cycle );
    149 #endif
    150         // get driver command function
    151         cxy_t       ioc_cxy = GET_CXY( ioc_xp );
    152         chdev_t   * ioc_ptr = GET_PTR( ioc_xp );
    153         dev_cmd_t * cmd = (dev_cmd_t *)hal_remote_lpt( XPTR( ioc_cxy , &ioc_ptr->cmd ) );
    154 
    155         // call driver function
    156         cmd( XPTR( local_cxy , this ) );
    157 
    158 #if DEBUG_DEV_IOC_RX
    159 if( (DEBUG_DEV_IOC_RX < cycle) && (cmd_type == IOC_SYNC_READ) )
    160 printk("\n[%s] thread[%x,%x] resumes for IOC_SYNC_READ\n",
    161 __FUNCTION__, this->process->pid , this->trdid )
    162 #endif
    163 
    164 #if DEBUG_DEV_IOC_TX
    165 if( (DEBUG_DEV_IOC_RX < cycle) && (cmd_type == IOC_SYNC_WRITE) )
    166 printk("\n[%s] thread[%x,%x] resumes for IOC_SYNC_WRITE\n",
    167 __FUNCTION__, this->process->pid , this->trdid )
    168 #endif
    169 
    170     }
    171     // for an asynchronous access, the client thread registers in the chdev waiting queue,
    172     // activates server thread, blocks on THREAD_BLOCKED_IO and deschedules.
    173     // It is re-activated by the server thread after IO operation completion.
    174     else  // (cmd_type == IOC_READ) || (cmd_type == IOC_WRITE)
    175     {
    176 
    177 #if DEBUG_DEV_IOC_RX
    178 uint32_t   cycle = (uint32_t)hal_get_cycles();
    179 if( (DEBUG_DEV_IOC_RX < cycle) && (cmd_type == IOC_READ) )
    180 printk("\n[%s] thread[%x,%x] enters for READ / lba  %x / buffer[%x,%x] / cycle %d\n",
    181 __FUNCTION__ , this->process->pid, this->trdid, lba,
    182 GET_CXY(buffer_xp), GET_PTR(buffer_xp), cycle );
    183 #endif
    184 
    185 #if DEBUG_DEV_IOC_TX
    186 uint32_t   cycle = (uint32_t)hal_get_cycles();
    187 if( (DEBUG_DEV_IOC_TX < cycle) && (cmd_type == IOC_WRITE) )
    188 printk("\n[%s] thread[%x,%x] enters for WRITE / lba  %x / buffer[%x,%x] / cycle %d\n",
    189 __FUNCTION__ , this->process->pid, this->trdid, lba,
    190 GET_CXY(buffer_xp), GET_PTR(buffer_xp), cycle );
    191 #endif
    192         chdev_register_command( ioc_xp );
    193 
    194 #if(DEBUG_DEV_IOC_RX )
    195 if( (DEBUG_DEV_IOC_RX < cycle) && (cmd_type == IOC_READ) )
    196 printk("\n[%s] thread[%x,%x] resumes for IOC_READ\n",
    197 __FUNCTION__, this->process->pid , this->trdid )
    198 #endif
    199 
    200 #if(DEBUG_DEV_IOC_TX & 1)
    201 if( (DEBUG_DEV_IOC_RX < cycle) && (cmd_type == IOC_WRITE) )
    202 printk("\n[%s] thread[%x,%x] resumes for IOC_WRITE\n",
    203 __FUNCTION__, this->process->pid , this->trdid )
    204 #endif
    205 
    206     }
     152    // get driver command function
     153    cxy_t       ioc_cxy = GET_CXY( ioc_xp );
     154    chdev_t   * ioc_ptr = GET_PTR( ioc_xp );
     155    dev_cmd_t * cmd = (dev_cmd_t *)hal_remote_lpt( XPTR( ioc_cxy , &ioc_ptr->cmd ) );
     156
     157    // call driver function whithout blocking & descheduling
     158    cmd( XPTR( local_cxy , this ) );
    207159
    208160    // return I/O operation status
    209161    return this->ioc_cmd.error;
    210162
    211 }  // end dev_ioc_move_data()
    212 
    213 
     163}  // end dev_ioc_sync_move()
     164
     165///////////////////////////////////////////
     166error_t dev_ioc_read( xptr_t     buffer_xp,
     167                      uint32_t   lba,
     168                      uint32_t   count )
     169{
     170
     171#if DEBUG_DEV_IOC_RX
     172thread_t * this  = CURRENT_THREAD;
     173uint32_t   cycle = (uint32_t)hal_get_cycles();
     174if( DEBUG_DEV_IOC_RX < cycle )
     175printk("\n[%s] thread[%x,%x] enters IOC_READ / lba  %x / buffer[%x,%x] / cycle %d\n",
     176__FUNCTION__, this->process->pid, this->trdid, lba,
     177GET_CXY(buffer_xp), GET_PTR(buffer_xp), cycle );
     178#endif
     179
     180    // software L2/L3 cache coherence for memory buffer
     181    if( chdev_dir.iob ) dev_mmc_inval( buffer_xp , count<<9 );
     182
     183    // request an asynchronous transfer
     184    error_t error = dev_ioc_move( IOC_READ,
     185                                  buffer_xp,
     186                                  lba,
     187                                  count );
     188#if(DEBUG_DEV_IOC_RX & 1)
     189cycle = (uint32_t)hal_get_cycles();
     190if( DEBUG_DEV_IOC_RX < cycle )
     191printk("\n[%s] thread[%x,%x] exit IOC_READ / cycle %d\n",
     192__FUNCTION__, this->process->pid , this->trdid , cycle );
     193#endif
     194
     195    return error;
     196
     197}  // end dev_ioc_read()
     198
     199///////////////////////////////////////////
     200error_t dev_ioc_write( xptr_t     buffer_xp,
     201                       uint32_t   lba,
     202                       uint32_t   count )
     203{
     204
     205#if DEBUG_DEV_IOC_TX
     206thread_t * this  = CURRENT_THREAD;
     207uint32_t   cycle = (uint32_t)hal_get_cycles();
     208if( DEBUG_DEV_IOC_TX < cycle )
     209printk("\n[%s] thread[%x,%x] enters IOC_WRITE / lba  %x / buffer[%x,%x] / cycle %d\n",
     210__FUNCTION__, this->process->pid, this->trdid, lba,
     211GET_CXY(buffer_xp), GET_PTR(buffer_xp), cycle );
     212#endif
     213
     214    // software L2/L3 cache coherence for memory buffer
     215    if( chdev_dir.iob ) dev_mmc_sync ( buffer_xp , count<<9 );
     216
     217    // request a blocking, but asynchronous, transfer
     218    error_t error = dev_ioc_move( IOC_WRITE,
     219                          buffer_xp,
     220                          lba,
     221                          count );
     222#if(DEBUG_DEV_IOC_TX & 1)
     223cycle = (uint32_t)hal_get_cycles();
     224if( DEBUG_DEV_IOC_TX < cycle )
     225printk("\n[%s] thread[%x,%x] exit IOC_WRITE / cycle %d\n",
     226__FUNCTION__, this->process->pid , this->trdid , cycle );
     227#endif
     228
     229    return error;
     230
     231}  // end dev_ioc_write()
     232
     233
     234///////////////////////////////////////////
     235error_t dev_ioc_sync_read( xptr_t     buffer_xp,
     236                           uint32_t   lba,
     237                           uint32_t   count )
     238{
     239
     240#if DEBUG_DEV_IOC_RX
     241thread_t * this  = CURRENT_THREAD;
     242uint32_t   cycle = (uint32_t)hal_get_cycles();
     243if( DEBUG_DEV_IOC_RX < cycle )
     244printk("\n[%s] thread[%x,%x] enters IOC_SYNC_READ / lba  %x / buffer[%x,%x] / cycle %d\n",
     245__FUNCTION__, this->process->pid, this->trdid, lba,
     246GET_CXY(buffer_xp), GET_PTR(buffer_xp), cycle );
     247#endif
     248
     249    // software L2/L3 cache coherence for memory buffer
     250    if( chdev_dir.iob ) dev_mmc_inval( buffer_xp , count<<9 );
     251
     252    // request an asynchronous transfer
     253    error_t error = dev_ioc_sync_move( IOC_SYNC_READ,
     254                                       buffer_xp,
     255                                       lba,
     256                                       count );
     257#if(DEBUG_DEV_IOC_RX & 1)
     258cycle = (uint32_t)hal_get_cycles();
     259if( DEBUG_DEV_IOC_RX < cycle )
     260printk("\n[%s] thread[%x,%x] exit IOC_SYNC_READ / cycle %d\n",
     261__FUNCTION__, this->process->pid , this->trdid , cycle );
     262#endif
     263
     264    return error;
     265
     266}  // end dev_ioc_sync_read() 
     267
     268/////////////////////////////////////////////////
     269error_t dev_ioc_sync_write( xptr_t     buffer_xp,
     270                            uint32_t   lba,
     271                            uint32_t   count )
     272{
     273
     274#if DEBUG_DEV_IOC_TX
     275thread_t * this  = CURRENT_THREAD;
     276uint32_t   cycle = (uint32_t)hal_get_cycles();
     277if( DEBUG_DEV_IOC_TX < cycle )
     278printk("\n[%s] thread[%x,%x] enters IOC_SYNC_WRITE / lba  %x / buffer[%x,%x] / cycle %d\n",
     279__FUNCTION__, this->process->pid, this->trdid, lba,
     280GET_CXY(buffer_xp), GET_PTR(buffer_xp), cycle );
     281#endif
     282
     283    // software L2/L3 cache coherence for memory buffer
     284    if( chdev_dir.iob ) dev_mmc_sync ( buffer_xp , count<<9 );
     285
     286    // request a blocking, but asynchronous, transfer
     287    error_t error = dev_ioc_sync_move( IOC_SYNC_WRITE,
     288                                       buffer_xp,
     289                                       lba,
     290                                       count );
     291#if(DEBUG_DEV_IOC_TX & 1)
     292cycle = (uint32_t)hal_get_cycles();
     293if( DEBUG_DEV_IOC_TX < cycle )
     294printk("\n[%s] thread[%x,%x] exit IOC_SYNC_WRITE / cycle %d\n",
     295__FUNCTION__, this->process->pid , this->trdid , cycle );
     296#endif
     297
     298    return error;
     299
     300}  // end dev_ioc_sync_write()
     301
     302
  • trunk/kernel/devices/dev_ioc.h

    r647 r657  
    22 * dev_ioc.h - IOC (Block Device Controler) generic device API definition.
    33 *
    4  * Author  Alain Greiner    (2016,2017,2018,2019)
     4 * Author  Alain Greiner    (2016,2017,2018,2019,2020)
    55 *
    66 * Copyright (c) UPMC Sorbonne Universites
     
    4545 * - SYNC_WRITE : move blocks from memory to device, with a busy waiting policy.
    4646 *
    47  * For the he READ or WRITE operations, the client thread is descheduled, and the work
     47 * For the READ or WRITE operations, the client thread is descheduled, and the work
    4848 * is done by the server thread associated to the IOC device:
    4949 * The client thread calls the dev_ioc_move_data() kernel functions that (i) registers
     
    9393
    9494/******************************************************************************************
    95  * This defines the (implementation independant)  command passed to the driver.
     95 * This structure defines the IOC command for all drivers implementing the IOC device.
    9696 *****************************************************************************************/
    9797
     
    103103    IOC_SYNC_WRITE = 3,
    104104}
    105 cmd_type_t;
     105ioc_cmd_type_t;
    106106
    107107typedef struct ioc_command_s
     
    111111    uint32_t    lba;        /*! first block index                                        */
    112112    uint32_t    count;      /*! number of blocks                                         */
    113     xptr_t      buf_xp;     /*! extended pointer on memory buffer                        */
     113    xptr_t      buf_xp;     /*! extended pointer on kernel memory buffer                 */
    114114    uint32_t    error;      /*! operation status (0 if success)                          */
    115115}
     
    122122 * @ return pointer on string.
    123123 *****************************************************************************************/
    124 char * dev_ioc_cmd_str( cmd_type_t cmd );
     124char * dev_ioc_cmd_str( ioc_cmd_type_t cmd );
    125125
    126126/******************************************************************************************
     
    138138
    139139/******************************************************************************************
    140  * This blocking function moves <count> contiguous blocks of data between the block device
    141  * starting from block defined by the <lba> argument and a kernel memory buffer, defined
    142  * by the <buffer_xp> argument. The transfer direction and mode are defined by the
    143  * <cmd_type> argument. The request is always registered in the calling thread descriptor.
    144  * - In synchronous mode, the calling thread is not descheduled, and directly calls the
    145  *   IOC driver, polling the IOC status to detect transfer completion.
    146  * - In asynchronous mode, the calling thread blocks and deschedules, and the IOC driver
    147  *   is called by the server thread associated to the IOC device.
    148  ******************************************************************************************
    149  * @ cmd_type  : IOC_READ / IOC_WRITE / IOC_SYNC_READ / IOC_SYN_WRITE.
    150  * @ buffer_xp : extended pointer on kernel buffer in memory (must be block aligned).
    151  * @ lba       : first block index on device.
    152  * @ count     : number of blocks to transfer.
    153  * @ returns 0 if success / returns -1 if error.
    154  *****************************************************************************************/
    155 error_t dev_ioc_move_data( uint32_t  cmd_type,
    156                            xptr_t    buffer_xp,
     140 * This blocking function register an asynchronous READ request : move <count> contiguous
     141 * blocks from the block device, starting from block defined by the <lba> argument, to a
     142 * kernel buffer defined by the <buffer_xp> argument.
     143 * It register the request in the client thread descriptor, it register the client thread
     144 * in the IOC device queue, it blocks on the THREAD_BLOCKED_IO condition, and deschedules.
     145 * It will be reactivated by the DEV server thread when the transfer is completed.
     146 * It can be executed by a thread running in any cluster.
     147 ******************************************************************************************
     148 * @ buffer_xp : extended pointer on kernel buffer in memory (must be block aligned).
     149 * @ lba       : first block index on device.
     150 * @ count     : number of blocks to transfer.
     151 * @ returns 0 if success / returns -1 if error.
     152 *****************************************************************************************/
     153error_t dev_ioc_read( xptr_t    buffer_xp,
     154                      uint32_t  lba,
     155                      uint32_t  count );
     156
     157/******************************************************************************************
     158 * This blocking function register an asynchronous WRITE request : move <count> contiguous
     159 * blocks from a kernel buffer defined by the <buffer_xp> argument to the block device,
     160 * starting from block defined by the <lba> argument.
     161 * It register the request in the client thread descriptor, it register the client thread
     162 * in the IOC device queue, it blocks on the THREAD_BLOCKED_IO condition, and deschedules.
     163 * It will be reactivated by the DEV server thread when the transfer is completed.
     164 * It can be executed by a thread running in any cluster.
     165 ******************************************************************************************
     166 * @ buffer_xp : extended pointer on kernel buffer in memory (must be block aligned).
     167 * @ lba       : first block index on device.
     168 * @ count     : number of blocks to transfer.
     169 * @ returns 0 if success / returns -1 if error.
     170 *****************************************************************************************/
     171error_t dev_ioc_write( xptr_t    buffer_xp,
     172                       uint32_t  lba,
     173                       uint32_t  count );
     174
     175/******************************************************************************************
     176 * This blocking function executes a synchronous SYNC_READ request : it moves <count>
     177 * contiguous blocks of data from the block device, starting from block defined by the
     178 * <lba> argument to a kernel memory buffer, defined by the <buffer_xp> argument.
     179 * The request is registered in the calling thread descriptor, but the client thread calls
     180 * directly the driver cmd function, that is also a blocking function returning only
     181 * when the transfer is completed.
     182 * It can be executed by a thread running in any cluster.
     183 ******************************************************************************************
     184 * @ buffer_xp : extended pointer on kernel buffer in memory (must be block aligned).
     185 * @ lba       : first block index on device.
     186 * @ count     : number of blocks to transfer.
     187 * @ returns 0 if success / returns -1 if error.
     188 *****************************************************************************************/
     189error_t dev_ioc_sync_read( xptr_t    buffer_xp,
    157190                           uint32_t  lba,
    158191                           uint32_t  count );
    159192
     193/******************************************************************************************
     194 * This blocking function executes a synchronous SYNC_WRITE request : it moves <count>
     195 * contiguous blocks of data from a kernel memory buffer, defined by the <buffer_xp>
     196 * argument to the block device, starting from block defined by the <lba> argument.
     197 * The request is registered in the calling thread descriptor, but the client thread calls
     198 * directly the driver cmd() function, that is also a blocking function returning only
     199 * when the transfer is completed.
     200 * It can be executed by a thread running in any cluster.
     201 ******************************************************************************************
     202 * @ buffer_xp : extended pointer on kernel buffer in memory (must be block aligned).
     203 * @ lba       : first block index on device.
     204 * @ count     : number of blocks to transfer.
     205 * @ returns 0 if success / returns -1 if error.
     206 *****************************************************************************************/
     207error_t dev_ioc_sync_write( xptr_t    buffer_xp,
     208                            uint32_t  lba,
     209                            uint32_t  count );
     210
    160211#endif  /* _DEV_IOC_H */
  • trunk/kernel/devices/dev_mmc.c

    r647 r657  
    22 * dev_mmc.c - MMC (Memory Cache Controler) generic device API implementation.
    33 *
    4  * Author  Alain Greiner    (2016,2017,2018)
     4 * Author  Alain Greiner    (2016,2017,2018,2019,2020)
    55 *
    66 * Copyright (c) UPMC Sorbonne Universites
     
    176176
    177177/////////////////////////////////////////
    178 error_t dev_mmc_set_error( cxy_t     cxy,
     178error_t dev_mmc_error_set( cxy_t     cxy,
    179179                           uint32_t  index,
    180180                           uint32_t  wdata )
     
    185185    // store command arguments in thread descriptor
    186186    this->mmc_cmd.dev_xp    = chdev_dir.mmc[cxy];
    187     this->mmc_cmd.type      = MMC_SET_ERROR;
     187    this->mmc_cmd.type      = MMC_ERROR_SET;
    188188    this->mmc_cmd.reg_index = index;
    189189    this->mmc_cmd.reg_ptr   = &wdata;
     
    194194                       
    195195//////////////////////////////////////////
    196 error_t dev_mmc_get_error( cxy_t      cxy,
     196error_t dev_mmc_error_get( cxy_t      cxy,
    197197                           uint32_t   index,
    198198                           uint32_t * rdata )
     
    203203    // store command arguments in thread descriptor
    204204    this->mmc_cmd.dev_xp    = chdev_dir.mmc[cxy];
    205     this->mmc_cmd.type      = MMC_GET_ERROR;
     205    this->mmc_cmd.type      = MMC_ERROR_GET;
    206206    this->mmc_cmd.reg_index = index;
    207207    this->mmc_cmd.reg_ptr   = rdata;
     
    210210    return dev_mmc_access( this );
    211211}
    212                        
    213 ////////////////////////////////////////////////////
    214 error_t dev_mmc_get_instrumentation( cxy_t      cxy,
    215                                      uint32_t   index,
    216                                      uint32_t * rdata )
     212
     213//////////////////////////////////////////
     214error_t dev_mmc_instr_get( cxy_t      cxy,
     215                           uint32_t   index,
     216                           uint32_t * rdata )
    217217{
    218218    // get calling thread local pointer
     
    221221    // store command arguments in thread descriptor
    222222    this->mmc_cmd.dev_xp    = chdev_dir.mmc[cxy];
    223     this->mmc_cmd.type      = MMC_GET_INSTRU;
     223    this->mmc_cmd.type      = MMC_INSTR_GET;
    224224    this->mmc_cmd.reg_index = index;
    225225    this->mmc_cmd.reg_ptr   = rdata;
     
    228228    return dev_mmc_access( this );
    229229}
    230 
  • trunk/kernel/devices/dev_mmc.h

    r565 r657  
    22 * dev_mmc.h - MMC (Generic L2 cache controller) device API definition.
    33 *
    4  * Authors   Alain Greiner  (2016,2017,2018)
     4 * Authors   Alain Greiner  (2016,2017,2018,2019,2020)
    55 *
    66 * Copyright (c) UPMC Sorbonne Universites
     
    3434 * acting in all clusters containing a level 2 cache controller.
    3535 *
    36  * It supports  five command types:
     36 * It supports three different services:
     37 * 1) L2/L3 software cache-coherence operations.
     38 * 2) error reporting for architecture specific addressing error.
     39 * 3) architecture specific intrumentation registers access.
     40 *
     41 * It supports therefore five command types:
    3742 * - MMC_CC_INVAL   : invalidate all cache lines covering a given buffer in L2 cache.
    3843 * - MMC_CC_SYNC    : synchronize all cache lines covering a given buffer to L3 cache.
    39  * - MMC_GET_ERROR  : return content of a given error signaling register.
    40  * - MMC_SET_ERROR  : set a given error signaling register.
    41  * - MMC_GET_INSTRU : return content of a given instrumentation register.
     44 * - MMC_ERROR_GET  : return content of a given error signaling register.
     45 * - MMC_ERROR_SET  : set a given error signaling register.
     46 * - MMC_INSTR_GET : return content of a given instrumentation register.
    4247 *
    4348 * As all L2 caches can be accessed by any thread running in any cluster, a calling
     
    7378    MMC_CC_INVAL   = 0,
    7479    MMC_CC_SYNC    = 1,
    75     MMC_GET_ERROR  = 2,
    76     MMC_SET_ERROR  = 3,
    77     MMC_GET_INSTRU = 4,
     80    MMC_ERROR_GET  = 2,
     81    MMC_ERROR_SET  = 3,
     82    MMC_INSTR_GET = 4,
    7883};
    7984
     
    126131                       
    127132/*****************************************************************************************
    128  * This function set a value in one error signaling MMC register.
     133 * This function set a value in one (architecture specific) MMC_ERROR register.
    129134 * It can be executed by any thread in any cluster, because it uses remote accesses
    130135 * to access the L2 cache instrumentation interface in any cluster.
     
    135140 * @ return 0 if success / return EINVAL if failure
    136141 ****************************************************************************************/
    137 error_t dev_mmc_set_error( cxy_t    cxy,
     142error_t dev_mmc_error_set( cxy_t    cxy,
    138143                           uint32_t index,
    139144                           uint32_t wdata );
    140145             
    141146/*****************************************************************************************
    142  * This function returns the value contained in one error signaling MMC register.
    143  * It can be executed by any thread in any cluster, because it uses remote accesses
    144  * to access the L2 cache instrumentation interface in any cluster.
     147 * This function returns the value contained in one (architecture specific) MMC_ERROR
     148 * register. It can be executed by any thread in any cluster, because it uses remote
     149 * accesses to access the L2 cache instrumentation interface in any cluster.
    145150 *****************************************************************************************
    146151 * @ cxy     : MMC cluster identifier.
     
    149154 * @ return 0 if success / return EINVAL if failure
    150155 ****************************************************************************************/
    151 error_t dev_mmc_get_error( cxy_t      cxy,
     156error_t dev_mmc_error_get( cxy_t      cxy,
    152157                           uint32_t   index,
    153158                           uint32_t * rdata );
    154159             
    155 
    156160/*****************************************************************************************
    157  * This function returns the value contained in one instrumentation MMC register.
    158  * It can be executed by any thread in any cluster, because it uses remote accesses
    159  * to access the L2 cache configuration interface in any cluster.
     161 * This function returns the value contained in one (architecture specific) MMC_INSTR
     162 * register. It can be executed by any thread in any cluster, because it uses remote
     163 * accesses to access the L2 cache instrumentation interface in any cluster.
    160164 *****************************************************************************************
    161165 * @ cxy     : MMC cluster identifier.
    162  * @ index   : instrumentation register index in MMC peripheral.
     166 * @ index   : error register index in MMC peripheral.
    163167 * @ rdata   : local pointer on buffer for returned value.
    164168 * @ return 0 if success / return EINVAL if failure
    165169 ****************************************************************************************/
    166 error_t dev_mmc_get_instrumentation( cxy_t      cxy,
    167                                      uint32_t   index,
    168                                      uint32_t * rdata );
    169 
     170error_t dev_mmc_instr_get( cxy_t      cxy,
     171                           uint32_t   index,
     172                           uint32_t * rdata );
     173             
    170174#endif  /* _DEV_MMC_H_ */
  • trunk/kernel/devices/dev_nic.c

    r647 r657  
    22 * dev_nic.c - NIC (Network Controler) generic device API implementation.
    33 *
    4  * Author  Alain Greiner    (2016,2017,2018,2019)
     4 * Author  Alain Greiner    (2016,2017,2018,2019,2020)
    55 *
    66 * Copyright (c) UPMC Sorbonne Universites
     
    2424#include <hal_kernel_types.h>
    2525#include <hal_special.h>
     26#include <hal_uspace.h>
     27#include <remote_buf.h>
    2628#include <printk.h>
    2729#include <chdev.h>
    2830#include <thread.h>
     31#include <socket.h>
    2932#include <hal_drivers.h>
    3033#include <dev_nic.h>
     34#include <vfs.h>
     35#include <shared_socket.h>
    3136
    3237/////////////////////////////////////////////////////////////////////////////////////////
    33 // Extern global variables
     38//                 Extern global variables
    3439/////////////////////////////////////////////////////////////////////////////////////////
    3540
    3641extern chdev_directory_t  chdev_dir;         // allocated in kernel_init.c
     42
     43////////////////////////////////////////////////////////////////////////////////////////////
     44// This static function is used by the dev_nic_rx_handle_tcp() & dev_nic_tx_handle_tcp()
     45// functions to check acceptability of a given sequence number. It returns true when
     46// the <seq> argument is contained in a wrap-around window defined by the <min> and <max>
     47// arguments. The window wrap-around when (min > max).
     48////////////////////////////////////////////////////////////////////////////////////////////
     49// @ seq   : [in] value to be checked.
     50// @ min   : [in] first  base.
     51// @ max   : [in] window size.
     52////////////////////////////////////////////////////////////////////////////////////////////
     53static inline bool_t is_in_window( uint32_t seq,
     54                                   uint32_t min,
     55                                   uint32_t max )
     56{
     57    if( max >= min )    // no wrap_around => only one window [min,max]
     58    {
     59        return( (seq >= min) && (seq <= max) );
     60    }
     61    else                // window wrap-around => two windows [min,0xFFFFFFFF] and [0,max]
     62    {
     63        return( (seq <= max) || (seq >= min) );
     64    }
     65
     66
     67////////////////////////////////////////////////////////////////////////////////////////////
     68// this static function compute a channel index in range [0,nic_channelx[ from
     69// a remote IP address and remote port.
     70// TODO this function should be provided by the NIC driver.
     71////////////////////////////////////////////////////////////////////////////////////////////
     72// @ addr     : [in] IP address.
     73// @ port     : [in] TCP/UDP port.
     74////////////////////////////////////////////////////////////////////////////////////////////
     75static inline uint32_t dev_nic_channel_index( uint32_t addr,
     76                                              uint16_t port )
     77{
     78    // get number of NIC channels
     79    uint32_t nic_channels = LOCAL_CLUSTER->nb_nic_channels;
     80 
     81    // compute NIC channel index
     82    return ( ((addr     ) & 0xFF) ^
     83             ((addr > 8 ) & 0xFF) ^
     84             ((addr > 16) & 0xFF) ^
     85             ((addr > 24) & 0xFF) ^
     86             ((port     ) & 0xFF) ^
     87             ((port > 8 ) & 0xFF) ) % nic_channels;
     88}
     89
     90////////////////////////////////////////////////////////////////////////////////////////
     91// This static function computes the checksum for an IP packet header.
     92// The "checksum" field itself is not taken into account for this computation.
     93////////////////////////////////////////////////////////////////////////////////////////
     94// @ buffer      : [in] pointer on IP packet header (20 bytes)
     95// @ return the checksum value on 16 bits
     96////////////////////////////////////////////////////////////////////////////////////////
     97uint16_t dev_nic_ip_checksum( uint8_t  * buffer )
     98{
     99    uint32_t   i;           
     100    uint32_t   cs;      // 32 bits accumulator
     101    uint16_t * buf;     
     102   
     103    buf = (uint16_t *)buffer;
     104
     105    // compute checksum
     106    for( i = 0 , cs = 0 ; i < 10 ; i++ )
     107    {
     108        if( i != 5 )  cs += buf[i];
     109    }
     110
     111    // one's complement
     112    return ~cs;
     113}
     114
     115////////////////////////////////////////////////////////////////////////////////////////
     116// This static function computes the checksum for an UDP packet defined by
     117// the <buffer> and <size> arguments.
     118////////////////////////////////////////////////////////////////////////////////////////
     119// @ buffer      : [in] pointer on UDP packet base.
     120// @ size        : [in] number of bytes in this packet (including header).
     121// @ return the checksum value on 16 bits
     122////////////////////////////////////////////////////////////////////////////////////////
     123uint16_t dev_nic_udp_checksum( uint8_t  * buffer,
     124                               uint32_t   size )
     125{
     126    uint32_t   i;           
     127    uint32_t   carry;
     128    uint32_t   cs;      // 32 bits accumulator
     129    uint16_t * buf;     
     130    uint32_t   max;     // number of uint16_t in packet
     131   
     132    // compute max & buf
     133    buf = (uint16_t *)buffer;
     134    max = size >> 1;
     135
     136    // extend buffer[] if required
     137    if( size & 1 )
     138    {
     139        max++;
     140        buffer[size] = 0;
     141    }
     142
     143    // compute checksum for UDP packet
     144    for( i = 0 , cs = 0 ; i < size ; i++ )  cs += buf[i];
     145
     146    // handle carry
     147    carry = (cs >> 16);
     148    if( carry )
     149    {
     150        cs += carry;
     151        carry = (cs >> 16);
     152        if( carry ) cs += carry;
     153    }
     154
     155    // one's complement
     156    return ~cs;
     157}
     158
     159////////////////////////////////////////////////////////////////////////////////////////
     160// This static function computes the checksum for a TCP segment defined by
     161// the <buffer> and <size> arguments.
     162// It includes the pseudo header defined by the <src_ip_addr>, <dst_ip_addr>,
     163// <size> arguments, and by the TCP_PROTOCOL code.
     164////////////////////////////////////////////////////////////////////////////////////////
     165// @ buffer      : [in] pointer on TCP segment base.
     166// @ size        : [in] number of bytes in this segment (including header).
     167// @ src_ip_addr : [in] source IP address (pseudo header)
     168// @ dst_ip_addr : [in] destination IP address (pseudo header)
     169// @ return the checksum value on 16 bits
     170////////////////////////////////////////////////////////////////////////////////////////
     171uint16_t dev_nic_tcp_checksum( uint8_t  * buffer,
     172                               uint32_t   size,
     173                               uint32_t   src_ip_addr,
     174                               uint32_t   dst_ip_addr )
     175{
     176    uint32_t   i;           
     177    uint32_t   carry;
     178    uint32_t   cs;      // 32 bits accumulator
     179    uint16_t * buf;
     180    uint32_t   max;     // number of uint16_t in segment
     181
     182    // compute max & buf
     183    buf = (uint16_t *)buffer;
     184    max = size >> 1;
     185
     186    // extend buffer[] if required
     187    if( size & 1 )
     188    {
     189        max++;
     190        buffer[size] = 0;
     191    }
     192
     193    // compute checksum for TCP segment
     194    for( i = 0 , cs = 0 ; i < size ; i++ )  cs += buf[i];
     195
     196    // complete checksum for pseudo-header
     197    cs += src_ip_addr;
     198    cs += dst_ip_addr;
     199    cs += PROTOCOL_TCP;
     200    cs += size;
     201
     202    // handle carry
     203    carry = (cs >> 16);
     204    if( carry )
     205    {
     206        cs += carry;
     207        carry = (cs >> 16);
     208        if( carry ) cs += carry;
     209    }
     210
     211    // one's complement
     212    return ~cs;
     213}
    37214
    38215//////////////////////////////////
     
    80257}  // end dev_nic_init()
    81258
     259
     260/////////////////////////////////////////////////////////////////////////////////////////
     261//                 Functions implementing the SOCKET related syscalls
     262/////////////////////////////////////////////////////////////////////////////////////////
     263
     264//////////////////////////////////////
     265int dev_nic_socket( uint32_t   domain,
     266                    uint32_t   type )
     267{
     268    uint32_t    fdid;
     269    socket_t  * socket;
     270    error_t     error;
     271
     272    // allocate memory for the file descriptor and for the socket
     273    error = socket_create( local_cxy,
     274                           domain,
     275                           type,
     276                           &socket,    // unused here
     277                           &fdid );
     278
     279    if( error ) return -1;
     280    return fdid;
     281}
     282
     283////////////////////////////////
     284int dev_nic_bind( uint32_t fdid,
     285                  uint32_t addr,
     286                  uint16_t port )
     287{
     288    vfs_inode_type_t    type;
     289    socket_t          * socket;
     290    uint32_t            state;
     291
     292    thread_t  * this    = CURRENT_THREAD;
     293    process_t * process = this->process;
     294
     295    // get pointers on file descriptor
     296    xptr_t       file_xp  = process_fd_get_xptr( process , fdid );
     297    vfs_file_t * file_ptr = GET_PTR( file_xp );
     298    cxy_t        file_cxy = GET_CXY( file_xp );
     299
     300    // check file_xp
     301    if( file_xp == XPTR_NULL )
     302    {
     303        printk("\n[ERROR] in %s : undefined fdid %d",
     304        __FUNCTION__, fdid );
     305        return -1;
     306    }
     307
     308    type   = hal_remote_l32( XPTR( file_cxy , &file_ptr->type ) );
     309    socket = hal_remote_lpt( XPTR( file_cxy , &file_ptr->socket ) );
     310
     311    // check file descriptor type
     312    if( type != INODE_TYPE_SOCK )
     313    {
     314        printk("\n[ERROR] in %s : illegal file type %s",
     315        __FUNCTION__, vfs_inode_type_str( type ) );
     316        return -1;
     317    }
     318
     319    state = (type == SOCK_STREAM) ? TCP_STATE_BOUND : UDP_STATE_BOUND;
     320
     321    // update the socket descriptor
     322    hal_remote_s32( XPTR( file_cxy , &socket->local_addr ) , addr );
     323    hal_remote_s32( XPTR( file_cxy , &socket->local_port ) , port );
     324    hal_remote_s32( XPTR( file_cxy , &socket->state      ) , state );
     325
     326    return 0;
     327
     328}  // end dev_nic_bind()
     329
     330//////////////////////////////////
     331int dev_nic_listen( uint32_t fdid,
     332                    uint32_t max_pending )
     333{
     334    xptr_t              file_xp;
     335    vfs_file_t        * file_ptr;
     336    cxy_t               file_cxy;
     337    vfs_inode_type_t    file_type;
     338    socket_t          * socket_ptr;
     339    uint32_t            socket_type;
     340    uint32_t            socket_state;
     341
     342    thread_t  * this    = CURRENT_THREAD;
     343    process_t * process = this->process;
     344
     345    if( max_pending != 0 )
     346    {
     347        printk("\n[WARNING] in %s : max_pending argument non supported\n",
     348        __FUNCTION__ );
     349    }
     350
     351    // get pointers on file descriptor
     352    file_xp  = process_fd_get_xptr( process , fdid );
     353    file_ptr = GET_PTR( file_xp );
     354    file_cxy = GET_CXY( file_xp );
     355
     356    // check file_xp
     357    if( file_xp == XPTR_NULL )
     358    {
     359        printk("\n[ERROR] in %s : undefined fdid %d",
     360        __FUNCTION__, fdid );
     361        return -1;
     362    }
     363
     364    file_type  = hal_remote_l32( XPTR( file_cxy , &file_ptr->type ) );
     365    socket_ptr = hal_remote_lpt( XPTR( file_cxy , &file_ptr->socket ) );
     366
     367    // check file descriptor type
     368    if( file_type != INODE_TYPE_SOCK )
     369    {
     370        printk("\n[ERROR] in %s : illegal file type %s",
     371        __FUNCTION__, vfs_inode_type_str(file_type) );
     372        return -1;
     373    }
     374
     375    // get socket type and state
     376    socket_type  = hal_remote_l32( XPTR( file_cxy , &socket_ptr->type ));
     377    socket_state = hal_remote_l32( XPTR( file_cxy , &socket_ptr->state ));
     378
     379    // check socket type
     380    if( socket_type != SOCK_STREAM )
     381    {
     382        printk("\n[ERROR] in %s : illegal socket type",
     383        __FUNCTION__ );
     384        return -1;
     385    }
     386   
     387    // check socket state
     388    if( socket_state != TCP_STATE_BOUND )
     389    {
     390        printk("\n[ERROR] in %s : illegal socket state %s",
     391        __FUNCTION__, socket_state_str(socket_state) );
     392        return -1;
     393    }
     394   
     395    // update socket.state
     396    hal_remote_s32( XPTR( file_cxy , &socket_ptr->state ) , TCP_STATE_LISTEN );
     397
     398    return 0;
     399
     400}  // end dev_nic_listen()
     401
    82402///////////////////////////////////
    83 error_t dev_nic_read( pkd_t * pkd )
    84 {
    85     error_t  error;
    86 
    87     // get pointers on this NIC-RX kernel thread
    88     thread_t * thread_ptr = CURRENT_THREAD;
    89     xptr_t     thread_xp  = XPTR( local_cxy , thread_ptr );
    90 
    91     // get local pointer on core running this kernel thead
    92     core_t * core = thread_ptr->core;
    93 
    94 // check thread can yield
    95 assert( (thread_ptr->busylocks == 0),
    96 "cannot yield : busylocks = %d\n", thread_ptr->busylocks );
     403int dev_nic_connect( uint32_t fdid,
     404                     uint32_t remote_addr,
     405                     uint16_t remote_port )
     406{
     407    vfs_inode_type_t    file_type;
     408    socket_t          * socket;
     409    uint32_t            socket_state;     // socket state
     410    uint32_t            socket_type;      // socket type 
     411    uint32_t            local_addr;       // local IP address
     412    uint32_t            local_port;       // local port
     413    xptr_t              tx_server_xp;     // extended pointer on TX server thread
     414    thread_t          * tx_server_ptr;    // local pointer on TX server thread
     415
     416    thread_t  * this    = CURRENT_THREAD;
     417    process_t * process = this->process;
     418
     419    // get pointers on file descriptor
     420    xptr_t       file_xp  = process_fd_get_xptr( process , fdid );
     421    vfs_file_t * file_ptr = GET_PTR( file_xp );
     422    cxy_t        file_cxy = GET_CXY( file_xp );
     423
     424    // check file_xp
     425    if( file_xp == XPTR_NULL )
     426    {
     427        printk("\n[ERROR] in %s : undefined fdid %d",
     428        __FUNCTION__, fdid );
     429        return -1;
     430    }
     431
     432    file_type = hal_remote_l32( XPTR( file_cxy , &file_ptr->type ) );
     433    socket    = hal_remote_lpt( XPTR( file_cxy , &file_ptr->socket ) );
     434
     435    // check file descriptor type
     436    if( file_type != INODE_TYPE_SOCK )
     437    {
     438        printk("\n[ERROR] in %s : illegal file type %s",
     439        __FUNCTION__, vfs_inode_type_str( file_type ) );
     440        return -1;
     441    }
     442
     443    // get relevant socket infos
     444    socket_type   = hal_remote_l32( XPTR( file_cxy , &socket->type ) );
     445    socket_state  = hal_remote_l32( XPTR( file_cxy , &socket->state ) );
     446    local_addr    = hal_remote_l32( XPTR( file_cxy , &socket->local_addr ) );
     447    local_port    = hal_remote_l32( XPTR( file_cxy , &socket->local_port ) );
     448
     449    if( socket_type == SOCK_DGRAM )       // UDP
     450    {
     451        if( socket_state != UDP_STATE_BOUND )
     452        {
     453            printk("\n[ERROR] in %s : illegal socket statea %s for CONNECT",
     454            __FUNCTION__, socket_state_str(socket_state) );
     455            return -1;
     456        }
     457    }
     458    else if( socket_type == SOCK_STREAM )  // TCP
     459    {
     460        if( socket_state != TCP_STATE_BOUND )
     461        {
     462            printk("\n[ERROR] in %s : illegal socket state %s for CONNECT",
     463            __FUNCTION__, socket_state_str(socket_state) );
     464            return -1;
     465        }
     466    }
     467    else
     468    {
     469        printk("\n[ERROR] in %s : illegal socket type %d for CONNECT",
     470        __FUNCTION__, socket_type );
     471        return -1;
     472    }
     473
     474    // compute nic_channel index from remote_addr and remote_port
     475    uint32_t nic_channel = dev_nic_channel_index( remote_addr , remote_port );
     476
     477    // link new socket to chdev servers
     478    socket_link_to_servers( XPTR( file_cxy , socket ),
     479                            nic_channel );
     480
     481    // update the socket descriptor
     482    hal_remote_s32( XPTR( file_cxy , &socket->remote_addr ) , remote_addr  );
     483    hal_remote_s32( XPTR( file_cxy , &socket->remote_port ) , remote_port  );
     484    hal_remote_s32( XPTR( file_cxy , &socket->nic_channel ) , nic_channel  );
     485
     486    // the actual connection mechanism depends on socket type
     487    // UDP : client thread directly updates the local socket state
     488    // TCP : client thread request TX server thread to start the 3 steps handshake
     489
     490    if( socket_type == SOCK_DGRAM )  // UDP
     491    {
     492        // directly update the local socket state
     493        hal_remote_s32( XPTR( file_cxy , &socket->state ) , UDP_STATE_CONNECT );
     494    }
     495    else                             // TCP
     496    {
     497        // get pointers on NIC_TX[index] chdev
     498        xptr_t    tx_chdev_xp  = chdev_dir.nic_tx[nic_channel];
     499        chdev_t * tx_chdev_ptr = GET_PTR( tx_chdev_xp );
     500        cxy_t     tx_chdev_cxy = GET_CXY( tx_chdev_xp );
     501
     502        // get pointers on NIC_TX[channel] server thread
     503        tx_server_ptr = hal_remote_lpt( XPTR( tx_chdev_cxy , &tx_chdev_ptr->server ));
     504        tx_server_xp  = XPTR( tx_chdev_cxy , tx_server_ptr );
     505
     506        // register command arguments in socket descriptor
     507        hal_remote_s64( XPTR( file_cxy , &socket->tx_cmd ),
     508                        SOCKET_TX_CONNECT );
     509
     510        // update the "tx_client" field in socket descriptor
     511        hal_remote_s64( XPTR( file_cxy , &socket->tx_client ),
     512                        XPTR( local_cxy , this ) );
     513
     514        // unblock NIC_TX server thread
     515        thread_unblock( tx_server_xp , THREAD_BLOCKED_CLIENT );
     516 
     517        // block on THREAD_BLOCKED_IO condition and deschedules
     518        thread_block( XPTR( local_cxy , this ) , THREAD_BLOCKED_IO );
     519        sched_yield( "blocked in connect" );
     520
     521        // reset the "tx_client" field in socket descriptor
     522        hal_remote_s64( XPTR( file_cxy , &socket->tx_client ),
     523                        XPTR_NULL );
     524    }
     525
     526    return 0;
     527
     528}  // end dev_nic_connect()
     529
     530////////////////////////////////////
     531int dev_nic_accept( uint32_t   fdid,
     532                    uint32_t * remote_addr,
     533                    uint16_t * remote_port )
     534{
     535    xptr_t              file_xp;             // extended pointer on remote file
     536    vfs_file_t        * file_ptr;
     537    cxy_t               file_cxy;
     538    vfs_inode_type_t    file_type;           // file descriptor type
     539    socket_t          * socket;              // local pointer on remote waiting socket
     540    uint32_t            socket_type;         // waiting socket type   
     541    uint32_t            socket_state;        // waiting socket state
     542    uint32_t            socket_domain;       // waiting socket domain
     543    uint32_t            socket_local_addr;   // waiting socket local IP address
     544    uint32_t            socket_local_port;   // waiting socket local port
     545    xptr_t              crqq_xp;             // extended pointer on socket.crqq queue
     546    socket_t          * new_socket;          // local pointer on new socket
     547    uint32_t            new_fdid;            // new socket file descriptor index
     548    sockaddr_t          new_sockaddr;        // one request in crqq queue
     549    uint32_t            new_remote_addr;     // new socket remote IP address
     550    uint32_t            new_remote_port;     // new socket remote port
     551    error_t             error;
     552
     553    thread_t  * this    = CURRENT_THREAD;
     554    process_t * process = this->process;
     555
     556    // get pointers on file descriptor
     557    file_xp  = process_fd_get_xptr( process , fdid );
     558    file_ptr = GET_PTR( file_xp );
     559    file_cxy = GET_CXY( file_xp );
     560
     561    // check file_xp
     562    if( file_xp == XPTR_NULL )
     563    {
     564        printk("\n[ERROR] in %s : undefined fdid %d",
     565        __FUNCTION__, fdid );
     566        return -1;
     567    }
     568
     569    file_type = hal_remote_l32( XPTR( file_cxy , &file_ptr->type ) );
     570    socket    = hal_remote_lpt( XPTR( file_cxy , &file_ptr->socket ) );
     571
     572    // check file descriptor type
     573    if( file_type != INODE_TYPE_SOCK )
     574    {
     575        printk("\n[ERROR] in %s : illegal file type %s / thread[%x,%x]\n",
     576        __FUNCTION__, vfs_inode_type_str(file_type), process->pid, this->trdid );
     577        return -1;
     578    }
     579
     580    // get socket type, domain, state, local_addr and local_port
     581    socket_type       = hal_remote_l32( XPTR( file_cxy , &socket->type ));
     582    socket_state      = hal_remote_l32( XPTR( file_cxy , &socket->state ));
     583    socket_domain     = hal_remote_l32( XPTR( file_cxy , &socket->domain ));
     584    socket_local_addr = hal_remote_l32( XPTR( file_cxy , &socket->local_addr ));
     585    socket_local_port = hal_remote_l32( XPTR( file_cxy , &socket->local_port ));
     586
     587    // check socket type
     588    if( socket_type != SOCK_STREAM )
     589    {
     590        printk("\n[ERROR] in %s : illegal socket type / thread[%x,%x]\n",
     591        __FUNCTION__, process->pid , this->trdid );
     592        return -1;
     593    }
     594   
     595    // check socket state
     596    if( socket_state != TCP_STATE_LISTEN )
     597    {
     598        printk("\n[ERROR] in %s : illegal socket state %s / thread[%x,%x]\n",
     599        __FUNCTION__, socket_state_str(socket_state), process->pid, this->trdid );
     600        return -1;
     601    }
     602   
     603    // select a cluster for the new socket
     604    cxy_t new_cxy = cluster_random_select();
     605
     606    // allocate memory for the new socket descriptor
     607    error = socket_create( new_cxy,
     608                           socket_domain,
     609                           socket_type,
     610                           &new_socket,
     611                           &new_fdid );
     612    if( error )
     613    {
     614        printk("\n[ERROR] in %s : cannot allocate new socket / thread[%x,%x]\n",
     615        __FUNCTION__, process->pid, this->trdid );
     616        return -1;
     617    }
     618   
     619    // build extended pointer on socket.crqq
     620    crqq_xp  = XPTR( file_cxy , &socket->crqq );
     621
     622    // blocks and deschedules if requests queue empty
     623    if( remote_buf_status( crqq_xp ) == 0 )
     624    {
     625        thread_block( XPTR( local_cxy , this ) , THREAD_BLOCKED_IO );
     626        sched_yield( "socket.crqq queue empty");
     627    }
     628       
     629    // extract first request from the socket.crqq queue
     630    remote_buf_get_to_kernel( crqq_xp,
     631                              (uint8_t *)(&new_sockaddr),
     632                              sizeof(sockaddr_t) );
     633
     634    new_remote_addr = new_sockaddr.s_addr;
     635    new_remote_port = new_sockaddr.s_port;
     636
     637    // compute NIC channel index from remote_addr and remote_port
     638    uint32_t nic_channel = dev_nic_channel_index( new_remote_addr , new_remote_port );
     639
     640    // update new socket descriptor
     641    new_socket->local_addr  = hal_remote_l32(XPTR( file_cxy , &socket->local_addr ));
     642    new_socket->local_port  = hal_remote_l32(XPTR( file_cxy , &socket->local_port ));
     643    new_socket->remote_addr = new_remote_addr;
     644    new_socket->remote_port = new_remote_port;
     645    new_socket->nic_channel = nic_channel;
     646
     647    // link new socket to chdev servers
     648    socket_link_to_servers( XPTR( new_cxy , new_socket ),
     649                            nic_channel );
     650    // return success
     651    *remote_addr = new_remote_addr;
     652    *remote_port = new_remote_port;
     653
     654    return new_fdid;
     655
     656}  // end dev_nic_accept()
     657
     658////////////////////////////////////////////////////////////////////////////////////////
     659// This static and blocking function is called by the four functions :
     660// dev_nic_send() / dev_nic_recv() / dev_nic_sendto() / dev_nic_recvfrom().
     661////////////////////////////////////////////////////////////////////////////////////////
     662// Implementation note
     663// The behavior is very different for SEND & RECV :
     664// - For a SEND, the client thread checks that there is no TX command registered
     665//   in the socket. It registers the command arguments in the socket descriptor
     666//   (tx_client, tx_cmd, tx_buf, tx_len). Then the client thread unblocks the
     667//   TX server thread from the BLOCKED_CLIENT condition, blocks itself on the
     668//   BLOCKED_IO condition, and deschedules. It is unblocked by the TX server thread
     669//   when the last byte has been sent (for UDP) or acknowledged (for TCP).
     670//   When the client thread resumes, it reset the command in socket, and returns.
     671// - For a RECV, the client thread checks that there is no RX command registered
     672//   in the socket. It registers itself in socket (rx_client). It checks the status
     673//   of the receive buffer. It the rx_buf is empty, it blocks on the BLOCKED_IO
     674//   condition, and deschedules. It is unblocked by the RX server thread when an UDP
     675//   packet or TCP segment has been writen in the rx_buf. When it resumes, it moves
     676//   the available data from the rx_buf to the user buffer, reset its registration
     677//   in socket (reset the rx_buf for an UDP socket), and returns.
     678////////////////////////////////////////////////////////////////////////////////////////
     679int dev_nic_register_cmd( bool_t     is_send,
     680                          uint32_t   fdid,
     681                          uint8_t  * u_buf,
     682                          uint32_t   length,
     683                          bool_t     explicit,
     684                          uint32_t   explicit_addr,
     685                          uint32_t   explicit_port )
     686{
     687    vfs_inode_type_t    file_type;       // file descriptor type
     688    socket_t          * socket_ptr;      // local pointer on socket descriptor
     689    uint32_t            socket_state;    // current socket state
     690    uint32_t            socket_type;     // socket type (UDP/TCP)
     691    uint32_t            nic_channel;     // NIC channel for this socket
     692    xptr_t              socket_lock_xp;  // extended pointer on socket lock
     693    xptr_t              file_xp;         // extended pointer on file descriptor
     694    vfs_file_t        * file_ptr;
     695    cxy_t               file_cxy;
     696    xptr_t              chdev_xp;        // extended pointer on NIC_TX[channel] chdev
     697    chdev_t           * chdev_ptr;
     698    cxy_t               chdev_cxy;
     699    uint32_t            remote_addr;
     700    uint32_t            remote_port;
     701    uint32_t            status;          // number of bytes in rx_buf
     702    int32_t             moved_bytes;     // total number of moved bytes (fot return)
     703    xptr_t              server_xp;       // extended pointer on NIC_TX / NIC_RX server thread
     704    thread_t          * server_ptr;      // local pointer on NIC_TX / NIC_RX server thread
     705
     706    thread_t  * this    = CURRENT_THREAD;
     707    process_t * process = this->process;
     708
     709    // get pointers on file descriptor identifying the socket
     710    file_xp  = process_fd_get_xptr( process , fdid );
     711    file_ptr = GET_PTR( file_xp );
     712    file_cxy = GET_CXY( file_xp );
     713
     714    if( file_xp == XPTR_NULL )
     715    {
     716        printk("\n[ERROR] in %s : undefined fdid %d / thread%x,%x]\n",
     717        __FUNCTION__, fdid , process->pid, this->trdid );
     718        return -1;
     719    }
     720 
     721    // get file type and socket pointer
     722    file_type  = hal_remote_l32( XPTR( file_cxy , &file_ptr->type ) );
     723
     724    // get local pointer on socket
     725    socket_ptr = hal_remote_lpt( XPTR( file_cxy , &file_ptr->socket ) );
     726
     727    // check file descriptor type
     728    if( file_type != INODE_TYPE_SOCK )
     729    {
     730        printk("\n[ERROR] in %s : illegal file type %s / fdid %d / thread%x,%x]\n",
     731        __FUNCTION__, vfs_inode_type_str(file_type), fdid, process->pid, this->trdid );
     732        return -1;
     733    }
     734
     735    // build extended pointer on file lock protecting socket
     736    socket_lock_xp = XPTR( file_cxy , &file_ptr->lock );
     737
     738    // take the socket lock
     739    remote_rwlock_wr_acquire( socket_lock_xp );
     740
     741    // get socket type, state, and channel
     742    socket_type  = hal_remote_l32( XPTR( file_cxy , &socket_ptr->type ));
     743    socket_state = hal_remote_l32( XPTR( file_cxy , &socket_ptr->state ));
     744    nic_channel  = hal_remote_l32( XPTR( file_cxy , &socket_ptr->nic_channel ));
     745
     746    // check socket state / type
     747    if( socket_type == SOCK_STREAM )     // TCP socket
     748    {
     749        if( socket_state != TCP_STATE_ESTAB )
     750        {
     751            printk("\n[ERROR] in %s : illegal SEND/RECV for state %s / thread%x,%x]\n",
     752            __FUNCTION__, socket_state_str(socket_state), process->pid, this->trdid );
     753            return -1;
     754        }
     755
     756        if( explicit )
     757        {
     758            // get remote IP address and type from socket descriptor
     759            remote_addr = hal_remote_l32( XPTR( file_cxy , &socket_ptr->remote_addr ));
     760            remote_port = hal_remote_l32( XPTR( file_cxy , &socket_ptr->remote_port ));
     761
     762            if( (remote_addr != explicit_addr) || (remote_port != explicit_port) )
     763            {
     764                printk("\n[ERROR] in %s : wrong expliciy access / thread%x,%x]\n",
     765                __FUNCTION__, process->pid, this->trdid );
     766                return -1;
     767            }
     768        }
     769    }
     770    else                              // UDP socket
     771    {
     772        if( explicit )
     773        {
     774            if( socket_state == UDP_STATE_UNBOUND )
     775            {
     776                printk("\n[ERROR] in %s : illegal SEND/RECV for state %s / thread%x,%x]\n",
     777                __FUNCTION__, socket_state_str(socket_state), process->pid, this->trdid );
     778                return -1;
     779            }
     780
     781            // update remote IP address and port into socket descriptor
     782            hal_remote_s32( XPTR( file_cxy , &socket_ptr->remote_addr ), explicit_addr );
     783            hal_remote_s32( XPTR( file_cxy , &socket_ptr->remote_port ), explicit_port );
     784        }
     785        else
     786        {
     787            if( socket_state != UDP_STATE_CONNECT )
     788            {
     789                printk("\n[ERROR] in %s : illegal SEND/RECV for state %s / thread%x,%x]\n",
     790                __FUNCTION__, socket_state_str(socket_state), process->pid, this->trdid );
     791                return -1;
     792            }
     793        }
     794    }
     795
     796    ///////////////////////////////////////////////////////
     797    if( is_send )                       // SEND command
     798    {
     799        // build extended pointer on socket "tx_client"
     800        xptr_t client_xp = XPTR( file_cxy , &socket_ptr->tx_client );
     801
     802        // check no previous SEND command
     803        xptr_t client = hal_remote_l64( client_xp );
     804
     805        if( client != XPTR_NULL )  // release socket lock and return error
     806        {
     807            // release socket lock
     808            remote_rwlock_wr_release( socket_lock_xp );
     809                   
     810            // get previous thread cluster & local pointer
     811            cxy_t      prev_cxy = GET_CXY( client );
     812            thread_t * prev_ptr = GET_PTR( client );
     813
     814            // get previous command type and trdid
     815            uint32_t prev_cmd = hal_remote_l32( XPTR( prev_cxy , &prev_ptr->nic_cmd.type ));
     816            uint32_t prev_tid = hal_remote_l32( XPTR( prev_cxy , &prev_ptr->trdid ));
     817
     818            printk("\n[ERROR] in %s : previous command %s for thread %x / thread%x,%x]\n",
     819            __FUNCTION__, socket_cmd_str(prev_cmd), prev_tid,
     820            process->pid, this->trdid );
     821
     822            return -1;
     823        }
     824
     825        // client thread registers in socket descriptor
     826        hal_remote_s64( client_xp , XPTR( local_cxy , this ) );
     827        hal_remote_s32( XPTR( file_cxy , &socket_ptr->tx_cmd  ) , SOCKET_TX_SEND );
     828        hal_remote_spt( XPTR( file_cxy , &socket_ptr->tx_buf  ) , u_buf );
     829        hal_remote_s32( XPTR( file_cxy , &socket_ptr->tx_len  ) , length );
     830        hal_remote_s32( XPTR( file_cxy , &socket_ptr->tx_todo ) , length );
     831
     832        // release socket lock
     833        remote_rwlock_wr_release( socket_lock_xp );
     834                   
     835        // get pointers on relevant chdev
     836        chdev_xp  = chdev_dir.nic_tx[nic_channel];
     837        chdev_ptr = GET_PTR( chdev_xp );
     838        chdev_cxy = GET_CXY( chdev_xp );
     839
     840        // get pointers on NIC_TX[channel] server thread
     841        server_ptr = hal_remote_lpt( XPTR( chdev_cxy , &chdev_ptr->server ));
     842        server_xp  = XPTR( chdev_cxy , server_ptr );
     843
     844        // unblocks the NIC_TX server thread
     845        thread_unblock( server_xp , THREAD_BLOCKED_CLIENT );
     846
     847        // client thread blocks itself and deschedules
     848        thread_block( XPTR( local_cxy , this ) , THREAD_BLOCKED_IO );
     849        sched_yield( "blocked in nic_io" );
     850
     851        // take the socket lock when unblocked
     852        remote_rwlock_wr_acquire( socket_lock_xp );
     853
     854        // unlink client thread from socket
     855        hal_remote_s64( client_xp , XPTR_NULL );
     856                   
     857        // release socket lock
     858        remote_rwlock_wr_release( socket_lock_xp );
     859                   
     860        // exit waiting loop and return
     861        return length;
     862
     863    }  // end SEND
     864
     865    ////////////////////////////////////////////////////////
     866    else                                 // RECV command
     867    {
     868        // build extended pointers on socket "rx_client"
     869        xptr_t client_xp = XPTR( file_cxy , &socket_ptr->rx_client );
     870
     871        // check no previous RECV command
     872        xptr_t client = hal_remote_l64( client_xp );
     873
     874        if( client != XPTR_NULL )  // release socket lock and return error
     875        {
     876            // release socket lock
     877            remote_rwlock_wr_release( socket_lock_xp );
     878                   
     879            // get previous thread cluster & local pointer
     880            cxy_t      prev_cxy = GET_CXY( client );
     881            thread_t * prev_ptr = GET_PTR( client );
     882
     883            // get previous command type and trdid
     884            uint32_t prev_cmd = hal_remote_l32( XPTR( prev_cxy , &prev_ptr->nic_cmd.type ));
     885            uint32_t prev_tid = hal_remote_l32( XPTR( prev_cxy , &prev_ptr->trdid ));
     886
     887            printk("\n[ERROR] in %s : previous command %s for thread %x / thread%x,%x]\n",
     888            __FUNCTION__, socket_cmd_str(prev_cmd), prev_tid, process->pid, this->trdid );
     889            return -1;
     890        }
     891
     892        // build extended pointer on "rx_buf"
     893        xptr_t rx_buf_xp = XPTR( file_cxy , &socket_ptr->rx_buf );
     894
     895        // get rx_buf status from socket
     896        status = remote_buf_status( rx_buf_xp );
     897
     898        if( status == 0 )    // rx_buf empty => blocks and deschedules
     899        {
     900            // release socket lock
     901            remote_rwlock_wr_release( socket_lock_xp );
     902                 
     903            // client thread blocks itself and deschedules
     904            thread_block( XPTR( local_cxy , this ) , THREAD_BLOCKED_IO );
     905            sched_yield( "blocked in nic_io" );
     906
     907            // take socket lock
     908            remote_rwlock_wr_release( socket_lock_xp );
     909        }
     910
     911        // number of moved bytes cannot be larger than u_buf size
     912        moved_bytes = ( length < status ) ? length : status;
     913
     914        // move data from kernel rx_buf to user u_buf
     915        remote_buf_get_to_user( rx_buf_xp,
     916                                 u_buf,
     917                                 moved_bytes );
     918
     919        // reset rx_buf for an UDP socket
     920        if( socket_type == SOCK_DGRAM ) remote_buf_reset( rx_buf_xp );
     921
     922        // unlink client thread from socket
     923        hal_remote_s64( client_xp , XPTR_NULL );
     924                   
     925        // release socket lock
     926        remote_rwlock_wr_release( socket_lock_xp );
     927                   
     928        // exit waiting loop and return
     929        return moved_bytes;
     930
     931    }  // end SEND 
     932
     933} // end dev_nic_register_cmd()
     934
     935
     936///////////////////////////////////
     937int dev_nic_send( uint32_t    fdid,
     938                  uint8_t   * u_buf,
     939                  uint32_t    length )
     940{
     941#if DEBUG_DEV_NIC_TX
     942thread_t  * this    = CURRENT_THREAD;
     943process_t * process = this->process;
     944trdid_t     trdid   = this->trdid;
     945pid_t       pid     = process->pid;
     946uint32_t cycle = (uint32_t)hal_get_cycle();
     947if (DEBUG_DEV_NIC_TX < cycle )
     948printk("[%s] thread[%x,%x] enters : fdid %d / buf %x / length %d / cycle %d\n",
     949__FUNCTION__, pid, trdid, fdid, u_buf, length, cycle );
     950#endif
     951
     952    error_t error = dev_nic_register_cmd( true,           // SEND
     953                                          fdid,
     954                                          u_buf,
     955                                          length,
     956                                          false, 0, 0 );  // no explicit remote socket
     957#if DEBUG_DEV_NIC_TX
     958cycle = (uint32_t)hal_get_cycle();
     959if (DEBUG_DEV_NIC_TX < cycle )
     960printk("[%s] thread[%x,%x] exit : fdid %d / cycle %d\n",
     961__FUNCTION__, pid, trdid, cycle );
     962#endif
     963
     964    return error;
     965
     966}  // end dev_nic_send()
     967
     968///////////////////////////////////
     969int dev_nic_recv( uint32_t    fdid,
     970                  uint8_t   * u_buf,
     971                  uint32_t    length )
     972{
     973#if DEBUG_DEV_NIC_RX
     974thread_t  * this    = CURRENT_THREAD;
     975process_t * process = this->process;
     976trdid_t     trdid   = this->trdid;
     977pid_t       pid     = process->pid;
     978uint32_t    cycle   = (uint32_t)hal_get_cycle();
     979if (DEBUG_DEV_NIC_RX < cycle )
     980printk("[%s] thread[%x,%x] enters : fdid %d / buf %x / length %d / cycle %d\n",
     981__FUNCTION__, pid, trdid, fdid, u_buf, length, cycle );
     982#endif
     983
     984    error_t error = dev_nic_register_cmd( false,          // RECV
     985                                          fdid,
     986                                          u_buf,
     987                                          length,
     988                                          false, 0, 0 );  // no explicit remote socket
     989#if DEBUG_DEV_NIC_RX
     990cycle = (uint32_t)hal_get_cycle();
     991if (DEBUG_DEV_NIC_RX < cycle )
     992printk("[%s] thread[%x,%x] exit : fdid %d / cycle %d\n",
     993__FUNCTION__, pid, trdid, cycle );
     994#endif
     995
     996    return error;
     997
     998} // end dev_nic_recv()
     999
     1000/////////////////////////////////////
     1001int dev_nic_sendto( uint32_t    fdid,
     1002                    uint8_t   * u_buf,
     1003                    uint32_t    length,
     1004                    uint32_t    remote_addr,
     1005                    uint32_t    remote_port )
     1006{
     1007#if DEBUG_DEV_NIC_TX
     1008thread_t  * this    = CURRENT_THREAD;
     1009process_t * process = this->process;
     1010trdid_t     trdid   = this->trdid;
     1011pid_t       pid     = process->pid;
     1012uint32_t cycle = (uint32_t)hal_get_cycle();
     1013if (DEBUG_DEV_NIC_TX < cycle )
     1014printk("[%s] thread[%x,%x] enters : fdid %d / buf %x / length %d / cycle %d\n",
     1015__FUNCTION__, pid, trdid, fdid, u_buf, length, cycle );
     1016#endif
     1017
     1018    error_t error = dev_nic_register_cmd( true,          // SEND
     1019                                          fdid,
     1020                                          u_buf,
     1021                                          length,
     1022                                          true,          // explicit remote socket
     1023                                          remote_addr,
     1024                                          remote_port );
     1025#if DEBUG_DEV_NIC_TX
     1026cycle = (uint32_t)hal_get_cycle();
     1027if (DEBUG_DEV_NIC_TX < cycle )
     1028printk("[%s] thread[%x,%x] exit : fdid %d / cycle %d\n",
     1029__FUNCTION__, pid, trdid, cycle );
     1030#endif
     1031
     1032    return error;
     1033
     1034}  // end dev_nic_sendto()
     1035
     1036///////////////////////////////////////
     1037int dev_nic_recvfrom( uint32_t    fdid,
     1038                      uint8_t   * u_buf,
     1039                      uint32_t    length,
     1040                      uint32_t    remote_addr,
     1041                      uint32_t    remote_port )
     1042{
     1043#if DEBUG_DEV_NIC_RX
     1044thread_t  * this    = CURRENT_THREAD;
     1045process_t * process = this->process;
     1046trdid_t     trdid   = this->trdid;
     1047pid_t       pid     = process->pid;
     1048uint32_t    cycle   = (uint32_t)hal_get_cycle();
     1049if (DEBUG_DEV_NIC_RX < cycle )
     1050printk("[%s] thread[%x,%x] enters : fdid %d / buf %x / length %d / cycle %d\n",
     1051__FUNCTION__, pid, trdid, fdid, u_buf, length, cycle );
     1052#endif
     1053
     1054    error_t error = dev_nic_register_cmd( false,         // RECV
     1055                                          fdid,
     1056                                          u_buf,
     1057                                          length,
     1058                                          true,          // explicit remote socket
     1059                                          remote_addr,
     1060                                          remote_port );
     1061#if DEBUG_DEV_NIC_RX
     1062cycle = (uint32_t)hal_get_cycle();
     1063if (DEBUG_DEV_NIC_RX < cycle )
     1064printk("[%s] thread[%x,%x] exit : fdid %d / cycle %d\n",
     1065__FUNCTION__, pid, trdid, cycle );
     1066#endif
     1067
     1068    return error;
     1069
     1070}  // end dev_nic_recvfrom()
     1071
     1072
     1073
     1074
     1075
     1076
     1077
     1078
     1079///////////////////////////////////////////////////////////////////////////////////////////
     1080//               Functions called by the NIC_RX server thread
     1081///////////////////////////////////////////////////////////////////////////////////////////
     1082
     1083/////////////////////////////////////////////////////////////////////////////////////////
     1084// This static function is called by the NIC_RX[channel] server thread to register
     1085// a send request defined by the <flags> argument in the R2T queue  specified by
     1086// the <queue_xp> argument.
     1087/////////////////////////////////////////////////////////////////////////////////////////
     1088// @ queue_xp   : [in] extended pointer on the R2T qeue descriptor.
     1089// @ flags      : [in] flags to be set in the TCP segment.
     1090/////////////////////////////////////////////////////////////////////////////////////////
     1091static void dev_nic_rx_put_r2t_request( xptr_t    queue_xp,
     1092                                        uint32_t  flags )
     1093{
     1094    while( 1 )
     1095    {
     1096        error_t error = remote_buf_put_from_kernel( queue_xp,
     1097                                                    (uint8_t *)(&flags),
     1098                                                    1 );
     1099
     1100        if( error )  sched_yield( "waiting R2T queue" );
     1101        else         break;
     1102    }
     1103
     1104}  // end dev_nic_rx_put_r2t_request()
     1105 
     1106///////////////////////////////////////////////////////////////////////////////////////////
     1107// This static function is called by the dev_nic_rx_server() function.
     1108// It calls directly the NIC driver (with the READABLE command) and returns the status
     1109// of the NIC_RX queue identified by the <chdev> argument.
     1110// in the <readable> buffer.
     1111///////////////////////////////////////////////////////////////////////////////////////////
     1112// @ chdev     : [in]  local pointer on NIC_TX chdev.
     1113// @ readable  : [out] zero if queue empty. 
     1114// @ returns 0 if success / returns -1 if failure in accessing NIC device.
     1115///////////////////////////////////////////////////////////////////////////////////////////
     1116error_t dev_nic_rx_queue_readable( chdev_t  * chdev,
     1117                                   uint32_t * readable )
     1118{
     1119    thread_t * this = CURRENT_THREAD;
     1120
     1121    // initialize NIC_READABLE command in thread descriptor
     1122    this->nic_cmd.dev_xp = XPTR( local_cxy , chdev );
     1123    this->nic_cmd.type   = NIC_CMD_READABLE;
     1124
     1125    // call driver to test readable
     1126    chdev->cmd( XPTR( local_cxy , this ) );
     1127
     1128    // return status
     1129    *readable = this->nic_cmd.status;
     1130
     1131    // return error
     1132    return this->nic_cmd.error;
     1133}
     1134
     1135///////////////////////////////////////////////////////////////////////////////////////////
     1136// This static function is called by the dev_nic_rx_server() function.
     1137// It moves one Ethernet packet from the NIC_RX_QUEUE identified the <chdev> argument,
     1138// to the 2K bytes kernel buffer identified by the <buffer> argument. The actual
     1139// Ethernet packet length is returned in the <length> argument.
     1140// It calls directly the NIC driver with the READ command, without registering in the
     1141// waiting queue, because only the NIC_RX server thread can access this NIC_RX_QUEUE.
     1142///////////////////////////////////////////////////////////////////////////////////////////
     1143// @ chdev   : [in]  local pointer on NIC_TX chdev.
     1144// @ buffer  : [in]  local pointer on destination kernel buffer.
     1145// @ length  : [out] Ethernet packet size in bytes.
     1146// @ returns 0 if success / returns -1 if failure in accessing NIC device.
     1147///////////////////////////////////////////////////////////////////////////////////////////
     1148error_t dev_nic_rx_move_packet( chdev_t  * chdev,
     1149                                uint8_t  * k_buf,
     1150                                uint32_t * length )
     1151{
     1152    thread_t * this = CURRENT_THREAD;
    971153
    981154#if DEBUG_DEV_NIC_RX
    991155uint32_t cycle = (uint32_t)hal_get_cycles();
    1001156if( DEBUG_DEV_NIC_RX < cycle )
    101 printk("\n[DBG] %s : thread %x enters for packet %x in cluster %x\n",
    102 __FUNCTION__ , thread_ptr , pkd , local_cxy );
     1157printk("\n[%s] thread[%x,%x] enters / cycle %d\n",
     1158__FUNCTION__, this->process->pid, this->trdid, cycle );
    1031159#endif
    1041160
    105     // get pointer on NIC-RX chdev descriptor
    106     uint32_t   channel = thread_ptr->chdev->channel;
    107     xptr_t     dev_xp  = chdev_dir.nic_rx[channel];
    108     cxy_t      dev_cxy = GET_CXY( dev_xp );
    109     chdev_t  * dev_ptr = (chdev_t *)GET_PTR( dev_xp );
    110 
    111     assert( (dev_xp != XPTR_NULL) , "undefined NIC chdev descriptor" );
    112 
    113     assert( (dev_cxy == local_cxy) , " chdev must be local" );
    114 
    115     // initialize command in thread descriptor
    116     thread_ptr->nic_cmd.dev_xp = dev_xp;
    117 
    118     // call driver to test readable
    119     thread_ptr->nic_cmd.cmd = NIC_CMD_READABLE;
    120     dev_ptr->cmd( thread_xp );
     1161    // initialize NIC_READ command in thread descriptor
     1162    this->nic_cmd.type    = NIC_CMD_READ;
     1163    this->nic_cmd.buffer  = k_buf;
     1164
     1165    // call NIC driver 
     1166    chdev->cmd( XPTR( local_cxy , this ) );
     1167
     1168    // returns packet length   
     1169    *length = this->nic_cmd.length;
    1211170
    1221171    // check error
    123     error = thread_ptr->nic_cmd.error;
    124     if( error ) return error;
    125 
    126     // block and deschedule if queue non readable
    127     if( thread_ptr->nic_cmd.status == false ) 
    128     {
    129         // enable NIC-RX IRQ
    130         dev_pic_enable_irq( core->lid , dev_xp );
    131 
    132         // block client thread on THREAD_BLOCKED_IO
    133         thread_block( XPTR( local_cxy , thread_ptr ) , THREAD_BLOCKED_IO );
    134 
    135         // deschedule client thread
    136         sched_yield("client blocked on I/O");
    137 
    138         // disable NIC-RX IRQ
    139         dev_pic_disable_irq( core->lid , dev_xp );
    140     }
    141 
    142     // call driver for actual read
    143     thread_ptr->nic_cmd.cmd     = NIC_CMD_READ;
    144     thread_ptr->nic_cmd.buffer  = pkd->buffer;
    145     dev_ptr->cmd( thread_xp );
    146 
    147     // check error
    148     error = thread_ptr->nic_cmd.error;
    149     if( error ) return error;
    150 
    151     // returns packet length   
    152     pkd->length = thread_ptr->nic_cmd.length;
     1172    if( this->nic_cmd.error )
     1173    {
    1531174
    1541175#if DEBUG_DEV_NIC_RX
    1551176cycle = (uint32_t)hal_get_cycles();
    1561177if( DEBUG_DEV_NIC_RX < cycle )
    157 printk("\n[DBG] %s : thread %x exit for packet %x in cluster %x\n",
    158 __FUNCTION__ , thread_ptr , pkd , local_cxy );
     1178printk("\n[%s] thread[%x,%x] exit / ERROR in NIC_RX / cycle %d\n",
     1179__FUNCTION__, this->process->pid, this->trdid, cycle );
    1591180#endif
    1601181
     1182        return -1;
     1183    }
     1184    else
     1185    {
     1186
     1187#if DEBUG_DEV_NIC_RX
     1188cycle = (uint32_t)hal_get_cycles();
     1189if( DEBUG_DEV_NIC_RX < cycle )
     1190printk("\n[%s] thread[%x,%x] exit / SUCCESS / cycle %d\n",
     1191__FUNCTION__, this->process->pid, this->trdid, cycle );
     1192#endif
     1193
     1194        return 0;
     1195    }
     1196
     1197}   // end dev_nic_rx_move_packet()
     1198
     1199///////////////////////////////////////////////////////////////////////////////////////////
     1200// This static function is called by the dev_nic_rx_server() function.
     1201// It analyses an Ethernet frame contained in the kernel buffer defined
     1202// by the <buffer> argument, and returns in the  <ip_length> argument the length
     1203// of the IP packet contained in the Ethernet packet payload.
     1204///////////////////////////////////////////////////////////////////////////////////////////
     1205// @ buffer     : [in] pointer on a received Ethernet packet
     1206// @ ip_length  : [out] length of IP packet (in bytes).
     1207// @ return 0 if success / return -1 if illegal packet length.
     1208///////////////////////////////////////////////////////////////////////////////////////////
     1209static error_t dev_nic_rx_check_eth( uint8_t  * buffer,
     1210                                     uint32_t * ip_length )
     1211{
     1212    uint32_t length = ((uint32_t)buffer[12] << 8) | (uint32_t)buffer[13];
     1213
     1214    *ip_length = length;
     1215
    1611216    return 0;
    162 
    163 }   // end dev_nic_read()
    164 
    165 
    166 ////////////////////////////////////
    167 error_t dev_nic_write( pkd_t * pkd )
    168 {
    169     error_t error;
    170 
    171     // get pointers on the NIC-TX kernel tread
    172     thread_t * thread_ptr = CURRENT_THREAD;
    173     xptr_t     thread_xp  = XPTR( local_cxy , thread_ptr );
    174 
    175     // get local pointer on core running this kernel thead
    176     core_t * core = thread_ptr->core;
     1217}
     1218   
     1219///////////////////////////////////////////////////////////////////////////////////////////
     1220// This static function analyses the IP packet contained in the kernel buffer
     1221// defined by the <buffer> argument, and returns in the <ip_src_addr>, <ip_dst_addr>,
     1222// <header_length> and <protocol> arguments the informations contained in the IP header.
     1223// It checks the IP packet length versus the value contained in Ethernet header.
     1224// It checks the IP header checksum.
     1225///////////////////////////////////////////////////////////////////////////////////////////
     1226// @ buffer          : [in] pointer on the IP packet.
     1227// @ expected_length : [in] expected IP packet length (from Ethernet header).
     1228// @ ip_src_addr     : [out] source IP address.
     1229// @ ip_dst_addr     : [out] destination IP address.
     1230// @ protocol        : [out] transport protocol type.
     1231// @ return 0 if success / return -1 if illegal packet.
     1232///////////////////////////////////////////////////////////////////////////////////////////
     1233static error_t dev_nic_rx_check_ip( uint8_t  * buffer,
     1234                                    uint32_t   expected_length,
     1235                                    uint32_t * ip_src_addr,
     1236                                    uint32_t * ip_dst_addr,
     1237                                    uint32_t * trsp_protocol )
     1238{
     1239    uint32_t length = ((uint32_t)buffer[2] << 8) | (uint32_t)buffer[3];
     1240
     1241    // discard packet if eth_length != ip_length
     1242    if( length != expected_length )
     1243    {
     1244
     1245#if DEBUG_NIC_DEV
     1246thread_t * this = CURRENT_THREAD;
     1247printk("\n[%s] thread[%x,%x] enters : length (%d) != expected_length (%d)\n",
     1248__FUNCTION__, this->process->pid, this->trdid, length, expected_length );
     1249#endif
     1250
     1251        return -1;
     1252    }
     1253
     1254    // compute IP header checksum
     1255    uint32_t received_cs = (uint32_t)dev_nic_ip_checksum( buffer );
     1256
     1257    // extract IP header checksum
     1258    uint32_t computed_cs = ((uint32_t)buffer[10] << 8) | ((uint32_t)buffer[11]);
     1259
     1260    // discard packet if bad checksum
     1261    if( received_cs != computed_cs )
     1262    {
     1263
     1264#if DEBUG_NIC_DEV
     1265thread_t * this = CURRENT_THREAD;
     1266printk("\n[%s] thread[%x,%x] computed checksum (%d) != received checksum (%d)\n",
     1267__FUNCTION__, this->process->pid, this->trdid, computed_cs, received_cs );
     1268#endif
     1269
     1270        return -1;
     1271    }
     1272
     1273
     1274    *ip_src_addr = ((uint32_t)buffer[12] << 24) |
     1275                   ((uint32_t)buffer[13] << 16) |
     1276                   ((uint32_t)buffer[14] <<  8) |
     1277                   ((uint32_t)buffer[15]      ) ;
     1278
     1279    *ip_dst_addr = ((uint32_t)buffer[16] << 24) |
     1280                   ((uint32_t)buffer[17] << 16) |
     1281                   ((uint32_t)buffer[18] <<  8) |
     1282                   ((uint32_t)buffer[19]      ) ;
     1283
     1284    *trsp_protocol = (uint32_t)buffer[9];
     1285   
     1286    return 0;
     1287}
     1288
     1289///////////////////////////////////////////////////////////////////////////////////////////
     1290// This static function analyses the UDP packet contained in the kernel buffer
     1291// defined by the <k_buf> and <k_length> arguments.
     1292// It checks the UDP checksum, and discard corrupted packets.
     1293// It scans the list of sockets attached to the NIC_RX chdev to find a matching socket,
     1294// and discard the received packet if no UDP socket found.
     1295// Finally, it copies the payload to the socket "rx_buf", as long as the packet payload
     1296// is not larger than the rx_buf.
     1297// It set the "rx_valid" flip-flop, and unblock the client thread when the last expected
     1298// byte has been received.
     1299///////////////////////////////////////////////////////////////////////////////////////////
     1300// @ chdev         : [in] local pointer on local NIC_RX chdev descriptor.
     1301// @ k_buf         : [in] pointer on the UDP packet in local kernel buffer.
     1302// @ k_length      : [in] number of bytes in buffer (including UDP header).
     1303// @ pkt_src_addr  : [in] source IP address (from IP packet header).
     1304// @ pkt_dst_addr  : [in] destination IP address (from IP packet header).
     1305///////////////////////////////////////////////////////////////////////////////////////////
     1306static void dev_nic_rx_handle_udp_packet( chdev_t  * chdev,
     1307                                          uint8_t  * k_buf,
     1308                                          uint32_t   k_length,
     1309                                          uint32_t   pkt_src_addr,
     1310                                          uint32_t   pkt_dst_addr )
     1311{
     1312    xptr_t     root_xp;           // extended pointer on attached sockets list root
     1313    xptr_t     lock_xp;           // extended pointer on chdev lock
     1314    xptr_t     iter_xp;           // iterator on socket list
     1315    xptr_t     socket_xp;         // extended pointer on socket descriptor
     1316    cxy_t      socket_cxy;
     1317    socket_t * socket_ptr;
     1318    uint32_t   socket_type;       // socket type
     1319    uint32_t   socket_state;      // socket state
     1320    uint32_t   local_addr;        // local IP address from socket
     1321    uint32_t   local_port;        // local port from socket
     1322    uint32_t   remote_addr;       // remote IP address from socket
     1323    uint32_t   remote_port;       // remote port from socket
     1324    bool_t     match_socket;      // matching socket found
     1325    uint16_t   checksum;          // computed checksum
     1326    uint16_t   pkt_checksum;      // received checksum
     1327    xptr_t     socket_rbuf_xp;    // extended pointer on socket rx_buf
     1328    xptr_t     socket_lock_xp;    // extended pointer on socket lock
     1329    xptr_t     socket_client_xp;  // extended pointer on socket rx_client field
     1330    xptr_t     client_xp;         // extended pointer on client thread descriptor
     1331    uint32_t   payload;           // number of bytes in payload
     1332    uint32_t   status;            // number of bytes in rx_buf
     1333    uint32_t   space;             // number of free slots in rx_buf
     1334    uint32_t   moved_bytes;       // number of bytes actually moved to rx_buf
     1335
     1336    // build extended pointers on list of sockets attached to NIC_RX chdev
     1337    root_xp = XPTR( local_cxy , &chdev->wait_root );
     1338    lock_xp = XPTR( local_cxy , &chdev->wait_lock );
     1339
     1340    // compute UDP packet checksum
     1341    checksum = dev_nic_udp_checksum( k_buf , k_length );
     1342
     1343    // get checksum from received packet header
     1344    pkt_checksum = ((uint16_t)k_buf[6] << 8) | (uint16_t)k_buf[7];
     1345
     1346    // discard corrupted packet 
     1347    if( pkt_checksum != checksum ) return;
     1348   
     1349    // get src_port and dst_port from UDP header
     1350    uint32_t pkt_src_port = ((uint32_t)k_buf[0] << 8) | (uint32_t)k_buf[1];
     1351    uint32_t pkt_dst_port = ((uint32_t)k_buf[2] << 8) | (uint32_t)k_buf[3];
     1352
     1353    // discard unexpected packet
     1354    if( xlist_is_empty( root_xp ) ) return;
     1355 
     1356    // take the tock protecting the sockets list
     1357    remote_busylock_acquire( lock_xp );
     1358
     1359    match_socket = false;
     1360
     1361    // scan sockets list to find a match
     1362    XLIST_FOREACH( root_xp , iter_xp )
     1363    {
     1364        // get socket cluster and local pointer
     1365        socket_xp  = XLIST_ELEMENT( iter_xp , socket_t , rx_list );
     1366        socket_ptr = GET_PTR( socket_xp );
     1367        socket_cxy = GET_CXY( socket_xp );
     1368
     1369        // get socket type
     1370        socket_type  = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->type ));
     1371        socket_state = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->state ));
     1372               
     1373        // skip TCP socket
     1374        if( socket_type == SOCK_STREAM ) continue;
     1375
     1376        // get relevant info from socket descriptor
     1377        local_addr  = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->local_addr ));
     1378        remote_addr = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->remote_addr ));
     1379        local_port  = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->local_port ));
     1380        remote_port = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->remote_port ));
     1381
     1382        // compute matching
     1383        bool_t local_match  = (local_addr  == pkt_dst_addr) &&
     1384                              (local_port  == pkt_dst_port);
     1385
     1386        bool_t remote_match = (remote_addr == pkt_src_addr) &&
     1387                              (remote_port == pkt_src_port);
     1388
     1389        if (socket_state == UDP_STATE_CONNECT ) match_socket = local_match && remote_match;
     1390        else                                    match_socket = local_match;
     1391
     1392        // exit loop when socket found
     1393        if( match_socket ) break;
     1394    }
     1395
     1396    // release the lock protecting the sockets list
     1397    remote_busylock_release( lock_xp );
     1398
     1399    // discard unexpected packet
     1400    if( match_socket == false ) return;
     1401   
     1402    // build extended pointers on various socket fields
     1403    socket_rbuf_xp   = XPTR( socket_cxy , &socket_ptr->rx_buf );
     1404    socket_lock_xp   = XPTR( socket_cxy , &socket_ptr->lock );
     1405    socket_client_xp = XPTR( socket_cxy , &socket_ptr->rx_client );
     1406
     1407    // take the lock protecting the socket
     1408    remote_rwlock_wr_acquire( socket_lock_xp );
     1409
     1410    // get status & space from rx_buf
     1411    status = remote_buf_status( socket_rbuf_xp );
     1412    space  = NIC_RX_BUF_SIZE - status;
     1413
     1414    // get client thread
     1415    client_xp  = hal_remote_l64( socket_client_xp );
     1416
     1417    // get number of bytes in payload
     1418    payload = k_length - UDP_HEAD_LEN;
     1419
     1420    // compute number of bytes to move : min (space , seg_payload)
     1421    moved_bytes = ( space < payload ) ? space : payload;
     1422
     1423    // move payload from kernel buffer to socket rx_buf
     1424    remote_buf_put_from_kernel( socket_rbuf_xp,
     1425                                 k_buf + UDP_HEAD_LEN,
     1426                                 moved_bytes );
     1427
     1428    // unblock client thread if registered
     1429    if( client_xp != XPTR_NULL )
     1430    {
     1431        thread_unblock( client_xp , THREAD_BLOCKED_IO );
     1432    }
     1433
     1434    // release the lock protecting the socket
     1435    remote_rwlock_wr_release( socket_lock_xp );
     1436
     1437}  // end dev_nic_rx_handle_udp_packet()
     1438
     1439///////////////////////////////////////////////////////////////////////////////////////////
     1440// This static function is called by the dev_nic_rx_server() function to handle one RX
     1441// TCP segment contained in a kernel buffer defined by the <k_buf> & <k_length> arguments.
     1442// It the received segment doesn't match an existing local socket, or is corrupted,
     1443// this faulty segment is discarded.
     1444///////////////////////////////////////////////////////////////////////////////////////////
     1445// Implementation note:
     1446// 1) It checks the TCP checksum, and discard the corrupted segment.
     1447// 2) It scans the list of sockets attached to the RX chdev, to find the socket
     1448//    matching the TCP segment header, and discards the segment if no socket found.
     1449// 3) When a socket has been found, it takes the lock protecting the socket state,
     1450//    because the socket is accessed by both the NIC_TX and NIC_RX server threads.
     1451// 4) Depending on the socket state, it handle the received segment, including the
     1452//    SYN, FIN, ACK and RST flags. It updates the socket state when required, moves
     1453//    data to the rx_buf when possible, and registers requests to the TX server
     1454//    thread in the R2T queue attached to the socket, to insert control flags in the
     1455//    TX stream, as required.
     1456// 5) Finally, it releases the lock protecting the socke and returns.
     1457///////////////////////////////////////////////////////////////////////////////////////////
     1458// @ chdev         : [in] local pointer on local NIC_RX chdev descriptor.
     1459// @ k_buf         : [in] pointer on the TCP packet in local kernel buffer.
     1460// @ k_length      : [in] number of bytes in buffer (including TCP header).
     1461// @ seg_src_addr  : [in] source IP address (from IP packet header).
     1462// @ seg_dst_addr  : [in] destination IP address (from IP packet header).
     1463///////////////////////////////////////////////////////////////////////////////////////////
     1464static void dev_nic_rx_handle_tcp_segment( chdev_t  * chdev,
     1465                                           uint8_t  * k_buf,
     1466                                           uint32_t   k_length,
     1467                                           uint32_t   seg_src_addr,
     1468                                           uint32_t   seg_dst_addr )
     1469{
     1470    xptr_t     root_xp;           // extended pointer on attached sockets list root
     1471    xptr_t     lock_xp;           // extended pointer on chdev lock
     1472    xptr_t     iter_xp;           // iterator for these queues
     1473    bool_t     match_socket;      // true if socket found
     1474    xptr_t     socket_xp;         // extended pointer on matching socket descriptor
     1475    cxy_t      socket_cxy;
     1476    socket_t * socket_ptr;
     1477    uint32_t   local_addr;        // local IP address from socket
     1478    uint32_t   local_port;        // local port from socket
     1479    uint32_t   remote_addr;       // remote IP address from socket
     1480    uint32_t   remote_port;       // remote port from socket
     1481    uint32_t   socket_state;      // socket state
     1482    uint32_t   socket_type;       // socket type
     1483    uint32_t   socket_tx_nxt;    // next byte to send in TX stream
     1484    uint32_t   socket_tx_una;    // first unacknowledged byte in TX stream
     1485    uint32_t   socket_rx_nxt;    // next expected byte in RX stream
     1486    uint32_t   socket_rx_wnd;    // current window value in RX stream
     1487    xptr_t     socket_lock_xp;    // extended pointer on lock protecting socket state
     1488    xptr_t     socket_rx_buf_xp;  // extended pointer on socket rx_buf
     1489    xptr_t     socket_r2tq_xp;    // extended pointer on socket r2t queue
     1490    xptr_t     socket_client_xp;  // extended pointer on socket rx_client thread
     1491    uint16_t   checksum;          // computed TCP segment chechsum
     1492
     1493    // build extended pointer on xlist of all sockets attached to NIC_RX chdev
     1494    root_xp = XPTR( local_cxy , &chdev->wait_root );
     1495    lock_xp = XPTR( local_cxy , &chdev->wait_lock );
     1496
     1497    // get relevant infos from TCP segment header
     1498    uint32_t seg_src_port = ((uint32_t)k_buf[0] << 8) | (uint32_t)k_buf[1];
     1499    uint32_t seg_dst_port = ((uint32_t)k_buf[2] << 8) | (uint32_t)k_buf[3];
     1500
     1501    uint32_t seg_seq_num  = ((uint32_t)k_buf[4]  << 24) |
     1502                            ((uint32_t)k_buf[5]  << 16) |
     1503                            ((uint32_t)k_buf[6]  <<  8) |
     1504                            ((uint32_t)k_buf[7]       );
     1505
     1506    uint32_t seg_ack_num  = ((uint32_t)k_buf[8]  << 24) |
     1507                            ((uint32_t)k_buf[9]  << 16) |
     1508                            ((uint32_t)k_buf[10] <<  8) |
     1509                            ((uint32_t)k_buf[11]      );
     1510
     1511    uint8_t  seg_hlen     = k_buf[12] >> 2;       // TCP header length in bytes
     1512 
     1513    uint8_t  seg_flags    = k_buf[13];
     1514
     1515    bool_t   seg_ack_set  = ((seg_flags & TCP_FLAG_ACK) != 0);
     1516    bool_t   seg_syn_set  = ((seg_flags & TCP_FLAG_SYN) != 0);
     1517    bool_t   seg_fin_set  = ((seg_flags & TCP_FLAG_FIN) != 0);
     1518    bool_t   seg_rst_set  = ((seg_flags & TCP_FLAG_RST) != 0);
     1519
     1520    uint16_t seg_window   = ((uint32_t)k_buf[14] << 8) | (uint32_t)k_buf[15];
     1521
     1522    uint16_t seg_checksum = ((uint32_t)k_buf[16] << 8) | (uint32_t)k_buf[17];
     1523
     1524    uint32_t seg_payload  = k_length - seg_hlen;  // number of bytes in payload
     1525
     1526    // 1. compute TCP checksum
     1527    checksum = dev_nic_tcp_checksum( k_buf,
     1528                                     k_length,
     1529                                     seg_src_addr,
     1530                                     seg_dst_addr );
     1531
     1532    // discard segment if corrupted
     1533    if( seg_checksum != checksum ) return;
     1534   
     1535    match_socket = false;
     1536
     1537    // take the lock protecting the list of sockets
     1538    remote_busylock_acquire( lock_xp );
     1539
     1540    // 2. scan list of sockets to find a matching socket
     1541    XLIST_FOREACH( root_xp , iter_xp )
     1542    {
     1543        // get socket cluster and local pointer
     1544        socket_xp  = XLIST_ELEMENT( iter_xp , socket_t , rx_list );
     1545        socket_ptr = GET_PTR( socket_xp );
     1546        socket_cxy = GET_CXY( socket_xp );
     1547
     1548        // get socket type and state
     1549        socket_type  = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->type ));
     1550        socket_state = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->state ));
     1551               
     1552        // skip UDP socket
     1553        if( socket_type == SOCK_DGRAM ) continue;
     1554
     1555        // get relevant socket infos for matching
     1556        local_addr   = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->local_addr ));
     1557        remote_addr  = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->remote_addr ));
     1558        local_port   = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->local_port ));
     1559        remote_port  = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->remote_port ));
     1560               
     1561        // compute matching condition
     1562        // (in LISTEN state, remote_port and remote_addr can be unspecified)
     1563        if( socket_state == TCP_STATE_LISTEN )
     1564        {
     1565            match_socket = (local_addr  == seg_dst_addr) &&
     1566                           (local_port  == seg_dst_port) ;
     1567        }
     1568        else
     1569        {
     1570            match_socket = (local_addr  == seg_dst_addr) &&
     1571                           (local_port  == seg_dst_port) &&
     1572                           (remote_addr == seg_src_addr) &&
     1573                           (remote_port == seg_src_port) ;
     1574        }
     1575
     1576        // exit loop if matching
     1577        if( match_socket ) break;
     1578
     1579    }  // end loop on sockets
     1580
     1581    // release the lock protecting the list of sockets
     1582    remote_busylock_release( lock_xp );
     1583
     1584    // discard segment if no matching socket found
     1585    if( match_socket == false ) return;
     1586
     1587    // From here the actions depend on both the socket state,
     1588    // and the received segment flags
     1589    // - update socket state,
     1590    // - move data to rx_buf,
     1591    // - make a R2T request when required
     1592
     1593    // build extended pointers on various socket fields
     1594    socket_lock_xp    = XPTR( socket_cxy , &socket_ptr->lock );
     1595    socket_rx_buf_xp  = XPTR( socket_cxy , &socket_ptr->rx_buf );
     1596    socket_r2tq_xp    = XPTR( socket_cxy , &socket_ptr->r2tq );
     1597    socket_client_xp  = XPTR( socket_cxy , &socket_ptr->rx_client );
     1598
     1599    // 3. take the lock protecting the matching socket
     1600    remote_rwlock_wr_acquire( socket_lock_xp );
     1601
     1602    // get relevant socket infos from socket descriptor
     1603    socket_state   = hal_remote_l32(XPTR( socket_cxy , &socket_ptr->state ));
     1604    socket_rx_nxt = hal_remote_l32(XPTR( socket_cxy , &socket_ptr->rx_nxt ));
     1605    socket_rx_wnd = hal_remote_l32(XPTR( socket_cxy , &socket_ptr->rx_wnd ));
     1606    socket_tx_una = hal_remote_l32(XPTR( socket_cxy , &socket_ptr->tx_una ));
     1607    socket_tx_nxt = hal_remote_l32(XPTR( socket_cxy , &socket_ptr->tx_nxt ));
     1608
     1609    switch( socket_state )
     1610    {
     1611        //////////////////////
     1612        case TCP_STATE_LISTEN:
     1613        {
     1614            // [1] discard segment if RST flag
     1615            if( seg_rst_set )  return;
     1616
     1617            // [2] send a RST & discard segment if ACK flag
     1618            if( seg_ack_set )
     1619            {
     1620                    // set socket.tx_nxt to seg_ack_num
     1621                    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_nxt ),
     1622                                    seg_ack_num );
     1623
     1624                    // make RST request to R2T queue
     1625                    dev_nic_rx_put_r2t_request( socket_r2tq_xp,
     1626                                                TCP_FLAG_RST );
     1627                    // discard segment
     1628                    break;
     1629                }
     1630
     1631                // [3] handle SYN flag
     1632                if( seg_syn_set )
     1633                {
     1634                    // set socket.rx_nxt to seg_seq_num + 1
     1635                    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->rx_nxt ),
     1636                                    seg_seq_num + 1 );
     1637
     1638                    // set socket.tx_nxt to ISS
     1639                    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_nxt ),
     1640                                    TCP_ISS );
     1641
     1642                    // set socket.rx_irs to seg_seq_num
     1643                    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->rx_irs ),
     1644                                    seg_seq_num + 1 );
     1645
     1646                    // make SYN.ACK request to R2T queue
     1647                    dev_nic_rx_put_r2t_request( socket_r2tq_xp,
     1648                                                TCP_FLAG_SYN | TCP_FLAG_ACK );
     1649                     
     1650                    // set socket.tx_nxt to ISS + 1
     1651                    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_nxt ),
     1652                                    TCP_ISS + 1 );
     1653
     1654                    // set socket.tx_una to ISS
     1655                    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_una ),
     1656                                    TCP_ISS );
     1657           
     1658                    // update socket.state
     1659                    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ),
     1660                                    TCP_STATE_SYN_RCVD );
     1661
     1662                    // update socket.remote_addr
     1663                    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->remote_addr ),
     1664                                    seg_src_addr );
     1665
     1666                    // update socket.remote_port
     1667                    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->remote_port ),
     1668                                    seg_src_port );
     1669                }               
     1670                break;
     1671            }
     1672            ////////////////////////
     1673            case TCP_STATE_SYN_SENT:
     1674            {
     1675                // [1] check ACK flag
     1676                if( seg_ack_set )
     1677                {
     1678                    if( seg_ack_num != TCP_ISS + 1 )  // ACK not acceptable
     1679                    {
     1680                        // discard segment if RST
     1681                        if( seg_rst_set ) break;
     1682
     1683                        // set socket.tx_nxt to seg_ack_num
     1684                        hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_nxt ),
     1685                                        seg_ack_num );
     1686
     1687                        // make an RST request to R2T queue
     1688                        dev_nic_rx_put_r2t_request( socket_r2tq_xp,
     1689                                                    TCP_FLAG_RST );
     1690                        // discard segment
     1691                        break;
     1692                    }
     1693                }
     1694
     1695                // [2] check RST flag
     1696                if( seg_rst_set )
     1697                {
     1698                    // TODO signal "error: connection reset" to user
     1699
     1700                    // update socket.state
     1701                    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ),
     1702                                    TCP_STATE_BOUND );
     1703
     1704                    // discard segment
     1705                    break;
     1706                }
     1707
     1708                // [3] handle SYN flag when (no ACK or acceptable ACK, and no RST)
     1709                if( seg_syn_set )
     1710                {
     1711                    // TODO Ne faut-il pas tester seg_seq_num ?
     1712
     1713                    if( seg_ack_set )  // received both SYN and ACK
     1714                    {
     1715                        // set socket.rx_nxt to seg_seq_num + 1
     1716                        hal_remote_s32( XPTR( socket_cxy , &socket_ptr->rx_nxt ),
     1717                                        seg_seq_num + 1 );
     1718
     1719                        // set socket.tx_una to seg_ack_num
     1720                        hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_una ),
     1721                                        seg_ack_num );
     1722
     1723                        // set socket.rx_irs to seg_seq_num
     1724                        hal_remote_s32( XPTR( socket_cxy , &socket_ptr->rx_irs ),
     1725                                        seg_seq_num );
     1726
     1727                        // update socket.state
     1728                        hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ),
     1729                                        TCP_STATE_ESTAB );
     1730
     1731                        // make an ACK request to R2T queue
     1732                        dev_nic_rx_put_r2t_request( socket_r2tq_xp,
     1733                                                    TCP_FLAG_ACK );
     1734                    }
     1735                    else               // received SYN without ACK
     1736                    {
     1737                        // update socket.state
     1738                        hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ),
     1739                                        TCP_STATE_SYN_RCVD );
     1740
     1741                        // set socket.tx_nxt to ISS
     1742                        hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_nxt ),
     1743                                        TCP_ISS );     
     1744
     1745                        // make a SYN.ACK request to R2T queue
     1746                        dev_nic_rx_put_r2t_request( socket_r2tq_xp,
     1747                                                    TCP_FLAG_SYN | TCP_FLAG_ACK );
     1748                    }
     1749                }
     1750                break;
     1751            }
     1752            ////////////////////////
     1753            case TCP_STATE_SYN_RCVD:
     1754            case TCP_STATE_ESTAB:
     1755            case TCP_STATE_FIN_WAIT1:
     1756            case TCP_STATE_FIN_WAIT2:
     1757            case TCP_STATE_CLOSE_WAIT:
     1758            case TCP_STATE_CLOSING:
     1759            case TCP_STATE_LAST_ACK:
     1760            case TCP_STATE_TIME_WAIT:
     1761            {
     1762                // [1] check sequence number
     1763
     1764                // compute min & max acceptable sequence numbers
     1765                uint32_t seq_min  = socket_rx_nxt;
     1766                uint32_t seq_max  = socket_rx_nxt + socket_rx_wnd - 1;
     1767
     1768                // compute sequence number for last byte in segment
     1769                uint32_t seg_seq_last = seg_seq_num + seg_payload - 1;
     1770
     1771                if( (seg_seq_num != socket_rx_nxt) ||     // out_of_order
     1772                    (is_in_window( seg_seq_last,
     1773                                   seq_min,
     1774                                   seq_max ) == false) )  // out_of_window
     1775                {
     1776                    // discard segment
     1777                    return;
     1778                }
     1779
     1780                // [2] handle RST flag
     1781
     1782                if( seg_rst_set )
     1783                {
     1784                     if( socket_state == TCP_STATE_SYN_RCVD )
     1785                     {
     1786                         // TODO unblock all clients threads with "reset" responses
     1787                     }
     1788                     else if( (socket_state == TCP_STATE_ESTAB     ) ||
     1789                              (socket_state == TCP_STATE_FIN_WAIT1 ) ||
     1790                              (socket_state == TCP_STATE_FIN_WAIT2 ) ||
     1791                              (socket_state == TCP_STATE_CLOSE_WAIT) )
     1792                     {
     1793                         // TODO all pending send & received commands
     1794                         // must receive "reset" responses
     1795
     1796                         // TODO destroy the socket
     1797                     }
     1798                     else  // all other states
     1799                     {
     1800                             
     1801
     1802                }
     1803
     1804                // [3] handle security & precedence TODO ... someday
     1805
     1806                // [4] handle SYN flag
     1807
     1808                if( seg_syn_set )        // received SYN
     1809                {
     1810                    // TODO signal error to user
     1811
     1812                    // make an RST request to R2T queue
     1813                    dev_nic_rx_put_r2t_request( socket_r2tq_xp,
     1814                                                TCP_FLAG_RST );
     1815                    // update socket state
     1816                    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ),
     1817                                    TCP_STATE_BOUND );
     1818                }
     1819
     1820                // [5] handle  ACK flag
     1821
     1822                if( seg_ack_set == false )
     1823                {
     1824                    // discard segment when ACK not set
     1825                    break;
     1826                }
     1827                else if( socket_state == TCP_STATE_SYN_RCVD )
     1828                {
     1829                    if( is_in_window( seg_ack_num , socket_tx_una , socket_tx_nxt ) )
     1830                    {
     1831                        // update socket.state to ESTAB
     1832                        hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ),
     1833                                              TCP_STATE_ESTAB );
     1834                    }
     1835                    else   // unacceptable ACK
     1836                    {
     1837                        // set socket.tx_nxt to seg_ack_num
     1838                        hal_remote_s32( XPTR( socket_cxy , &socket_ptr->rx_nxt ),
     1839                                        seg_ack_num );
     1840
     1841                        // make an RST request to R2T queue
     1842                        dev_nic_rx_put_r2t_request( socket_r2tq_xp,
     1843                                                    TCP_FLAG_RST );
     1844                    }
     1845                }
     1846                else if( (socket_state == TCP_STATE_ESTAB)      ||
     1847                         (socket_state == TCP_STATE_FIN_WAIT1)  ||
     1848                         (socket_state == TCP_STATE_FIN_WAIT1)  ||
     1849                         (socket_state == TCP_STATE_CLOSE_WAIT) ||
     1850                         (socket_state == TCP_STATE_CLOSING)    )
     1851                {
     1852                    if( is_in_window( seg_ack_num + 1 , socket_tx_una , socket_tx_nxt ) )
     1853                    {
     1854                        // update socket.tx_una
     1855                        hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_una ),
     1856                                        seg_ack_num );
     1857
     1858                        // update socket.tx_wnd 
     1859                        hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_wnd ),
     1860                                        seg_window );
     1861                    }
     1862                    else   // unacceptable ACK
     1863                    {
     1864                        // discard segment
     1865                        break;
     1866                    }
     1867               
     1868                    // specific for FIN_WAIT1
     1869                    if( socket_state == TCP_STATE_FIN_WAIT1 )
     1870                    {
     1871                        if( seg_fin_set )
     1872                        {
     1873                            // update socket.state
     1874                            hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ),
     1875                                                  TCP_STATE_FIN_WAIT2 );
     1876                        }
     1877                    }
     1878
     1879                    // specific for CLOSING
     1880                    if( socket_state == TCP_STATE_CLOSING )
     1881                    {
     1882                        if( seg_ack_set )
     1883                        {
     1884                            // update socket.state
     1885                            hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ),
     1886                                                  TCP_STATE_TIME_WAIT );
     1887                        }
     1888                        else
     1889                        {
     1890                            // discard segment
     1891                            break;
     1892                        }
     1893                    }
     1894                }
     1895                else if( socket_state == TCP_STATE_LAST_ACK )
     1896                {
     1897                    if( seg_ack_set )
     1898                    {
     1899                        // update socket.state
     1900                        hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ),
     1901                                              TCP_STATE_TIME_WAIT );
     1902                    }
     1903                   
     1904                }
     1905
     1906                // [6] handle URG flag  TODO ... someday
     1907
     1908                // [7] Move DATA to rx_buf and unblock client thread
     1909
     1910                if( seg_payload )
     1911                {
     1912                    if( (socket_state == TCP_STATE_ESTAB)     ||
     1913                        (socket_state == TCP_STATE_FIN_WAIT1) ||
     1914                        (socket_state == TCP_STATE_FIN_WAIT2) )
     1915                    {
     1916                        // get number of bytes already stored in rx_buf
     1917                        uint32_t status = remote_buf_status( socket_rx_buf_xp );
     1918
     1919                        // compute empty space in rx_buf
     1920                        uint32_t space = NIC_RX_BUF_SIZE - status;
     1921
     1922                        // compute number of bytes to move : min (space , seg_payload)
     1923                        uint32_t nbytes = ( space < seg_payload ) ? space : seg_payload;
     1924
     1925                        // move payload from k_buf to rx_buf
     1926                        remote_buf_put_from_kernel( socket_rx_buf_xp,
     1927                                                    k_buf + seg_hlen,
     1928                                                    nbytes );
     1929                        // update socket.rx_nxt
     1930                        hal_remote_s32( XPTR( socket_cxy , &socket_ptr->rx_nxt ),
     1931                                              socket_rx_nxt + nbytes );
     1932
     1933                        // update socket.rx_wnd
     1934                        hal_remote_s32( XPTR( socket_cxy , &socket_ptr->rx_wnd ),
     1935                                        socket_rx_wnd - nbytes );
     1936
     1937                        // make an ACK request to R2T queue
     1938                        dev_nic_rx_put_r2t_request( socket_r2tq_xp,
     1939                                                    TCP_FLAG_ACK );
     1940
     1941                        // get extended pointer on rx_client thread
     1942                        xptr_t client_xp = hal_remote_l64( socket_client_xp );
     1943                       
     1944                        // unblock client thread
     1945                        if( client_xp != XPTR_NULL )
     1946                        {
     1947                            thread_unblock( client_xp , THREAD_BLOCKED_IO );
     1948                        }
     1949                    }
     1950                }
     1951
     1952                // [8] handle FIN flag
     1953
     1954                if( seg_fin_set )
     1955                {
     1956                    if( (socket_state == TCP_STATE_UNBOUND) ||
     1957                        (socket_state == TCP_STATE_BOUND)   ||
     1958                        (socket_state == TCP_STATE_LISTEN)  ||
     1959                        (socket_state == TCP_STATE_SYN_SENT) )
     1960                    {
     1961                        // discard segment
     1962                        break;
     1963                    }
     1964                    else // all other states
     1965                    {
     1966                        // TODO signal "connection closing"
     1967
     1968                        // make an ACK request to R2T queue
     1969                        dev_nic_rx_put_r2t_request( socket_r2tq_xp,
     1970                                                    TCP_FLAG_ACK );
     1971
     1972                        // increment socket.rx_nxt
     1973                        hal_remote_s32( XPTR( socket_cxy , &socket_ptr->rx_nxt ),
     1974                                        socket_rx_nxt + 1 );
     1975
     1976                        if( (socket_state == TCP_STATE_SYN_RCVD) ||
     1977                            (socket_state == TCP_STATE_ESTAB) )
     1978                        {
     1979                            // update socket.state
     1980                            hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ),
     1981                                            TCP_STATE_TIME_WAIT );
     1982                        }
     1983                        else if( socket_state == TCP_STATE_FIN_WAIT1 )
     1984                        {
     1985                            if( seg_ack_set )
     1986                            {
     1987                                // TODO start "time-wait" timer / turn off others timers
     1988
     1989                                // update socket.state
     1990                                hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ),
     1991                                                TCP_STATE_TIME_WAIT );
     1992                            }
     1993                            else
     1994                            {
     1995                                // update socket.state
     1996                                hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ),
     1997                                                TCP_STATE_CLOSING );
     1998                            }
     1999                        }
     2000                        else if( socket_state == TCP_STATE_FIN_WAIT2 )
     2001                        {
     2002                            // TODO start "time-wait" timer / turn off other timers
     2003
     2004                            // update socket.state
     2005                            hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ),
     2006                                            TCP_STATE_TIME_WAIT );
     2007                        }
     2008                        else if( socket_state == TCP_STATE_TIME_WAIT )
     2009                        {
     2010                            // TODO restart "time_wait" timer
     2011                        }
     2012                    }
     2013                }  // end if FIN
     2014            }  // end case sockets synchronized
     2015        }  // end switch socket state
     2016
     2017        // release the lock protecting socket
     2018        remote_rwlock_wr_acquire( socket_lock_xp );
     2019
     2020    }  // end socket found
     2021
     2022}  // end dev_nic_rx_handle_tcp_segment()
     2023
     2024
     2025/////////////////////////////////////////
     2026void dev_nic_rx_server( chdev_t * chdev )
     2027{
     2028    uint8_t       k_buf[2048];          // kernel buffer for one ETH/IP/UDP packet
     2029                                 
     2030    uint32_t      pkt_src_addr;         // packet source IP address
     2031    uint32_t      pkt_dst_addr;         // packet destination IP address
     2032    uint32_t      trsp_protocol;        // transport protocol (TCP / UDP)
     2033    uint32_t      eth_length;           // size of Ethernet packet (bytes)
     2034    uint32_t      ip_length;            // size of IP packet in bytes
     2035    uint32_t      nic_queue_readable;   // NIC_RX queue non empty when true
     2036    error_t       error;
     2037
     2038    thread_t * this = CURRENT_THREAD;
     2039
     2040// check chdev direction and type
     2041assert( (chdev->func == DEV_FUNC_NIC) && (chdev->is_rx == true) ,
     2042"illegal chdev type or direction" );
    1772043
    1782044// check thread can yield
    179 assert( (thread_ptr->busylocks == 0),
    180 "cannot yield : busylocks = %d\n", thread_ptr->busylocks );
     2045assert( (this->busylocks == 0),
     2046"cannot yield : busylocks = %d\n", this->busylocks );
     2047
     2048    while( 1 )
     2049    {
     2050        // check NIC_RX_QUEUE readable
     2051        error = dev_nic_rx_queue_readable( chdev,
     2052                                           &nic_queue_readable );
     2053        if( error )
     2054        {
     2055            printk("\n[PANIC] in %s : cannot access NIC_TX[%d] queue\n",
     2056            __FUNCTION__, chdev->channel );
     2057        }
     2058   
     2059        if( nic_queue_readable ) // NIC_TX_QUEUE non empty
     2060        {
     2061            // moves one Ethernet packet to kernel buffer
     2062            error = dev_nic_rx_move_packet( chdev,
     2063                                            k_buf,
     2064                                            &eth_length );
     2065            if( error )
     2066            {
     2067                printk("\n[PANIC] in %s : cannot read the NIC_TX[%d] queue\n",
     2068                __FUNCTION__, chdev->channel );
     2069            }
     2070
     2071            // analyse the ETH header
     2072            error = dev_nic_rx_check_eth( k_buf,
     2073                                          &ip_length );
     2074
     2075            // discard packet if error reported by Ethernet layer
     2076            if( error ) continue;
     2077
     2078            // analyse the IP header
     2079            error = dev_nic_rx_check_ip( k_buf + ETH_HEAD_LEN,
     2080                                         ip_length,
     2081                                         &pkt_src_addr,
     2082                                         &pkt_dst_addr,
     2083                                         &trsp_protocol );
     2084
     2085            // discard packet if error reported by IP layer
     2086            if( error ) continue;
     2087
     2088            // call relevant transport protocol
     2089            if( trsp_protocol == PROTOCOL_UDP )   
     2090            {
     2091                dev_nic_rx_handle_udp_packet( chdev,
     2092                                              k_buf + ETH_HEAD_LEN + IP_HEAD_LEN,
     2093                                              ip_length - IP_HEAD_LEN,
     2094                                              pkt_src_addr,
     2095                                              pkt_dst_addr );
     2096            }
     2097            else if ( trsp_protocol == PROTOCOL_TCP)
     2098            {
     2099                dev_nic_rx_handle_tcp_segment( chdev,
     2100                                               k_buf + ETH_HEAD_LEN + IP_HEAD_LEN,
     2101                                               ip_length - IP_HEAD_LEN,
     2102                                               pkt_src_addr,
     2103                                               pkt_dst_addr );
     2104            }
     2105        }
     2106        else     // block and deschedule if NIC_RX_QUEUE empty
     2107        {
     2108            thread_block( XPTR( local_cxy , this ) , THREAD_BLOCKED_ISR );
     2109            sched_yield( "waiting RX client" );
     2110        }
     2111
     2112    } // end of while loop
     2113
     2114}  // end dev_nic_rx_server()
     2115
     2116
     2117
     2118
     2119
     2120
     2121
     2122
     2123
     2124
     2125///////////////////////////////////////////////////////////////////////////////////////////
     2126//              Functions used by the NIC_TX server thread
     2127///////////////////////////////////////////////////////////////////////////////////////////
     2128
     2129
     2130///////////////////////////////////////////////////////////////////////////////////////////
     2131// These static functions are called by the NIC_TX server thread to report the
     2132// completion  (success or error) of a TX command.
     2133// - it print an error message in case of error.
     2134// - it updates the "tx_error"  field in socket descriptor.
     2135// - it unblocks the client thread.
     2136///////////////////////////////////////////////////////////////////////////////////////////
     2137// @ socket_xp    : [in] extended pointer on socket
     2138// @ cmd_type     : [in] SOCKET_TX_CONNECT / SOCKET_TX_SEND / SOCKET_TX_CLOSE
     2139// @ socket_state : [in] current socket state
     2140///////////////////////////////////////////////////////////////////////////////////////////
     2141static void dev_nic_tx_report_error( xptr_t    socket_xp,
     2142                                     uint32_t  cmd_type,
     2143                                     uint32_t  socket_state )
     2144{
     2145    printk("\n[ERROR] in %s : command %s in %s state\n",
     2146    __FUNCTION__, socket_cmd_str(cmd_type), socket_state_str(socket_state) );
     2147
     2148    // get socket thread cluster and local pointer
     2149    socket_t * socket_ptr = GET_PTR( socket_xp );
     2150    cxy_t      socket_cxy = GET_CXY( socket_xp );
     2151
     2152    // set tx_error field in socket descriptor
     2153    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_error ) , 1 );
     2154
     2155    // get extended point on client thread
     2156    xptr_t client_xp = hal_remote_l64( XPTR( socket_cxy , &socket_ptr->tx_client ));
     2157
     2158    // unblock the client thread
     2159    thread_unblock( client_xp , THREAD_BLOCKED_IO );
     2160}
     2161
     2162////////////////////////////////////////////////////////////
     2163static void dev_nic_tx_report_success( xptr_t    socket_xp )
     2164{
     2165    // get socket thread cluster and local pointer
     2166    socket_t * socket_ptr = GET_PTR( socket_xp );
     2167    cxy_t      socket_cxy = GET_CXY( socket_xp );
     2168
     2169    // set tx_error field in socket descriptor
     2170    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_error ) , 0 );
     2171
     2172    // get extended point on client thread
     2173    xptr_t client_xp = hal_remote_l64( XPTR( socket_cxy , &socket_ptr->tx_client ));
     2174
     2175    // unblock the client thread
     2176    thread_unblock( client_xp , THREAD_BLOCKED_IO );
     2177}
     2178
     2179
     2180
     2181
     2182
     2183///////////////////////////////////////////////////////////////////////////////////////////
     2184// This static function is called by the dev_nic_tx_server() function.
     2185// It calls directly the NIC driver (WRITABLE command) and returns the status
     2186// of the NIC_TX queue identified by the <chdev> argument.
     2187// in the <writable> buffer.
     2188///////////////////////////////////////////////////////////////////////////////////////////
     2189// @ chdev     : [in]  local pointer on NIC_TX chdev.
     2190// @ length    : [in]  packet length in bytes.
     2191// @ writable  : [out] zero if queue full. 
     2192// @ returns 0 if success / returns -1 if failure in accessing NIC device.
     2193///////////////////////////////////////////////////////////////////////////////////////////
     2194error_t dev_nic_tx_queue_writable( chdev_t  * chdev,
     2195                                   uint32_t   length,
     2196                                   uint32_t * writable )
     2197{
     2198    thread_t * this = CURRENT_THREAD;
     2199
     2200    // initialize READABLE command in thread descriptor
     2201    this->nic_cmd.dev_xp = XPTR( local_cxy , chdev );
     2202    this->nic_cmd.type   = NIC_CMD_WRITABLE;
     2203    this->nic_cmd.length = length;
     2204
     2205    // call driver to test writable
     2206    chdev->cmd( XPTR( local_cxy , this ) );
     2207
     2208    // return status
     2209    *writable = this->nic_cmd.status;
     2210
     2211    // return error
     2212    return this->nic_cmd.error;
     2213
     2214}  // end dev_nic_tx_queue_writable
     2215
     2216///////////////////////////////////////////////////////////////////////////////////////////
     2217// This static function is called by the dev_nic_tx_server() function.
     2218// It moves one ETH/IP/UDP packet from the kernel buffer identified by the <buffer> and
     2219// <length> arguments to the NIC_TX_QUEUE identified the <chdev> argument.
     2220// It calls directly the NIC driver, without registering in a waiting queue, because
     2221// only this NIC_TX server thread can access this NIC_TX_QUEUE.
     2222// 1) It checks NIC_TX_QUEUE status in a while loop, using the NIC_CMD_WRITABLE command.
     2223//    As long as the queue is not writable, it blocks and deschedules. It is re-activated
     2224//    by the NIC-TX ISR as soon as the queue changes status.
     2225// 2) When the queue is writable, it put the ETH/IP/UDP packet into the NIC_TX_QUEUE,
     2226//   using the driver NIC_CMD_WRITE command.
     2227// Both commands are successively registered in this NIC-TX server thread descriptor
     2228// to be passed to the driver.
     2229///////////////////////////////////////////////////////////////////////////////////////////
     2230// @ chdev   : [in] local pointer on NIC_TX chdev.
     2231// @ buffer  : [in] pointer on a local kernel buffer (2K bytes).
     2232// @ length  : [in] actual Ethernet packet length in bytes.
     2233///////////////////////////////////////////////////////////////////////////////////////////
     2234void dev_nic_tx_move_packet( chdev_t  * chdev,
     2235                             uint8_t  * buffer,
     2236                             uint32_t   length )
     2237{
     2238    error_t    error;
     2239    uint32_t   writable;
     2240
     2241    thread_t * this = CURRENT_THREAD;
     2242
     2243    // get extended pointers on server tread and chdev
     2244    xptr_t     thread_xp = XPTR( local_cxy , this );
     2245    xptr_t     chdev_xp  = XPTR( local_cxy , chdev );
     2246
     2247    // get local pointer on core running this server thead
     2248    core_t * core = this->core;
     2249
     2250// check thread can yield
     2251assert( (this->busylocks == 0),
     2252"cannot yield : busylocks = %d\n", this->busylocks );
    1812253
    1822254#if DEBUG_DEV_NIC_RX
    1832255uint32_t cycle = (uint32_t)hal_get_cycles();
    1842256if( DEBUG_DEV_NIC_RX < cycle )
    185 printk("\n[DBG] %s : thread %x enters for packet %x in cluster %x\n",
    186 __FUNCTION__ , thread_ptr , pkd , local_cxy );
     2257printk("\n[%s] thread[%x,%x] enters for packet %x / cycle %d\n",
     2258__FUNCTION__, this->process->pid, this->trdid, pkd, cycle );
    1872259#endif
    1882260
    189     // get pointer on NIC-TX chdev descriptor
    190     uint32_t   channel = thread_ptr->chdev->channel;
    191     xptr_t     dev_xp  = chdev_dir.nic_tx[channel];
    192     cxy_t      dev_cxy = GET_CXY( dev_xp );
    193     chdev_t  * dev_ptr = (chdev_t *)GET_PTR( dev_xp );
    194 
    195     assert( (dev_xp != XPTR_NULL) , "undefined NIC chdev descriptor" );
    196 
    197     assert( (dev_cxy == local_cxy) , " chdev must be local" );
    198 
    199     // initialize command in thread descriptor
    200     thread_ptr->nic_cmd.dev_xp = dev_xp;
    201 
    202     // call driver to test writable
    203     thread_ptr->nic_cmd.cmd = NIC_CMD_WRITABLE;
    204     dev_ptr->cmd( thread_xp );
    205 
    206     // check error
    207     error = thread_ptr->nic_cmd.error;
    208     if( error ) return error;
    209 
    210     // block and deschedule if queue non writable
    211     if( thread_ptr->nic_cmd.status == false ) 
    212     {
    213         // enable NIC-TX IRQ
    214         dev_pic_enable_irq( core->lid ,dev_xp );
    215 
    216         // block client thread on THREAD_BLOCKED I/O condition
    217         thread_block( XPTR( local_cxy , thread_ptr ) , THREAD_BLOCKED_IO );
    218 
    219         // deschedule client thread
    220         sched_yield("client blocked on I/O");
    221 
    222         // disable NIC-TX IRQ
    223         dev_pic_disable_irq( core->lid , dev_xp );
    224     }
    225 
    226     // call driver for actual write
    227     thread_ptr->nic_cmd.cmd    = NIC_CMD_WRITE;
    228     thread_ptr->nic_cmd.buffer = pkd->buffer;
    229     thread_ptr->nic_cmd.length = pkd->length;
    230     dev_ptr->cmd( thread_xp );
    231 
    232     // check error
    233     error = thread_ptr->nic_cmd.error;
    234     if( error ) return error;
     2261    // check NIC_TX_QUEUE writable
     2262    while( 1 )
     2263    {
     2264        error = dev_nic_tx_queue_writable( chdev,
     2265                                           length,
     2266                                           &writable );
     2267        if( error )
     2268        {
     2269            printk("\n[PANIC] in %s : cannot access NIC_TX queue\n", __FUNCTION__ );
     2270            return;
     2271        }
     2272           
     2273        if( writable == 0 )  // block & deschedule if non writable
     2274        {
     2275            // enable NIC-TX IRQ
     2276            dev_pic_enable_irq( core->lid , chdev_xp );
     2277
     2278            // block TX server thread
     2279            thread_block( thread_xp , THREAD_BLOCKED_ISR );
     2280
     2281            // deschedule TX server thread
     2282            sched_yield("client blocked on NIC_TX queue full");
     2283
     2284            // disable NIC-TX IRQ
     2285            dev_pic_disable_irq( core->lid , chdev_xp );
     2286        }
     2287        else                // exit loop if writable
     2288        {
     2289            break;
     2290        }
     2291    }
     2292
     2293    // initialize WRITE command in server thread descriptor
     2294    this->nic_cmd.dev_xp = chdev_xp;
     2295    this->nic_cmd.type   = NIC_CMD_WRITE;
     2296    this->nic_cmd.buffer = buffer;
     2297    this->nic_cmd.length = length;
     2298
     2299    // call driver to move packet
     2300    chdev->cmd( thread_xp );
    2352301
    2362302#if DEBUG_DEV_NIC_RX
    2372303cycle = (uint32_t)hal_get_cycles();
    2382304if( DEBUG_DEV_NIC_RX < cycle )
    239 printk("\n[DBG] %s : thread %x exit for packet %x in cluster %x\n",
    240 __FUNCTION__ , thread_ptr , pkd , local_cxy );
     2305printk("\n[%s] thread[%x,%x] exit for packet %x\n",
     2306__FUNCTION__ , this->process->pid, this->trdid , pkd );
    2412307#endif
    2422308
    243     return 0;
    244 }  // end dev_nic_write()
    245 
    246 
    247 
     2309    return;
     2310
     2311}  // end dev_nic_tx_move_packet()
     2312
     2313///////////////////////////////////////////////////////////////////////////////////////////
     2314// This static function is called by the dev_nic_tx_server() function to build an UDP
     2315// header in the kernel buffer defined by the <k_buf> arguement,  as specified by the
     2316// <socket_xp> argument. The <length> argument defines the number of bytes in payload.
     2317// It set the "src_port", "dst_port", "total_length" and "checksum" fields in UDP header.
     2318// The payload must be previouly loaded in the pernel buffer.
     2319///////////////////////////////////////////////////////////////////////////////////////////
     2320// @ k_buf      : [in]  pointer on first byte of UDP header in kernel buffer.
     2321// @ socket_xp  : [in]  extended pointer on socket.
     2322// @ length     : [in]  number of bytes in payload.
     2323///////////////////////////////////////////////////////////////////////////////////////////
     2324void dev_nic_tx_build_udp_header( uint8_t  * k_buf,
     2325                                  xptr_t     socket_xp,
     2326                                  uint32_t   length )
     2327{
     2328    uint16_t   checksum;        // checksum value
     2329    uint32_t   total_length;    // total UDP packet length
     2330    uint32_t   local_addr;      // local IP address
     2331    uint32_t   remote_addr;     // remote IP address
     2332    uint32_t   local_port;      // local port
     2333    uint32_t   remote_port;     // remote port
     2334
     2335    // get socket cluster an local pointer
     2336    socket_t * socket_ptr = GET_PTR( socket_xp );
     2337    cxy_t      socket_cxy = GET_CXY( socket_xp );
     2338
     2339    // get relevant infos from socket
     2340    local_addr  = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->local_addr ));
     2341    remote_addr = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->remote_addr ));
     2342    local_port  = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->local_port ));
     2343    remote_port = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->remote_port ));
     2344
     2345    // compute UDP packet total length
     2346    total_length = length + UDP_HEAD_LEN;
     2347
     2348    // set src_port and dst_port in header
     2349    k_buf[0] = local_port >> 8;
     2350    k_buf[1] = local_port;
     2351    k_buf[2] = remote_port >> 8;
     2352    k_buf[3] = remote_port;
     2353
     2354    // set packet length in header
     2355    k_buf[4] = total_length >> 8;
     2356    k_buf[5] = total_length;
     2357   
     2358    // compute UDP packet checksum
     2359    checksum = dev_nic_udp_checksum( k_buf , total_length );
     2360
     2361    // set checksum
     2362    k_buf[6] = checksum >> 8;
     2363    k_buf[7] = checksum;
     2364
     2365}  // end dev_nic_tx_build_udp_header()
     2366
     2367///////////////////////////////////////////////////////////////////////////////////////////
     2368// This static function is called by the dev_nic_tx_server() function.
     2369// It builds a TCP header in the kernel buffer defined by the <k_buf> argument.
     2370// The payload must have been previouly registered in this buffer.
     2371// The "local_addr", "local_port", "remote_addr", "remote_port", seq_num", "ack_num",
     2372// and "window" fields are obtained from the <socket_xp> argument.
     2373// The <length> argument defines the number of bytes in payload, and the <flags> argument
     2374// defines the flags to be set in TCP header.
     2375///////////////////////////////////////////////////////////////////////////////////////////
     2376// @ k_buf      : [in]  pointer on first byte of TCP header in kernel buffer.
     2377// @ length     : [in]  number of bytes in payload.
     2378// @ socket_xp  : [in]  extended pointer on socket.
     2379// @ flags      : [in]  flags to be set in TCP header.
     2380///////////////////////////////////////////////////////////////////////////////////////////
     2381void dev_nic_tx_build_tcp_header( uint8_t  * k_buf,
     2382                                  uint32_t   length,
     2383                                  xptr_t     socket_xp,
     2384                                  uint8_t    flags )
     2385{
     2386    uint16_t   checksum;        // global segment checksum
     2387    uint32_t   total_length;    // total UDP packet length
     2388    uint32_t   src_addr;        // local IP address
     2389    uint32_t   dst_addr;        // remote IP address
     2390    uint16_t   src_port;        // local port
     2391    uint16_t   dst_port;        // remote port
     2392    uint32_t   seq_num;         // first byte of segment in TX stream
     2393    uint32_t   ack_num;         // next expected byte in RX stream
     2394    uint16_t   window;          // window of accepted segments in RX stream
     2395
     2396    // get socket cluster an local pointer
     2397    socket_t * sock_ptr = GET_PTR( socket_xp );
     2398    cxy_t      sock_cxy = GET_CXY( socket_xp );
     2399
     2400    // get relevant infos from socket
     2401    src_addr = hal_remote_l32(XPTR( sock_cxy , &sock_ptr->local_addr ));
     2402    dst_addr = hal_remote_l32(XPTR( sock_cxy , &sock_ptr->remote_addr ));
     2403    src_port = hal_remote_l32(XPTR( sock_cxy , &sock_ptr->local_port ));
     2404    dst_port = hal_remote_l32(XPTR( sock_cxy , &sock_ptr->remote_port ));
     2405    seq_num  = hal_remote_l32(XPTR( sock_cxy , &sock_ptr->tx_nxt ));
     2406    ack_num  = hal_remote_l32(XPTR( sock_cxy , &sock_ptr->rx_nxt ));
     2407    window   = hal_remote_l32(XPTR( sock_cxy , &sock_ptr->rx_wnd ));
     2408
     2409    // compute TCP segment total length
     2410    total_length = length + TCP_HEAD_LEN;
     2411
     2412    // set "src_port" and "dst_port"
     2413    k_buf[0]  = src_port >> 8;
     2414    k_buf[1]  = src_port;
     2415    k_buf[2]  = dst_port >> 8;
     2416    k_buf[3]  = dst_port;
     2417
     2418    // set "seq_num" 
     2419    k_buf[4]  = seq_num >> 24;
     2420    k_buf[5]  = seq_num >> 16;
     2421    k_buf[6]  = seq_num >>  8;
     2422    k_buf[7]  = seq_num;
     2423
     2424    // set "ack_num" 
     2425    k_buf[8]  = ack_num >> 24;
     2426    k_buf[9]  = ack_num >> 16;
     2427    k_buf[10] = ack_num >>  8;
     2428    k_buf[11] = ack_num;
     2429
     2430    // set "hlen"
     2431    k_buf[12] = 5;
     2432
     2433    // set "flags"
     2434    k_buf[13] = flags & 0x3F;
     2435
     2436    // set "window"
     2437    k_buf[14] = window >> 8;
     2438    k_buf[15] = window;
     2439
     2440    // reset "checksum"
     2441    k_buf[16] = 0;
     2442    k_buf[17] = 0;
     2443   
     2444    // set "urgent_ptr"
     2445    k_buf[18] = 0;
     2446    k_buf[19] = 0;
     2447 
     2448    // compute TCP segment checksum
     2449    checksum = dev_nic_tcp_checksum( k_buf,
     2450                                     total_length,
     2451                                     src_addr,
     2452                                     dst_addr );
     2453    // set "checksum"
     2454    k_buf[16] = checksum >> 8;
     2455    k_buf[17] = checksum;
     2456
     2457}  // end dev_nic_tx_build_tcp_header()
     2458
     2459
     2460///////////////////////////////////////////////////////////////////////////////////////////
     2461// This static function is called by the dev_nic_tx_server() function.
     2462// It builds the IP header in the 20 first bytes of <buffer>.
     2463///////////////////////////////////////////////////////////////////////////////////////////
     2464// @ buffer     : pointer on first byte of IP header in kernel buffer
     2465// @ src_addr   : source IP address.
     2466// @ dst_addr   : destination IP address.
     2467// @ length     : number of bytes in IP packet payload.
     2468///////////////////////////////////////////////////////////////////////////////////////////
     2469void dev_nic_tx_build_ip_header( uint8_t * buffer,
     2470                                 uint32_t  src_addr,
     2471                                 uint32_t  dst_addr,
     2472                                 uint16_t  length )
     2473{
     2474    uint16_t   hcs;
     2475
     2476    uint16_t   total = length + IP_HEAD_LEN;
     2477
     2478    buffer[0]  = 0x45;         // IPV4 / IHL = 20 bytes 
     2479    buffer[1]  = 0;            // DSCP / ECN
     2480    buffer[2]  = total >> 8; 
     2481    buffer[3]  = total; 
     2482
     2483    buffer[4]  = 0x40;         // Don't Fragment
     2484    buffer[5]  = 0;
     2485    buffer[6]  = 0;
     2486    buffer[7]  = 0;
     2487
     2488    buffer[8]  = 0xFF;         // TTL
     2489    buffer[9]  = 0x11;         // UDP protocol
     2490   
     2491    buffer[12] = src_addr >> 24;
     2492    buffer[13] = src_addr >> 16;
     2493    buffer[14] = src_addr >> 8;
     2494    buffer[15] = src_addr;
     2495
     2496    buffer[16] = dst_addr >> 24;
     2497    buffer[17] = dst_addr >> 16;
     2498    buffer[18] = dst_addr >> 8;
     2499    buffer[19] = dst_addr;
     2500
     2501    // compute IP header checksum
     2502    hcs = dev_nic_ip_checksum( buffer );
     2503
     2504    // set checksum
     2505    buffer[10] = hcs >> 8;
     2506    buffer[11] = hcs;
     2507
     2508}  // end dev_nic_tx_build_ip_header
     2509
     2510///////////////////////////////////////////////////////////////////////////////////////////
     2511// This static function is called by the dev_nic_tx_server() function.
     2512// It builds the Ethernet header in the 14 first bytes of <buffer>.
     2513///////////////////////////////////////////////////////////////////////////////////////////
     2514// @ buffer     : pointer on first byte of Ethernet header in kernel buffer
     2515// @ src_mac_54 : two MSB bytes in source MAC address.
     2516// @ src_mac_32 : two MED bytes in source MAC address.
     2517// @ src_mac_10 : two LSB bytes in source MAC address.
     2518// @ dst_mac_54 : two MSB bytes in destination MAC address.
     2519// @ dst_mac_32 : two MED bytes in destination MAC address.
     2520// @ dst_mac_10 : two LSB bytes in destination MAC address.
     2521// @ length     : number of bytes in Ethernet frame payload.
     2522///////////////////////////////////////////////////////////////////////////////////////////
     2523void dev_nic_tx_build_eth_header( uint8_t * buffer,
     2524                                  uint16_t  src_mac_54,
     2525                                  uint16_t  src_mac_32,
     2526                                  uint16_t  src_mac_10,
     2527                                  uint16_t  dst_mac_54,
     2528                                  uint16_t  dst_mac_32,
     2529                                  uint16_t  dst_mac_10,
     2530                                  uint32_t  length )
     2531{
     2532    buffer[0]  = dst_mac_54 >> 8;
     2533    buffer[1]  = dst_mac_54;
     2534    buffer[2]  = dst_mac_32 >> 8;
     2535    buffer[3]  = dst_mac_32;
     2536    buffer[4]  = dst_mac_10 >> 8;
     2537    buffer[5]  = dst_mac_10;
     2538
     2539    buffer[6]  = src_mac_54 >> 8;
     2540    buffer[7]  = src_mac_54;
     2541    buffer[8]  = src_mac_32 >> 8;
     2542    buffer[9]  = src_mac_32;
     2543    buffer[10] = src_mac_10 >> 8;
     2544    buffer[11] = src_mac_10;
     2545
     2546    buffer[12] = length >> 8;
     2547    buffer[13] = length;
     2548
     2549}  // end dev_nic_tx_build_eth_header()
     2550
     2551///////////////////////////////////////////////////////////////////////////////////////////
     2552// This static function is called by the dev_nic_tx_server() function to handle one
     2553// TX command, or one R2T request, registered in the socket identified by the <socket_xp>
     2554// argument. If there is one valid command, or if the R2T queue is non empty (for a TCP
     2555// socket), it builds an ETH/IP/UDP packet (or a ETH/IP/TCP segment), in the buffer
     2556// defined by the  <k_buf> argument, and registers it in the NIC_TX queue defined by the
     2557// <chdev> argument. The supported commands are SOCKET_SEND/SOCKET_CONNECT/SOCKET_CLOSE.
     2558// It unblocks the client thread when the command is completed.
     2559///////////////////////////////////////////////////////////////////////////////////////////
     2560// When there is a packet to send, it makes the following actions:
     2561// 1) it takes the lock protecting the socket state.
     2562// 2) it get the command arguments from client thread descriptor.
     2563// 3) it build an UDP packet or a TCP segment, depending on both the command type, and
     2564//    the socket state, updates the socket state, and unblocks the client thread.
     2565// 4) it release the lock protecting the socket.
     2566// 5) it build the IP header.
     2567// 6) it build the ETH header.
     2568// 7) it copies the packet in the NIC_TX queue.
     2569///////////////////////////////////////////////////////////////////////////////////////////
     2570// @ socket_xp   : [in] extended pointer on client socket. 
     2571// @ k_buf       : [in] local pointer on kernel buffer (2 Kbytes).
     2572// @ chdev       : [in] local pointer on NIC_RX chdev.
     2573///////////////////////////////////////////////////////////////////////////////////////////
     2574static void dev_nic_tx_handle_one_cmd( xptr_t    socket_xp,
     2575                                       uint8_t * k_buf,
     2576                                       chdev_t * chdev )
     2577{
     2578    socket_t  * socket_ptr;
     2579    cxy_t       socket_cxy;
     2580    xptr_t      client_xp;       // extended pointer on client thread 
     2581    thread_t  * client_ptr;
     2582    cxy_t       client_cxy;
     2583    sock_cmd_t  cmd;             // NIC command type
     2584    uint8_t   * buf;             // pointer on user buffer
     2585    uint32_t    len;             // user buffer length
     2586    uint32_t    todo;            // number of bytes not yet sent
     2587    uint32_t    socket_type;     // socket type (UDP/TCP)
     2588    uint32_t    socket_state;    // socket state       
     2589    xptr_t      socket_lock_xp;  // extended pointer on socket lock
     2590    xptr_t      socket_r2tq_xp;  // extended pointer on R2T queue
     2591    uint32_t    src_ip_addr;     // source IP address
     2592    uint32_t    dst_ip_addr;     // destination IP address
     2593    uint32_t    tx_una;          // next byte to be sent
     2594    uint32_t    tx_nxt;          // first unacknowledged byte
     2595    uint32_t    nbytes;          // number of bytes in UDP/TCP packet payload
     2596    uint8_t   * k_base;          // pointer UDP/TCP packet in kernel buffer
     2597    uint32_t    trsp_length;     // length of TCP/UDP packet
     2598    uint8_t     r2t_flags;       // flags defined by one R2T queue request
     2599    bool_t      do_send;         // build & send a packet when true
     2600 
     2601    // get socket cluster and local pointer
     2602    socket_cxy = GET_CXY( socket_xp );
     2603    socket_ptr = GET_PTR( socket_xp );
     2604   
     2605    // build extended pointer on socket lock and r2t queue
     2606    socket_lock_xp = XPTR( socket_cxy , &socket_ptr->lock );
     2607    socket_r2tq_xp = XPTR( socket_cxy , &socket_ptr->r2tq );
     2608
     2609    // 1. take lock protecting this socket
     2610    remote_rwlock_wr_acquire( socket_lock_xp );
     2611
     2612    // get pointers on TX client thread from socket
     2613    client_xp = hal_remote_l64( XPTR( socket_cxy , &socket_ptr->tx_client ));
     2614    client_cxy = GET_CXY( client_xp );
     2615    client_ptr = GET_PTR( client_xp );
     2616
     2617    // check valid command
     2618    if( client_xp != XPTR_NULL )   // valid command found
     2619    {
     2620        // 2. get command arguments from socket
     2621        cmd  = hal_remote_l32( XPTR(socket_cxy , &socket_ptr->tx_cmd ));
     2622        buf  = hal_remote_lpt( XPTR(socket_cxy , &socket_ptr->tx_buf ));
     2623        len  = hal_remote_l32( XPTR(socket_cxy , &socket_ptr->tx_len ));
     2624        todo = hal_remote_l32( XPTR(socket_cxy , &socket_ptr->tx_todo ));
     2625       
     2626        // get socket type and state
     2627        socket_type  = hal_remote_l32( XPTR(socket_cxy , &socket_ptr->type ));
     2628        socket_state = hal_remote_l32( XPTR(socket_cxy , &socket_ptr->state ));
     2629
     2630        // 3. UDP : build UDP packet and update UDP socket state
     2631        if( socket_type == SOCK_DGRAM )       
     2632        {
     2633            if( socket_state == UDP_STATE_UNBOUND )
     2634            {
     2635                // report illegal command
     2636                dev_nic_tx_report_error( socket_xp, cmd, socket_state );
     2637
     2638                do_send = false;
     2639            }
     2640            else  // BOUND or CONNECT state
     2641            {
     2642                if( cmd == SOCKET_TX_SEND )
     2643                {
     2644                    // compute payload length
     2645                    nbytes = ( PAYLOAD_MAX_LEN < todo ) ? PAYLOAD_MAX_LEN : todo;
     2646
     2647                    // compute UDP packet base in kernel buffer
     2648                    k_base = k_buf + ETH_HEAD_LEN + IP_HEAD_LEN;
     2649
     2650                    // move payload to kernel buffer
     2651                    hal_copy_from_uspace( XPTR(local_cxy , k_base + UDP_HEAD_LEN ),
     2652                                          buf + (len - todo),
     2653                                          nbytes );
     2654                    // build UDP header
     2655                    dev_nic_tx_build_udp_header( k_base,
     2656                                                 socket_xp,
     2657                                                 nbytes );
     2658
     2659                    // update "tx_todo" in socket descriptor
     2660                    hal_remote_s32( XPTR(socket_cxy , socket_ptr->tx_todo),
     2661                                    todo - nbytes );
     2662
     2663                    // unblock client thread when SEND command completed
     2664                    if( nbytes == todo )
     2665                    {
     2666                        dev_nic_tx_report_success( socket_xp );
     2667                    }
     2668
     2669                    do_send = true;
     2670                }
     2671                else
     2672                {
     2673                    // report illegal command
     2674                    dev_nic_tx_report_error( socket_xp, cmd, socket_state );
     2675
     2676                    do_send = false;
     2677                }
     2678            }
     2679
     2680            // compute transport packet length
     2681            trsp_length = UDP_HEAD_LEN + nbytes;
     2682
     2683        }  // end UDP
     2684
     2685        // 3. TCP : build TCP segment and update TCP socket state
     2686        if( socket_type == SOCK_STREAM )
     2687        {
     2688            // extract one request from TCP socket R2T queue if queue non empty
     2689            if( remote_buf_status( socket_r2tq_xp ) )
     2690            {
     2691                remote_buf_get_to_kernel( socket_r2tq_xp , &r2t_flags , 1 );
     2692            }
     2693            else
     2694            {
     2695                r2t_flags = 0;
     2696            }
     2697
     2698            /////////////////////////////////////
     2699            if( socket_state == TCP_STATE_ESTAB )    // connected TCP socket
     2700            {
     2701                if( cmd == SOCKET_TX_SEND )         
     2702                {
     2703                    // get  "tx_nxt", and "tx_una" from socket descriptor
     2704                    tx_nxt = hal_remote_l32( XPTR(socket_cxy , &socket_ptr->tx_nxt ));
     2705                    tx_una = hal_remote_l32( XPTR(socket_cxy , &socket_ptr->tx_una ));
     2706
     2707                    // compute actual payload length
     2708                    nbytes = ( PAYLOAD_MAX_LEN < todo ) ? PAYLOAD_MAX_LEN : todo;
     2709
     2710                    // compute TCP segment base in kernel buffer
     2711                    k_base = k_buf + ETH_HEAD_LEN + IP_HEAD_LEN;
     2712
     2713                    // move payload to kernel buffer
     2714                    hal_copy_from_uspace( XPTR( local_cxy , k_base + TCP_HEAD_LEN ),
     2715                                          buf + (len - todo),
     2716                                          nbytes );
     2717
     2718                    // build TCP header
     2719                    dev_nic_tx_build_tcp_header( k_base,
     2720                                                 socket_xp,
     2721                                                 nbytes,                       // payload
     2722                                                 TCP_FLAG_ACK | r2t_flags );   // flags
     2723
     2724                    // update "tx_todo" in socket descriptor
     2725                    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_todo ),
     2726                                    todo - nbytes );
     2727
     2728                    // update "tx_nxt" in socket descriptor
     2729                    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_nxt ),
     2730                                    tx_nxt + nbytes );
     2731
     2732                    // unblock client thread when SEND command completed
     2733                    if( (todo == 0) && (tx_nxt == tx_una) )
     2734                    {
     2735                        dev_nic_tx_report_success( socket_xp );
     2736                    }
     2737
     2738                    do_send = true;
     2739                }
     2740                else if( cmd == SOCKET_TX_CLOSE )         
     2741                {
     2742                    // build TCP FIN segment
     2743                    dev_nic_tx_build_tcp_header( k_base,
     2744                                                 socket_xp,
     2745                                                 0,                            // payload
     2746                                                 TCP_FLAG_FIN | r2t_flags );   // flags
     2747                    // update socket state
     2748                    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ),
     2749                                    TCP_STATE_FIN_WAIT1 );
     2750
     2751                    do_send = true;
     2752                }
     2753                else  // cmd == CONNECT
     2754                {
     2755                    // report illegal command
     2756                    dev_nic_tx_report_error( socket_xp , cmd , socket_state );
     2757
     2758                    do_send = false;
     2759                }
     2760            }
     2761            //////////////////////////////////////////
     2762            else if( socket_state == TCP_STATE_BOUND )  // unconnected TCP socket
     2763            {
     2764                if ( cmd == SOCKET_TX_CONNECT ) 
     2765                {
     2766                    // set socket.tx_nxt
     2767                    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_nxt ),
     2768                                     TCP_ISS  );
     2769                     
     2770                    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->rx_nxt ), 0 );
     2771                    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->rx_wnd ),
     2772                                    NIC_RX_BUF_SIZE);
     2773                                     
     2774                    // build TCP SYN segment
     2775                    dev_nic_tx_build_tcp_header( k_base,
     2776                                                  socket_xp,
     2777                                                  0,                // payload
     2778                                                  TCP_FLAG_SYN );   // flags
     2779                    // update socket state
     2780                    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ),
     2781                                     TCP_STATE_SYN_SENT );
     2782
     2783                    do_send = true;
     2784                }
     2785                else   // cmd == SEND / CLOSE
     2786                {
     2787                    // report illegal command
     2788                    dev_nic_tx_report_error( socket_xp, cmd, socket_state );
     2789
     2790                    do_send = false;
     2791                }
     2792            }
     2793            ///////////////////////////////////////////
     2794            else if( socket_state == TCP_STATE_LISTEN )  // server wait connect
     2795            {
     2796                if( cmd == SOCKET_TX_CONNECT )         
     2797                {
     2798                    // update socket.state
     2799                    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ),
     2800                                    TCP_STATE_SYN_SENT );
     2801                   
     2802                    // set socket.tx_una 
     2803                    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_una ),
     2804                                    TCP_ISS );
     2805
     2806                    // set socket.tx_nxt
     2807                    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_una ),
     2808                                    TCP_ISS + 1 );
     2809
     2810                    // build TCP SYN segment
     2811                    dev_nic_tx_build_tcp_header( k_base,
     2812                                                 socket_xp,
     2813                                                 0,                // payload
     2814                                                 TCP_FLAG_SYN );   // flags
     2815                    do_send = true;
     2816                }
     2817                else  // cmd == CLOSE / SEND
     2818                {
     2819                    // report illegal command
     2820                    dev_nic_tx_report_error( socket_xp, cmd, socket_state );
     2821
     2822                    do_send = false;
     2823                }
     2824            }
     2825            /////////////////////////////////////////////
     2826            else if( socket_state == TCP_STATE_SYN_RCVD )  // socket wait ACK
     2827            {
     2828                if( cmd == SOCKET_TX_CLOSE )         
     2829                {
     2830                    // build TCP FIN segment
     2831                    dev_nic_tx_build_tcp_header( k_base,
     2832                                                 socket_xp,
     2833                                                 0,                // payload
     2834                                                 TCP_FLAG_FIN );   // flags
     2835                    // update socket state
     2836                    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ),
     2837                                    TCP_STATE_FIN_WAIT1 );
     2838
     2839                    do_send = true;
     2840                }
     2841                else  // SEND / CONNECT
     2842                {
     2843                    // report illegal command
     2844                    dev_nic_tx_report_error( socket_xp, cmd, socket_state );
     2845
     2846                    do_send = false;
     2847                }
     2848            }
     2849            ////////////////////////////////////////////////
     2850            else if( socket_state == TCP_STATE_CLOSE_WAIT )  // wait local close()
     2851            {
     2852                if( cmd == SOCKET_TX_CLOSE )         
     2853                {
     2854                    // build TCP FIN segment
     2855                    dev_nic_tx_build_tcp_header( k_base,
     2856                                                 socket_xp,
     2857                                                 0,                // payload
     2858                                                 TCP_FLAG_FIN );   // flags
     2859                    // update socket state
     2860                    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ),
     2861                                    TCP_STATE_LAST_ACK );
     2862
     2863                    do_send = true;
     2864                }
     2865                else  // SEND / CONNECT
     2866                {
     2867                    // report illegal command
     2868                    dev_nic_tx_report_error( socket_xp, cmd, socket_state );
     2869
     2870                    do_send = false;
     2871                }
     2872            }
     2873            ////
     2874            else
     2875            {
     2876                    // report illegal command
     2877                    dev_nic_tx_report_error( socket_xp, cmd, socket_state );
     2878
     2879                    do_send = false;
     2880            }
     2881
     2882            // compute TCP segment length
     2883            trsp_length = TCP_HEAD_LEN + nbytes;
     2884        }
     2885    } 
     2886    else                        // no valid command found
     2887    {
     2888        if( socket_type == SOCK_DGRAM )    //  UDP socket
     2889        {
     2890            do_send = false;
     2891        }
     2892        else                               //  TCP socket
     2893        {
     2894            if( remote_buf_status( socket_r2tq_xp ) == 0 )  // R2T queue empty
     2895            {
     2896                do_send = false;
     2897            }
     2898            else                                // pending request in R2T queue
     2899            {
     2900                // get one request from R2T queue
     2901                remote_buf_get_to_kernel( socket_r2tq_xp , &r2t_flags , 1 );
     2902
     2903                // build TCP header for an empty segment
     2904                dev_nic_tx_build_tcp_header( k_base,
     2905                                             socket_xp,
     2906                                             0,             // payload
     2907                                             r2t_flags );   // flags
     2908                do_send = true;
     2909            }         
     2910        }
     2911    }
     2912
     2913    // 4. release the lock protecting the socket
     2914    remote_rwlock_wr_release( socket_lock_xp );
     2915
     2916    // return if no packet to send
     2917    if( do_send == false ) return;
     2918
     2919    // 5. build IP header
     2920    dev_nic_tx_build_ip_header( k_buf + ETH_HEAD_LEN,
     2921                                src_ip_addr,
     2922                                dst_ip_addr,
     2923                                IP_HEAD_LEN + trsp_length );
     2924
     2925    // 6. build ETH header
     2926    dev_nic_tx_build_eth_header( k_buf,
     2927                                 (uint16_t)SRC_MAC_54,
     2928                                 (uint16_t)SRC_MAC_32,
     2929                                 (uint16_t)SRC_MAC_10,
     2930                                 (uint16_t)DST_MAC_54,
     2931                                 (uint16_t)DST_MAC_32,
     2932                                 (uint16_t)DST_MAC_10,
     2933                                 ETH_HEAD_LEN + IP_HEAD_LEN + trsp_length );
     2934
     2935    // 7. move packet to NIC_TX queue
     2936    dev_nic_tx_move_packet( chdev,
     2937                            k_buf,
     2938                            ETH_HEAD_LEN + IP_HEAD_LEN + trsp_length );
     2939
     2940}  // end dev_nic_tx_handle_one_cmd()
     2941
     2942/////////////////////////////////////////
     2943void dev_nic_tx_server( chdev_t * chdev )
     2944{
     2945    uint8_t       k_buf[NIC_KERNEL_BUF_SIZE];  // buffer for one packet
     2946
     2947    xptr_t        root_xp;         // extended pointer on clients list root
     2948    xptr_t        lock_xp;         // extended pointer on lock protecting this list
     2949    xptr_t        socket_xp;       // extended pointer on on client socket
     2950    socket_t    * socket_ptr;
     2951    cxy_t         socket_cxy;
     2952    xptr_t        entry_xp;        // extended pointer on socket tx_list entry
     2953
     2954    thread_t * this = CURRENT_THREAD;
     2955
     2956// check chdev direction and type
     2957assert( (chdev->func == DEV_FUNC_NIC) && (chdev->is_rx == false) ,
     2958"illegal chdev type or direction" );
     2959
     2960// check thread can yield
     2961assert( (this->busylocks == 0),
     2962"cannot yield : busylocks = %d\n", this->busylocks );
     2963
     2964    // build extended pointer on client sockets lock & root
     2965    lock_xp = XPTR( local_cxy , &chdev->wait_lock );
     2966    root_xp = XPTR( local_cxy , &chdev->wait_root );
     2967
     2968    while( 1 )  // TX server infinite loop
     2969    {
     2970        // take the lock protecting the client sockets queue
     2971        remote_busylock_acquire( lock_xp );
     2972
     2973        /////////////// block and deschedule if no clients
     2974        if( xlist_is_empty( root_xp ) == false )
     2975        {
     2976            // release the lock protecting the TX client sockets queue
     2977            remote_busylock_release( lock_xp );
     2978 
     2979            // block and deschedule
     2980            thread_block( XPTR( local_cxy , this ) , THREAD_BLOCKED_CLIENT );
     2981            sched_yield( "waiting client" );
     2982        }
     2983        ////////////// 
     2984        else
     2985        {
     2986            // get first client socket
     2987            socket_xp  = XLIST_FIRST( root_xp , socket_t , tx_list );
     2988            socket_cxy = GET_CXY( socket_xp );
     2989            socket_ptr = GET_PTR( socket_xp );
     2990 
     2991            // build extended pointer on socket xlist_entry
     2992            entry_xp = XPTR( socket_cxy , &socket_ptr->tx_list );
     2993
     2994            // remove this socket from the waiting queue
     2995            xlist_unlink( entry_xp );
     2996
     2997            // release the lock protecting the client sockets queue
     2998            remote_busylock_release( lock_xp );
     2999
     3000            // handle this TX client
     3001            dev_nic_tx_handle_one_cmd( socket_xp,
     3002                                       k_buf,
     3003                                       chdev );
     3004
     3005            // take the lock protecting the client sockets queue
     3006            remote_busylock_acquire( lock_xp );
     3007
     3008            // add this socket in last position of queue
     3009            xlist_add_last( root_xp , entry_xp );
     3010
     3011            // release the lock protecting the client sockets queue
     3012            remote_busylock_release( lock_xp );
     3013        }
     3014    }   // end while
     3015}  // end dev_nic_tx_server()
     3016
     3017
  • trunk/kernel/devices/dev_nic.h

    r457 r657  
    22 * dev_nic.h - NIC (Network Controler) generic device API definition.
    33 *
    4  * Author  Alain Greiner    (2016,2017,2018)
     4 * Author  Alain Greiner    (2016,2017,2018,2019,2020)
    55 *
    66 * Copyright (c) UPMC Sorbonne Universites
     
    2727#include <kernel_config.h>
    2828#include <hal_kernel_types.h>
     29#include <remote_busylock.h>
     30#include <remote_buf.h>
     31#include <xlist.h>
     32
     33/****  Forward declarations  ****/
     34
     35struct chdev_s;
    2936
    3037/*****************************************************************************************
    3138 *     Generic Network Interface Controler definition
    3239 *
    33  * This device provide access to an external Gigabit Ethernet network controler.
    34  * It assume that the NIC hardware peripheral handles two packets queues for sent (TX)
    35  * and received (RX) packets. Packets are (Ethernet/IPV4).
     40 * This device provides access to a generic Gigabit Ethernet network controler.
     41 * It assumes that the NIC hardware peripheral handles two packets queues for sent (TX)
     42 * and received (RX) packets.
     43 *
     44 * The supported protocols stack is : Ethernet / IPV4 / TCP or UDP
    3645 *
    37  * The NIC device is handling an (infinite) stream of packets to or from the network.
     46 * 1) hardware assumptions
     47 *
     48 * The NIC device is handling two (infinite) streams of packets to or from the network.
    3849 * It is the driver responsibility to move the RX packets from the NIC to the RX queue,
    3950 * and the TX packets from the TX queue to the NIC.
    4051 *
    41  * AS the RX and TX queues are independant, there is one NIC-RX device descriptor
    42  * to handle RX packets, and another NIC-TX device descriptor to handle TX packets.
    43  * In order to improve throughput, the hardware NIC controller can optionnally implement
    44  * multiple channels:
    45  * - The RX channels are indexed by an hash key derived from the source IP address.
    46  * - The TX channels are indexed by an hash key derived from the destination IP address.
    47  * These 2*N devices, and 2*N associated server threads, are distributed in 2*N clusters.
    48  * The  2*N server threads implement the protocols stack. The RX server threads block
    49  * and deschedule when the RX queue is empty. The TX server stack block and deschedule
    50  * when the queue is full.
    51  *
    52  * It is the driver responsibily to re-activate a blocked server thread when
    53  * the queue state is modified: not full for TX, or not empty for RX.
     52 * AS the RX and TX queues are independant, there is one NIC_RX device descriptor
     53 * to handle RX packets, and another NIC_TX device descriptor to handle TX packets.
     54 *
     55 * In order to improve throughput, the NIC controller can implement multiple (N) channels.
     56 * In this case, the channel index is defined by an hash function computed from the remote
     57 * IP address and port. This index is computed by the hardware for an RX packet, and is
     58 * computed by the kernel for a TX packet, using a specific driver function. TODO ...
     59 * The 2*N chdevs, and the associated server threads implementing the protocols stack,
     60 * are distributed in 2*N different clusters.
     61 *
     62 * 2) User API
     63 *
     64 * On the user side, ALMOS-MKH implements the POSIX socket API.
     65 * The kernel functions implementing the socket related syscalls are :
     66 * - dev_nic_socket()    : create a local socket registered in process fd_array[].
     67 * - dev_nic_bind()      : attach a local IP address and port to a local socket.
     68 * - dev_nic_listen()    : local server makes a passive open.
     69 * - dev_nic_connect()   : local client makes an active open to a remote server.
     70 * - dev_nic_accept()    : local server accept a new remote client.
     71 * - dev_nic_send()      : send data on a connected socket.
     72 * - dev_nic_recv()      : receive data on a connected socket.
     73 * - dev_nic_sendto()    : send a packet to a remote (IP address/port).
     74 * - dev_nic_recvfrom()  : receive a paket from a remote (IP address/port).
     75 * - dev_nic_close()     : close a socket
     76 *
     77 * 3) TX stream
     78 *
     79 * The internal API between the client threads and the TX server thread defines
     80 * the 3 following commands:
     81 *   . SOCKET_TX_CONNECT : request to execute the 3 steps TCP connection handshake.
     82 *   . SOCKET_TX_SEND    : send data to a remote socket (UDP or TCP).
     83 *   . SOCKET_TX_CLOSE   : request to execute the 3 steps TCP close handshake.
     84 *
     85 * - These 3 commands are blocking for the client thread that registers the command in the
     86 *   socket descriptor, blocks on the BLOCKED_IO condition, and deschedules.
     87 * - The TX server thread is acting as a multiplexer. It scans the list of attached sockets,
     88 *   to handle all valid commands: one UDP packet or TCP segment per iteration.
     89 *   It uses the user buffer defined by the client thread, and attached to socket descriptor,
     90 *   as a retransmission buffer. It blocks and deschedules on the BLOCKED_CLIENT condition,
     91 *   when there is no more active TX command registered in any socket. It is re-activated
     92 *   by the first client thread registering a new TX command in the socket descriptor.
     93 *   It unblocks a client thread only when a command is fully completed. It signals errors
     94 *   to the client thread using the tx_error field in socket descriptor.
     95 *
     96 * 4) RX stream
     97 *
     98 * The communication between the RX server thread and the client threads expecting data
     99 * is done through receive buffers (one private buffer per socket) that are handled
     100 * as single-writer / single reader-FIFOs, called rx_buf.
     101 * - The RX server thread is acting as a demultiplexor: it handle one TCP segment or UDP
     102 *   packet per iteration, and register the data in the rx_buf of the socket matching
     103 *   the packet. It simply discard all packets that does not match a registered socket.
     104 *   When a client thread is registered in the socket descriptor, the RX server thread
     105 *   unblocks this client thread as soon as there is data available in rx_buf.
     106 *   It blocks and deschedules on the BLOCKED_ISR condition when there is no more packets
     107 *   in the NIC_RX queue. It is unblocked by the hardware ISR.
     108 * - The client thread simply access the rx_buf attached to socket descriptor, and consumes
     109 *   the available data when the rx_buf is non empty. It blocks on the BLOCKED_IO condition,
     110 *   and deschedules when the rx_buf is empty.
     111 *
     112 * 5) R2T queue
     113 *
     114 * To implement the TCP "3 steps handshake" protocol, the RX server thread can directly
     115 * request the associated TX server thread to send control packets in  the TX stream,
     116 * using a dedicate R2T (RX to TX) FIFO stored in the socket descriptor.
     117 *
     118 * 6) NIC driver API
     119 *
     120 * The generic NIC device "driver" API defines the following commands to the NIC driver:
     121 * - READABLE : returns true if at least one RX paquet is available in RX queue.
     122 * - WRITABLE : returns true if at least one empty slot is available in TX queue.
     123 * - READ     : consume one packet from the RX queue.
     124 * - WRITE    : produce one packet to the TX queue.
     125 * All RX or TX paquets are sent or received in standard 2 Kbytes kernel buffers,
     126 * that are dynamically allocated by the protocols stack.
     127 *
     128 * The actual TX an RX queues structures depends on the hardware NIC implementation,
     129 * and are defined in the HAL specific driver code.
    54130 *
    55131 * WARNING: the WTI mailboxes used by the driver ro receive events from the hardware
    56132 * (available RX packet, or available free TX slot, for a given channel), must be
    57133 * statically allocated during the kernel initialisation phase, and must be
    58  * routed to the cluster containing the associated device descriptor and server thread.
    59  * to simplify the server thread re-activation.
    60  *
    61  * Finally, the generic NIC device API defines the following commands:
    62  * - READABLE : returns true if at least one RX paquet is available in RX queue.
    63  * - WRITABLE : returns true if atleast one empty slot is available in TX queue.
    64  * - READ     : consume one packet from the RX queue.
    65  * - WRITE    : produce one packet fto the TX queue.
    66  * All RX or TX paquets are sent or received in standard 2 Kbytes kernel buffers,
    67  * that are dynamically allocated by the protocols stack. The structure pkd_t
    68  * defining a packet descriptor is defined below, and contain the buffer pointer
    69  * and the actual Ethernet packet Length.
    70  *
    71  * The actual TX an RX queues structures depends on the hardware NIC implementation,
    72  * and are defined in the driver code.
     134 * routed to the cluster containing the associated TX/RX chdev and server thread.
     135 *
    73136 *****************************************************************************************/
    74137
     
    78141
    79142/******************************************************************************************
    80  * This defines the extension for the generic IOC device.
     143 *   Various constants used by the Protocols stack
     144 *****************************************************************************************/
     145
     146#define SRC_MAC_54             0x54
     147#define SRC_MAC_32             0x32
     148#define SRC_MAC_10             0x10
     149#define DST_MAC_54             0x54
     150#define DST_MAC_32             0x32
     151#define DST_MAC_10             0x10
     152
     153#define TCP_HEAD_LEN           20
     154#define UDP_HEAD_LEN           8
     155#define IP_HEAD_LEN            20
     156#define ETH_HEAD_LEN           14
     157
     158#define PROTOCOL_UDP           0x11
     159#define PROTOCOL_TCP           0x06
     160
     161#define TCP_ISS                0x10000
     162
     163#define PAYLOAD_MAX_LEN        1500         // max payload for and UDP packet or a TCP segment
     164
     165#define TCP_FLAG_FIN           0x01
     166#define TCP_FLAG_SYN           0x02
     167#define TCP_FLAG_RST           0x04
     168#define TCP_FLAG_PSH           0x08
     169#define TCP_FLAG_ACK           0x10
     170#define TCP_FLAG_URG           0x20
     171
     172#define NIC_RX_BUF_SIZE        0x100000     // 1 Mbytes
     173#define NIC_R2T_QUEUE_SIZE     0x64         // smallest KCM size
     174#define NIC_CRQ_QUEUE_SIZE     0x8          // 8 * sizeof(sockaddr_t) = smallest KCM size
     175#define NIC_PKT_MAX_SIZE       1500         // for Ethernet
     176#define NIC_KERNEL_BUF_SIZE    2000         // for on ETH/IP/TCP packet
     177
     178/*****************************************************************************************
     179 * This defines the extension for the generic NIC device.
    81180 * The actual queue descriptor depends on the implementation.
    82  *****************************************************************************************/
     181 *
     182 * WARNING : for all NIC_TX and NIC_RX chdevs, the xlist rooted in in the chdev
     183 *           ("wait_root" and "wait_lock" fields) is actually a list of sockets.
     184 ****************************************************************************************/
    83185
    84186typedef struct nic_extend_s
    85187{
    86     void     * queue;     /*! local pointer on the packets queue descriptor (RX or TX)   */
     188    void         * queue;       /*! local pointer on NIC queue descriptor (RX or TX)    */
    87189}
    88190nic_extend_t;
    89191
    90 /******************************************************************************************
    91  * This structure defines the Ethernet/IPV4 packet descriptor, that is sent to,
    92  * or received from, the protocols stack.
    93  *****************************************************************************************/
    94 
    95 typedef struct pkd_s
    96 {
    97     char      * buffer;   /*! local pointer on 2 Kbytes buffer containing packet         */ 
    98     uint32_t    length;   /*! actual number of bytes                                     */
    99 }
    100 pkd_t;
    101 
    102 /******************************************************************************************
     192/*****************************************************************************************
    103193 * This enum defines the various implementations of the generic NIC peripheral.
    104194 * This array must be kept consistent with the define in the arch_info.h file.
    105  *****************************************************************************************/
    106 
    107 enum nic_impl_e
     195 ****************************************************************************************/
     196
     197typedef enum nic_impl_e
    108198{
    109199    IMPL_NIC_CBF =   0,     
     
    112202nic_impl_t;
    113203
    114 /******************************************************************************************
    115  * This defines the (implementation independant) command  passed to the NIC driver.
    116  *****************************************************************************************/
     204/****************************************************************************************
     205 * This defines the (implementation independant) commands to access the NIC hardware.
     206 * These commands are registered by the NIC_TX and NIC_RX server threads in the
     207 * server thread descriptor, to be used by the NIC driver.
     208 * The buffer is always a 2K bytes kernel buffer, containing an Ethernet packet.
     209 ****************************************************************************************/
    117210
    118211typedef enum nic_cmd_e
    119212{
    120     NIC_CMD_WRITABLE = 0,  /*! test TX queue not full (for a given length packet)        */
    121     NIC_CMD_WRITE    = 1,  /*! put one (given length) packet to TX queue                 */
    122     NIC_CMD_READABLE = 2,  /*! test RX queue not empty (for any length packet)           */
    123     NIC_CMD_READ     = 3,  /*! get one (any length) packet from RX queue                 */
     213    NIC_CMD_WRITABLE  = 10,   /*! test TX queue not full (for a given packet length)    */
     214    NIC_CMD_WRITE     = 11,   /*! put one (given length) packet to TX queue             */
     215    NIC_CMD_READABLE  = 12,   /*! test RX queue not empty (for any packet length)       */
     216    NIC_CMD_READ      = 13,   /*! get one (any length) packet from RX queue             */
    124217}
    125218nic_cmd_t;
     
    127220typedef struct nic_command_s
    128221{
    129     xptr_t      dev_xp;   /*! extended pointer on device descriptor                      */
    130     nic_cmd_t   cmd;      /*! requested operation type                                   */
    131     char      * buffer;   /*! local pointer on 2 Kbytes buffer containing packet         */ 
    132     uint32_t    length;   /*! actual number of bytes                                     */
    133     bool_t      status;   /*! return true if writable or readable (depend on command)    */
    134     uint32_t    error;    /*! return an error from the hardware (0 if no error)          */
     222    xptr_t      dev_xp;       /*! extended pointer on NIC chdev descriptor              */
     223    nic_cmd_t   type;         /*! command type                                          */
     224    uint8_t   * buffer;       /*! local pointer on buffer (kernel or user space)        */ 
     225    uint32_t    length;       /*! number of bytes in buffer                             */
     226    uint32_t    status;       /*! return value (depends on command type)                */
     227    uint32_t    error;        /*! return an error from the hardware (0 if no error)     */
    135228}
    136229nic_command_t;
     230
     231/*****************************************************************************************
     232 * This structure defines a socket descriptor. In order to parallelize the transfers,
     233 * the set of all registered sockets is split in several subsets.
     234 * The number of subsets is the number of  NIC channels.
     235 * The distribution key is computed from the (remote_addr/remote_port) couple.
     236 * This computation is done by the NIC hardware for RX packets,
     237 * and by the dev_nic_connect() function for the TX packets.
     238 *
     239 * A socket is attached to the NIC_TX[channel] & NIC_RX[channel] chdevs.
     240 * Each socket descriptor allows the TX and TX server threads to access various buffers:
     241 * - the user "send" buffer contains the data to be send by the TX server thread.
     242 * - the kernel "receive" buffer contains the data received by the RX server thread.
     243 * - the kernel "r2t" buffer allows the RX server thread to make direct requests
     244 *   to the associated TX server (to implement the TCP 3 steps handshake).
     245 *
     246 * The synchronisation mechanism between the clients threads and the servers threads
     247 * is different for TX and RX transfers:
     248 *
     249 * 1) For a TX transfer, it can exist only one client thread for a given socket,
     250 *    the transfer is always initiated by the local process, and all TX commands
     251 *    (CONNECT/SEND/CLOSE) are blocking for the client thread. The user buffer is
     252 *    used by TCP to handle retransmissions when required.in case of re
     253 *    The client thread registers the command in the thread descriptor, registers itself
     254 *    in the socket descriptor, unblocks the TX server thread from the BLOCKED_CLIENT
     255 *    condition, blocks itself on the BLOCKED_IO condition, and deschedules.
     256 *    When the command is completed, the TX server thread unblocks the client thread.
     257 *    The TX server blocks itself on the BLOCKED_CLIENT condition, when there is no
     258 *    pending commands and the R2T queue is empty. It is unblocked when a client
     259 *    register a new command, or when the TX server thread register a mew request
     260 *    in the R2T queue.
     261 *    The tx_valid flip-flop is SET by the client thread to signal a valid command.
     262 *    It is RESET by the server thread when the command is completed: For a SEND,
     263 *    all bytes have been sent (UDP) or acknowledged (TCP).
     264 *
     265 * 2) For an RX transfer, it can exist only one client thread for a given socket,
     266 *    but the transfer is initiated by the remote process, and the  RECV command
     267 *    is not really blocking: the data can arrive before the local RECV command is
     268 *    executed, and the server thread does not wait to receive all requested data
     269 *    to deliver data to client thread. Therefore each socket contains a receive
     270 *    buffer (rx_buf) handled as a single-writer/single-reader fifo.
     271 *    The client thread consumes data from the rx_buf when possible. It blocks on the
     272 *    BLOCKED_IO condition and deschedules when the rx_buf is empty.
     273 *    It is unblocked by the RX server thread when new data is available in the rx_buf.
     274 *    The RX server blocks itself on the BLOCKED_ISR condition When the NIC_RX packets
     275 *    queue is empty. It is unblocked by the hardware when new packets are available.
     276 *
     277 * Note : the socket domains and types are defined in the "shared_socket.h" file.
     278 ****************************************************************************************/
     279
     280/******************************************************************************************
     281 * This function returns a printable string for a given NIC command <type>.
     282 ******************************************************************************************
     283 * @ type    : NIC command type
     284 *****************************************************************************************/
     285char * nic_cmd_str( uint32_t type );
     286   
     287/******************************************************************************************
     288 * This function returns a printable string for a given socket <state>.
     289 ******************************************************************************************
     290 * @ state    : socket state
     291 *****************************************************************************************/
     292char * socket_state_str( uint32_t state );
    137293
    138294/******************************************************************************************
     
    143299 * device and the specific data structures when required.
    144300 * It creates the associated server thread and allocates a WTI from local ICU.
     301 * For a TX_NIC chedv, it allocates and initializes the R2T waiting queue used by the
     302 * NIC_RX[channel] server to send direct requests to the NIC_TX[channel] server.
    145303 * It must de executed by a local thread.
    146304 ******************************************************************************************
     
    149307void dev_nic_init( struct chdev_s * chdev );
    150308
    151 /******************************************************************************************
    152  * This blocking function must be called by the kernel thread running in the cluster
    153  * containing the NIC_RX channel device descriptor.
    154  * It read one packet (Ethernet/IPV4) from the NIC_RX queue associated to the NIC channel.
    155  * It calls directly the NIC driver, without registering in a waiting queue, because
    156  * only this NIC_RX thread can access this packets queue.
    157  * 1) It test the packets queue status, using the NIC_CMD_WRITABLE command.
    158  *    If it is empty, it unmask the NIC-RX channel IRQ, blocks and deschedule.
    159  *    It is re-activated by the NIC-RX ISR (generated by the NIC) as soon as the queue
    160  *    becomes not empty.
    161  * 2) if the queue is not empty, it get one packet, using the driver NIC_CMD_READ command.
    162  * Both commands are successively registered in the NIC-RX server thread descriptor
    163  * to be passed to the driver.
    164  *
    165  * WARNING : for a RX packet the initiator is the NIC hardware, and the protocols
    166  * stack is traversed upward, from the point of view of function calls.
    167  ******************************************************************************************
    168  * @ pkd     : pointer on packet descriptor (expected).
    169  * @ returns 0 if success / returns non zero if ENOMEM, or error reported from NIC.
    170  *****************************************************************************************/
    171 error_t dev_nic_read( pkd_t * pkd );
    172 
    173 /******************************************************************************************
    174  * This blocking function must be called by the kernel thread running in the cluster
    175  * containing the NIC_TX channel device descriptor.
    176  * It writes one packet (Ethernet/IPV4) to the NIC_RX queue associated to the NIC channel.
    177  * It calls directly the NIC driver, without registering in a waiting queue, because
    178  * only this NIC_TX thread can access this packets queue.
    179  * 1) It test the packets queue status, using the NIC_CMD_READABLE command.
    180  *    If it is full, it unmask the NIC-TX channel IRQ, blocks and deschedule.
    181  *    It is re-activated by the NIC-TX ISR (generated by the NIC) as soon as the queue
    182  *    is not full.
    183  * 2) If the queue is not empty, it put one packet, using the driver NIC_CMD_WRITE command.
    184  * Both commands are successively registered in the NIC-TX server thread descriptor
    185  * to be passed to the driver.
    186  *
    187  * WARNING : for a TX packet the initiator is the "client" thread, and the protocols
    188  * stack is traversed downward from the point of view of function calls.
    189  ******************************************************************************************
    190  * @ pkd     : pointer on packet descriptor (to be filed).
    191  * @ returns 0 if success / returns if length > 2K, undefined key, or error from NIC.
    192  *****************************************************************************************/
    193 error_t dev_nic_write( pkd_t * pkd );
    194 
    195 
    196 /******************************************************************************************
    197  * This function is executed by the server thread associated to a NIC channel device
    198  * descriptor (RX or TX). This thread is created by the dev_nic_init() function.
    199  * It executes an infinite loop, handling one packet per iteration.
    200  *
    201  * -- For a TX channel --
    202  * 1) It allocates a 2 Kbytes buffer.
    203  * 2) It copies the client TCP/UDP packet in this buffer.
    204  * 3) It calls the IP layer to add the IP header.
    205  * 4) It calls the ETH layer to add the ETH header.
    206  * 5) It calls the dev_nic_write() blocking function to move the packet to the TX queue.
    207  * 6) It releases the 2 Kbytes buffer.
    208  *
    209  * When the waiting threads queue is empty, it blocks on the THREAD_BLOCKED_IO_CMD
    210  * condition and deschedule. It is re-activated by a client thread registering a command.
    211  *
    212  * -- For a RX channel --
    213  * 1) It allocates a 2 Kbytes buffer.
    214  * 2  It calls the dev_nic_read() blocking function to move the ETH packet to this buffer.
    215  * 3) It calls the ETH layer to analyse the ETH header.
    216  * 4) It calls the IP layer to analyse the IP header. TODO ???
    217  * 5) It calls the transport (TCP/UDP) layer. TODO ???
    218  * 5) It deliver the packet to the client thread. TODO ???
    219  * 6) It releases the 2 Kbytes buffer.
    220  *
    221  * When the RX packets queue is empty, it blocks on the THREAD_BLOCKED_IO_CMD
    222  * condition and deschedule. It is re-activated by the NIC driver when this queue
    223  * becomes non empty.
    224  ******************************************************************************************
    225  * @ dev     : local pointer on NIC chdev descriptor.
    226  *****************************************************************************************/
    227 void dev_nic_server( struct chdev_s * chdev );
    228 
     309
     310/* functions implementing the socket API */
     311
     312/****************************************************************************************
     313 * This function implements the socket() syscall.
     314 * This function allocates and intializes in the calling thread cluster:
     315 * - a new socket descriptor, defined by the <domain> and <type> arguments,
     316 * - a new file descriptor, associated to this socket,
     317 * It registers the file descriptor in the reference process fd_array[], set
     318 * the socket state to IDLE, and returns the <fdid> value.
     319 ****************************************************************************************
     320 * @ domain  : [in] socket protocol family (AF_UNIX / AF_INET)
     321 * @ type    : [in] socket type (SOCK_DGRAM / SOCK_STREAM).
     322 * @ return a file descriptor <fdid> if success / return -1 if failure.
     323***************************************************************************************/
     324int dev_nic_socket( uint32_t   domain,
     325                    uint32_t   type );
     326
     327/****************************************************************************************
     328 * This function implements the bind() syscall.
     329 * It initializes the  "local_addr" and "local_port" fields in the socket
     330 * descriptor identified by the <fdid> argument and set the socket state to BOUND.
     331 * It can be called by a thread running in any cluster.
     332 ****************************************************************************************
     333 * @ fdid      : [in] file descriptor identifying the socket.
     334 * @ addr      : [in] local IP address.
     335 * @ port      : [in] local port.
     336 * @ return 0 if success / return -1 if failure.
     337 ***************************************************************************************/
     338int dev_nic_bind( uint32_t fdid,
     339                  uint32_t addr,
     340                  uint16_t port );
     341
     342/****************************************************************************************
     343 * This function implements the listen() syscall().
     344 * It is called by a (local) server process to specify the max size of the queue
     345 * registering the (remote) client process connections, and set the socket identified
     346 * by the <fdid> argument to LISTEN state. It applies only to sockets of type TCP.
     347 * It can be called by a thread running in any cluster.
     348 * TODO handle the <max_pending> argument...
     349 ****************************************************************************************
     350 * @ fdid        : [in] file descriptor identifying the local server socket.
     351 * @ max_pending : [in] max number of accepted remote client connections.
     352 ***************************************************************************************/
     353int dev_nic_listen( uint32_t fdid,
     354                    uint32_t max_pending );
     355
     356/****************************************************************************************
     357 * This function implements the connect() syscall.
     358 * It is used by a (local) client process to connect a local socket identified by
     359 * the <fdid> argument, to a remote socket identified by the <remote_addr> and
     360 * <remote_port> arguments. It can be used for both  UDP and TCP sockets.
     361 * It computes the nic_channel index from <remote_addr> and <remote_port> values,
     362 * and initializes "remote_addr","remote_port", "nic_channel" in local socket.
     363 * It registers the socket in the two lists of clients rooted in the NIC_RX[channel]
     364 * and NIC_TX[channel] chdevs.  It can be called by a thread running in any cluster.
     365 * WARNING : the clients are the socket descriptors, and NOT the threads descriptors.
     366 ****************************************************************************************
     367 * Implementation Note:
     368 * - For a TCP socket, it updates the "remote_addr", "remote_port", "nic_channel" fields
     369 *   in the socket descriptor defined by the <fdid> argument, and register this socket,
     370 *   in the lists of sockets attached to the NIC_TX and NIC_RX chdevs.
     371 *   Then, it registers a CONNECT command in the "nic_cmd" field ot the client thread
     372 *   descriptor to request the NIC_TX server thread to execute the 3 steps handshake,
     373 *   and updates the "tx_client" field in the socket descriptor. It unblocks the NIC_TX
     374 *   server thread, blocks on the THREAD_BLOCKED_IO condition and deschedules.
     375 * - For an UDP socket, it simply updates "remote_addr", "remote_port", "nic_channel"
     376 *   in the socket descriptor defined by the <fdid> argument, and register this socket,
     377 *   in the lists of sockets attached to the NIC_TX and NIC_RX chdevs.
     378 *   Then, it set the socket state to CONNECT, without unblocking the NIC_TX server
     379 *   thread, and without blocking itself.
     380 * TODO : the nic_channel index computation must be done by a driver specific function.
     381 ****************************************************************************************
     382 * @ fdid          : [in] file descriptor identifying the socket.
     383 * @ remote_addr   : [in] remote IP address.
     384 * @ remote_port   : [in] remote port.
     385 * @ return 0 if success / return -1 if failure.
     386 ***************************************************************************************/
     387int dev_nic_connect( uint32_t  fdid,
     388                     uint32_t  remote_addr,
     389                     uint16_t  remote_port );
     390
     391/****************************************************************************************
     392 * This function implements the accept() syscall().
     393 * It is executed by a server process, waiting for one (or several) client process(es)
     394 * requesting a connection on a socket identified by the <fdid> argument.
     395 * This socket was previouly created with socket(), bound to a local address with bind(),
     396 * and is listening for connections after a listen().
     397 * This function extracts the first connection request on the CRQQ queue of pending
     398 * requests, creates a new socket with the same properties as the existing socket,
     399 * and allocates a new file descriptor for this new socket.
     400 * If no pending connections are present on the queue, it blocks the caller until a
     401 * connection is present.
     402 * The new socket cannot accept more connections, but the original socket remains open.
     403 * It returns the new socket <fdid>, and register in the <address> an <port> arguments
     404 * the remote client IP address & port. It applies only to sockets of type SOCK_STREAM.
     405 ****************************************************************************************
     406 * @ fdid         : [in] file descriptor identifying the listening socket.
     407 * @ address      : [out] server IP address.
     408 * @ port         : [out] server port address length in bytes.
     409 * @ return the new socket <fdid> if success / return -1 if failure
     410 ***************************************************************************************/
     411int dev_nic_accept( uint32_t   fdid,
     412                    uint32_t * address,
     413                    uint16_t * port );
     414
     415/****************************************************************************************
     416 * This blocking function implements the send() syscall.
     417 * It is used to send data stored in the user buffer, identified the <u_buf> and <length>
     418 * arguments, to a connected (TCP or UDP) socket, identified by the <fdid> argument.
     419 * The work is actually done by the NIC_TX server thread, and the synchronisation
     420 * between the client and the server threads uses the "rx_valid" set/reset flip-flop:
     421 * The client thread registers itself in the socket descriptor, registers in the queue
     422 * rooted in the NIC_TX[index] chdev, set "rx_valid", unblocks the server thread, and
     423 * finally blocks on THREAD_BLOCKED_IO, and deschedules.
     424 * When the TX server thread completes the command (all data has been sent for an UDP
     425 * socket, or acknowledeged for a TCP socket), the server thread reset "rx_valid" and
     426 * unblocks the client thread.
     427 * This function can be called by a thread running in any cluster.
     428 * WARNING : This implementation does not support several concurent SEND/SENDTO commands
     429 * on the same socket, as only one TX thread can register in a given socket.
     430 ****************************************************************************************
     431 * @ fdid      : [in] file descriptor identifying the socket.
     432 * @ u_buf     : [in] pointer on buffer containing packet in user space.
     433 * @ length    : [in] packet size in bytes.
     434 * @ return number of sent bytes if success / return -1 if failure.
     435 ***************************************************************************************/
     436int dev_nic_send( uint32_t    fdid,
     437                  uint8_t   * u_buf,
     438                  uint32_t    length );
     439
     440/****************************************************************************************
     441 * This blocking function implements the sendto() syscall.
     442 * It registers the <remote_addr> and <remote_port> arguments in the local socket
     443 * descriptor, and does the same thing as the dev_nic_send() function above,
     444 * but can be called  on an unconnected UDP socket.
     445 ****************************************************************************************
     446 * @ fdid        : [in] file descriptor identifying the socket.
     447 * @ u_buf       : [in] pointer on buffer containing packet in user space.
     448 * @ length      : [in] packet size in bytes.
     449 * @ remote_addr : [in] destination IP address.
     450 * @ remote_port : [in] destination port.
     451 * @ return number of sent bytes if success / return -1 if failure.
     452 ***************************************************************************************/
     453int dev_nic_sendto( uint32_t    fdid,
     454                    uint8_t   * u_buf,
     455                    uint32_t    length,
     456                    uint32_t    remote_addr,
     457                    uint32_t    remote_port );
     458
     459/****************************************************************************************
     460 * This blocking function implements the recv() syscall.
     461 * It is used to receive data that has been stored by the NIC_RX server thread in the
     462 * rx_buf of a connected (TCP or UDP) socket, identified by the <fdid> argument.
     463 * The synchronisation between the client and the server threads uses the "rx_valid"
     464 * set/reset flip-flop: If "rx_valid" is set, the client simply moves the available
     465 * data from the "rx_buf" to the user buffer identified by the <u_buf> and <length>
     466 * arguments, and reset the "rx_valid" flip_flop. If "rx_valid" is not set, the client
     467 * thread register itself in the socket descriptor, registers in the clients queue rooted
     468 * in the NIC_RX[index] chdev, and finally blocks on THREAD_BLOCKED_IO, and deschedules.
     469 * The client thread is re-activated by the RX server, that set the "rx_valid" flip-flop
     470 * as soon as data is available in the "rcv_buf" (can be less than the user buffer size).
     471 * This  function can be called by a thread running in any cluster.
     472 * WARNING : This implementation does not support several concurent RECV/RECVFROM
     473 * commands on the same socket, as only one RX thread can register in a given socket.
     474 ****************************************************************************************
     475 * @ fdid      : [in] file descriptor identifying the socket.
     476 * @ u_buf     : [in] pointer on buffer in user space.
     477 * @ length    : [in] buffer size in bytes.
     478 * @ return number of received bytes if success / return -1 if failure.
     479 ***************************************************************************************/
     480int dev_nic_recv( uint32_t    fdid,
     481                  uint8_t   * u_buf,
     482                  uint32_t    length );
     483
     484/****************************************************************************************
     485 * This blocking function implements the recvfrom() syscall.
     486 * It registers the <remote_addr> and <remote_port> arguments in the local socket
     487 * descriptor, and does the same thing as the dev_nic_recv() function above,
     488 * but can be called  on an unconnected UDP socket.
     489 ****************************************************************************************
     490 * @ fdid        : [in] file descriptor identifying the socket.
     491 * @ u_buf       : [in] pointer on buffer containing packet in user space.
     492 * @ length      : [in] packet size in bytes.
     493 * @ remote_addr : [in] destination IP address.
     494 * @ remote_port : [in] destination port.
     495 * @ return number of received bytes if success / return -1 if failure.
     496 ***************************************************************************************/
     497int dev_nic_recvfrom( uint32_t    fdid,
     498                      uint8_t   * u_buf,
     499                      uint32_t    length,
     500                      uint32_t    remote_addr,
     501                      uint32_t    remote_port );
     502
     503
     504/*  Instrumentation functions */
     505
     506
     507/******************************************************************************************
     508 * This instrumentation function displays on the TXT0 kernel terminal the content
     509 * of the instrumentation registers contained in the NIC device.
     510 *****************************************************************************************/
     511void dev_nic_print_stats( void );
     512
     513/******************************************************************************************
     514 * This instrumentation function reset all instrumentation registers contained
     515 * in the NIC device.
     516 *****************************************************************************************/
     517void dev_nic_clear_stats( void );
     518
     519
     520/* Functions executed by the TX and RX server threads */
     521 
     522/******************************************************************************************
     523 * This function is executed by the server thread associated to a NIC_TX[channel] chdev.
     524 * This TX server thread is created by the dev_nic_init() function.
     525 * It build and send UDP packets or TCP segments for all clients threads registered in
     526 * the NIC_TX[channel] chdev. The command types are (CONNECT / SEND / CLOSE), and the
     527 * priority between clients is round-robin. It takes into account the request registered
     528 * by the RX server thread in the R2T queue associated to the involved socket.
     529 * When a command is completed, it unblocks the client thread. For a SEND command, the
     530 * last byte must have been sent for an UDP socket, and it must have been acknowledged
     531 * for a TCP socket.
     532 * When the TX client threads queue is empty, it blocks on THREAD_BLOCKED_CLIENT
     533 * condition and deschedules. It is re-activated by a client thread registering a command.
     534 ******************************************************************************************
     535 * Implementation note:
     536 * It execute an infinite loop in which it takes the lock protecting the clients list
     537 * to build a "kleenex" list of currently registered clients.
     538 * For each client registered in this "kleenex" list, it takes the lock protecting the
     539 * socket state, build one packet/segment in a local 2K bytes kernel buffer, calls the
     540 * transport layer to add the UDP/TCP header, calls the IP layer to add the IP header,
     541 * calls the ETH layer to add the ETH header, and moves the packet to the NIC_TX_QUEUE.
     542 * Finally, it updates the socket state, and release the socket lock.
     543 ******************************************************************************************
     544 * @ chdev    : [in] local pointer on one local NIC_TX[channel] chdev descriptor.
     545 *****************************************************************************************/
     546void dev_nic_tx_server( struct chdev_s * chdev );
     547
     548
     549/******************************************************************************************
     550 * This function is executed by the server thread associated to a NIC_RX[channel] chdev.
     551 * This RX server thread is created by the dev_nic_init() function.
     552 * It handles all UDP packets or TCP segments received by the sockets attached to
     553 * the NIC_RX[channel] chdev. It writes the received data in the socket rcv_buf, and
     554 * unblocks the client thread waiting on a RECV command.
     555 * To implement the three steps handshahke required by a TCP connection, it posts direct
     556 * requests to the TX server, using the R2T queue attached to the involved socket.
     557 * It blocks on the THREAD_BLOCKED_ISR condition and deschedules when the NIC_RX_QUEUE
     558 * is empty. It is re-activated by the NIC_RX_ISR, when the queue becomes non empty.
     559 ******************************************************************************************
     560 * Implementation note:
     561 * It executes an infinite loop in which it extracts one packet from the NIC_RX_QUEUE
     562 * of received packets, copies this packet in a local 2 kbytes kernel buffer, checks
     563 * the Ethernet header, checks the IP header, calls the relevant (TCP or UDP) transport
     564 * protocol that search a matching socket for the received packet. It copies the payload
     565 * to the relevant socket rcv_buf when the packet is acceptable, and unblocks the client
     566 * thread. It discard the packet if no socket found.
     567 ******************************************************************************************
     568 * @ chdev    : [in] local pointer on one local NIC_RX[channel] chdev descriptor.
     569 *****************************************************************************************/
     570void dev_nic_rx_server( struct chdev_s * chdev );
    229571
    230572#endif  /* _DEV_NIC_H */
  • trunk/kernel/devices/dev_txt.c

    r647 r657  
    133133}  // end dev_txt_init()
    134134
    135 //////////////////////////////////////////////////////////////////////////////////
    136 // This static function is called by dev_txt_read(), dev_txt_write() functions.
    137 ////////////////////////////////////i/////////////////////////////////////////////
    138 static error_t dev_txt_access( uint32_t   type,
    139                                uint32_t   channel,
    140                                char     * buffer,
    141                                uint32_t   count )
    142 {
    143     xptr_t     dev_xp;
    144     thread_t * this = CURRENT_THREAD;
    145 
    146     // check channel argument
    147     assert( (channel < CONFIG_MAX_TXT_CHANNELS) , "illegal channel index" );
    148 
    149     // get extended pointer on remote TXT chdev descriptor
    150     if( type == TXT_WRITE )  dev_xp = chdev_dir.txt_tx[channel];
    151     else                     dev_xp = chdev_dir.txt_rx[channel];
    152 
    153     assert( (dev_xp != XPTR_NULL) , "undefined TXT chdev descriptor" );
    154 
    155     // register command in calling thread descriptor
    156     this->txt_cmd.dev_xp  = dev_xp;
    157     this->txt_cmd.type    = type;
    158     this->txt_cmd.buf_xp  = XPTR( local_cxy , buffer );
    159     this->txt_cmd.count   = count;
    160 
    161     // register client thread in waiting queue, activate server thread
    162     // block client thread on THREAD_BLOCKED_IO and deschedule.
    163     // it is re-activated by the ISR signaling IO operation completion.
    164     chdev_register_command( dev_xp );
    165 
    166     // return I/O operation status from calling thread descriptor
    167     return this->txt_cmd.error;
    168 
    169 }  // end dev_txt_access()
    170 
    171135/////////////////////////////////////////
    172136error_t dev_txt_write( uint32_t   channel,
     
    180144#endif
    181145
     146    thread_t * this = CURRENT_THREAD;
     147
    182148#if DEBUG_DEV_TXT_TX
    183 thread_t * this  = CURRENT_THREAD;
    184149uint32_t   cycle = (uint32_t)hal_get_cycles();
    185150if( DEBUG_DEV_TXT_TX < cycle )
     
    188153#endif
    189154
     155// check channel argument
     156assert( (channel < CONFIG_MAX_TXT_CHANNELS) , "illegal channel index" );
     157
     158    // get pointers on chdev
     159    xptr_t    dev_xp  = chdev_dir.txt_tx[channel];
     160    cxy_t     dev_cxy = GET_CXY( dev_xp );
     161    chdev_t * dev_ptr = GET_PTR( dev_xp );
     162
     163// check dev_xp
     164assert( (dev_xp != XPTR_NULL) , "undefined TXT chdev descriptor" );
     165
    190166    // If we use MTTY (vci_multi_tty), we do a synchronous write on TXT[0]
    191167    // If we use TTY  (vci_tty_tsar), we do a standard asynchronous write
    192168    // TODO this is not very clean ... [AG]
    193169
    194     // get pointers on chdev
    195     xptr_t dev_xp = chdev_dir.txt_tx[0];
    196     cxy_t     dev_cxy = GET_CXY( dev_xp );
    197     chdev_t * dev_ptr = GET_PTR( dev_xp );
    198 
    199     if( dev_ptr->impl == IMPL_TXT_MTY )
     170    if( dev_ptr->impl == IMPL_TXT_MTY ) 
    200171    {
    201172        // get driver command function
     
    216187    else
    217188    {
    218         // register command in chdev queue for an asynchronous access
    219         error = dev_txt_access( TXT_WRITE , channel , buffer , count );
     189        // register command in calling thread descriptor
     190        this->txt_cmd.dev_xp  = dev_xp;
     191        this->txt_cmd.type    = TXT_WRITE;
     192        this->txt_cmd.buf_xp  = XPTR( local_cxy , buffer );
     193        this->txt_cmd.count   = count;
     194
     195        // register client thread in waiting queue, activate server thread
     196        // block client thread on THREAD_BLOCKED_IO and deschedule.
     197        // it is re-activated by the ISR signaling IO operation completion.
     198        chdev_register_command( dev_xp );
     199
     200        // get I/O operation status from calling thread descriptor
     201        error = this->txt_cmd.error;
    220202
    221203        if( error )
     
    251233#endif
    252234
     235    thread_t * this = CURRENT_THREAD;
     236
    253237#if DEBUG_DEV_TXT_RX
    254 thread_t * this  = CURRENT_THREAD;
    255238uint32_t   cycle = (uint32_t)hal_get_cycles();
    256239if( DEBUG_DEV_TXT_RX < cycle )
     
    259242#endif
    260243
    261     // register command in chdev queue for an asynchronous access
    262     error = dev_txt_access( TXT_READ , channel , buffer , 1 );
     244// check channel argument
     245assert( (channel < CONFIG_MAX_TXT_CHANNELS) , "illegal channel index" );
     246
     247    // get pointers on chdev
     248    xptr_t    dev_xp  = chdev_dir.txt_rx[channel];
     249
     250// check dev_xp
     251assert( (dev_xp != XPTR_NULL) , "undefined TXT chdev descriptor" );
     252
     253    // register command in calling thread descriptor
     254    this->txt_cmd.dev_xp  = dev_xp;
     255    this->txt_cmd.type    = TXT_READ;
     256    this->txt_cmd.buf_xp  = XPTR( local_cxy , buffer );
     257    this->txt_cmd.count   = 1;
     258
     259    // register client thread in waiting queue, activate server thread
     260    // block client thread on THREAD_BLOCKED_IO and deschedule.
     261    // it is re-activated by the ISR signaling IO operation completion.
     262    chdev_register_command( dev_xp );
     263
     264    // get I/O operation status from calling thread descriptor
     265    error = this->txt_cmd.error;
    263266
    264267    if( error )
    265268    {
    266         printk("\n[ERROR] in %s : cannot get character / cycle %d\n",
    267         __FUNCTION__, (uint32_t)hal_get_cycles() );
     269         printk("\n[ERROR] in %s : cannot write string %s / cycle %d\n",
     270         __FUNCTION__, buffer, (uint32_t)hal_get_cycles() );
    268271    }
    269272
Note: See TracChangeset for help on using the changeset viewer.