Changeset 658 for trunk/hal


Ignore:
Timestamp:
Oct 10, 2020, 3:48:50 PM (4 years ago)
Author:
alain
Message:

Improve the TSAR NIC driver.

Location:
trunk/hal
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/hal/generic/hal_uspace.h

    r657 r658  
    3030//           User space access API (implementation in hal_uspace.c)
    3131//
     32// For sake of portability, user/kernel data transfers must use the following API.
     33//
    3234// When moving data between user space and kernel space, the user address is always
    33 // a virtual address, but the kernel address is an extended pointer.
    34 // For sake of portability, user/kernel data transfers must use the following API.
     35// a virtual address, and the kernel address is an extended pointer.
     36// Therefore, each of these buffers can be located in any cluster.
     37//
     38// WARNING: these function must be executed by an user thread (i.e. PID > 0),
     39//          to handle a possible page fault when accessing the user buffer.
    3540//////////////////////////////////////////////////////////////////////////////////////////
    3641
    3742
    3843/*****************************************************************************************
    39  * This function tranfers a data buffer in user space to a kernel buffer
    40  * that can be located in any cluster.
     44 * This function moves <size> bytes from a source buffer in user virtual space,
     45 * defined by the <u_src_ptr> argument, to a destination kernel buffer, defined by the
     46 * <k_dst_xp> argument.
    4147 *****************************************************************************************
    4248 * @ k_dst_xp  : extended pointer on kernel destination buffer.
     
    4955
    5056/*****************************************************************************************
    51  * This function tranfers a kernel buffer that can be located in any cluster
    52  * to a data buffer in the user space.
     57 * This function moves <size> bytes from a source kernel buffer, defined by the
     58 * <k_src_xp> argument, to a destination buffer in user virtual space, defined by
     59 * the <u_dst_ptr> argument.
    5360 *****************************************************************************************
    5461 * @ u_dst_ptr : destination buffer address in user space.
     
    8794
    8895/*****************************************************************************************
    89  * This function computes the length of a string in user space.
     96 * This function returns the length of a string located in user space.
    9097 *****************************************************************************************
    9198 * @ string     : string in user space.
  • trunk/hal/tsar_mips32/core/hal_gpt.c

    r647 r658  
    11871187
    11881188
    1189 
    1190 
    1191 
  • trunk/hal/tsar_mips32/core/hal_special.c

    r625 r658  
    292292}
    293293
     294
  • trunk/hal/tsar_mips32/core/hal_uspace.c

    r657 r658  
    3131
    3232///////////////////////////////////////////////////////////////////////////////////////
    33 // This function moves <size> bytes from a source buffer in user virtual space,
    34 // defined by the <u_src_ptr> argument, to a destination kernel buffer, defined by the
    35 // <k_dst_xp> argument.
     33// Implementation note
    3634// It works in a critical section, as it modifies two CP2 registers:
    3735// It activates briefly the DATA_MMU by writing into the CP2_MODE register to access the
     
    4139// If the buffers are not aligned, it moves all data byte per byte.
    4240///////////////////////////////////////////////////////////////////////////////////////
    43 // @ k_dst_xp  : extended pointer on destination kernel buffer
    44 // @ u_src_ptr : pointer on source user buffer
    45 // @ size     : number of bytes to move
    46 ///////////////////////////////////////////////////////////////////////////////////////
    4741void hal_copy_from_uspace( xptr_t     k_dst_xp,
    4842                           void     * u_src_ptr,
     
    5549    uint32_t cxy = (uint32_t)GET_CXY( k_dst_xp );
    5650 
     51assert( (CURRENT_THREAD->process->pid > 0), "must be called by an user thread" );
     52
    5753#if DEBUG_HAL_USPACE
    5854thread_t * this  = CURRENT_THREAD;
     
    133129
    134130///////////////////////////////////////////////////////////////////////////////////////
    135 // This function moves <size> bytes from a source kernel buffer, defined by the
    136 // <k_src_xp> argument, to a destination buffer in user virtual space, defined by
    137 // the <u_dst_ptr> argument.
     131// Implementation note
    138132// It works in a critical section, as it modifies two CP2 registers:
    139133// It activates briefly the DATA_MMU by writing into the CP2_MODE register to access the
     
    143137// If the buffers are not word aligned, it moves all data byte per byte.
    144138///////////////////////////////////////////////////////////////////////////////////////
    145 // @ u_dst_ptr : pointer on destination user buffer
    146 // @ k_src_xp  : extended pointer on source kernel buffer
    147 // @ size      : number of bytes to move
    148 ///////////////////////////////////////////////////////////////////////////////////////
    149139void hal_copy_to_uspace( void     * u_dst_ptr,
    150140                         xptr_t     k_src_xp,
     
    156146    uint32_t src = (uint32_t)GET_PTR( k_src_xp );
    157147    uint32_t cxy = (uint32_t)GET_CXY( k_src_xp );
     148
     149assert( (CURRENT_THREAD->process->pid > 0), "must be called by an user thread" );
    158150
    159151#if DEBUG_HAL_USPACE
     
    244236    uint32_t cxy = (uint32_t)GET_CXY( k_dst_xp );
    245237
     238assert( (CURRENT_THREAD->process->pid > 0), "must be called by an user thread" );
     239
    246240    hal_disable_irq( &save_sr );
    247241
     
    297291    uint32_t cxy = (uint32_t)GET_CXY( k_src_xp );
    298292
     293assert( (CURRENT_THREAD->process->pid > 0), "must be called by an user thread" );
     294
    299295    hal_disable_irq( &save_sr );
    300296
     
    346342    uint32_t count = 0;
    347343    uint32_t str   = (uint32_t)u_str;
     344
     345assert( (CURRENT_THREAD->process->pid > 0), "must be called by an user thread" );
    348346
    349347    hal_disable_irq( &save_sr );
  • trunk/hal/tsar_mips32/drivers/soclib_nic.c

    r657 r658  
    22 * soclib_nic.c - SOCLIB_NIC (Network Interface Controler) driver implementation.
    33 *
    4  * Author     Alain Greiner (2016,2017,2018,2019,2020:)
     4 * Author     Alain Greiner (2016,2017,2018,2019,2020)
    55 *
    66 * Copyright (c) UPMC Sorbonne Universites
     
    3333#include <soclib_nic.h>
    3434
     35
     36////////////////////////////////////////////////////////////////////////////////////////
     37// Extern global variables
     38////////////////////////////////////////////////////////////////////////////////////////
     39
     40extern chdev_directory_t  chdev_dir;     // allocated in kernel_init.c
     41
     42#if DEBUG_HAL_NIC_TX || DEBUG_HAL_NIC_RX
     43
     44////////////////////////////////////////////////////////////////////////////////////////
     45//          static function used for SOCLIB_NIC driver debug
     46////////////////////////////////////////////////////////////////////////////////////////
     47static void soclib_nic_chbuf_display( nic_chbuf_t * chbuf,
     48                                      char        * name )
     49{
     50    uint32_t i;
     51
     52    // software L2/L3 cache coherence for chbuf WID & RID read
     53    if( chdev_dir.iob )  dev_mmc_inval( XPTR ( local_cxy , chbuf ) , 8 );
     54
     55    // get pointers on TXT0 chdev
     56    xptr_t    txt0_xp  = chdev_dir.txt_tx[0];
     57    cxy_t     txt0_cxy = GET_CXY( txt0_xp );
     58    chdev_t * txt0_ptr = GET_PTR( txt0_xp );
     59
     60    // get extended pointer on remote TXT0 chdev lock
     61    xptr_t  lock_xp = XPTR( txt0_cxy , &txt0_ptr->wait_lock );
     62
     63    // get TXT0 lock
     64    remote_busylock_acquire( lock_xp );
     65
     66    nolock_printk("\n***** chbuf %s : ptr %x / wid %d / rid %d *****\n",
     67    name, chbuf, chbuf->wid, chbuf->rid );
     68
     69    for( i = 0 ; i < SOCLIB_NIC_CHBUF_DEPTH ; i++ )
     70    {
     71        uint32_t * container = chbuf->cont_ptr[i];
     72
     73        // software L2/L3 cache coherence for container STS & PLEN read
     74        if( chdev_dir.iob ) dev_mmc_inval( XPTR( local_cxy , container + 510 ), 8 );
     75
     76        if( container[511] )
     77        {
     78            nolock_printk(" - %d : FULL  / cont_ptr %x / cont_pad [%x,%x] / plen %d\n",
     79            i, chbuf->cont_ptr[i],
     80            (uint32_t)(chbuf->cont_pad[i]>>32),
     81            (uint32_t)chbuf->cont_pad[i],
     82            container[510] );
     83        }
     84        else
     85        {
     86            nolock_printk(" - %d : EMPTY / cont_ptr %x / cont_pad [%x,%x]\n",
     87            i, chbuf->cont_ptr[i],
     88            (uint32_t)(chbuf->cont_pad[i]>>32),
     89            (uint32_t)chbuf->cont_pad[i] );
     90        }
     91    }
     92
     93    // release TXT0 lock
     94    remote_busylock_release( lock_xp );
     95
     96}  // end soclib_nic_chbuf_display()
     97
     98#endif
     99
    35100///////////////////////////////////////
    36101void soclib_nic_init( chdev_t * chdev )
     
    38103    uint32_t    i;
    39104    kmem_req_t  req;
     105    ppn_t       ppn;
     106    uint64_t    padr;
    40107
    41108    // set driver specific fields in chdev descriptor
    42109    chdev->cmd = &soclib_nic_cmd;
    43110    chdev->isr = &soclib_nic_isr;
     111
     112    // get chdev channel & direction
     113    bool_t   is_rx   = chdev->is_rx;
     114    uint32_t channel = chdev->channel;
    44115   
    45     // get hardware device cluster and local pointer
     116    // get NIC device cluster and local pointer
    46117    cxy_t      nic_cxy  = GET_CXY( chdev->base );
    47     uint32_t * nic_ptr  = (uint32_t *)GET_PTR( chdev->base );
    48 
    49     // initialize Soclib NIC global registers
    50     hal_remote_s32( XPTR( nic_cxy , nic_ptr + NIC_GLOBAL_SPAN + NIC_G_BC_ENABLE ) , 0 );
    51     hal_remote_s32( XPTR( nic_cxy , nic_ptr + NIC_GLOBAL_SPAN + NIC_G_RUN       ) , 0 );
    52 
    53     // allocate memory for chbuf descriptor (one page)
    54     assert( (sizeof(nic_chbuf_t) <= CONFIG_PPM_PAGE_SIZE ) ,
    55             "chbuf descriptor exceeds one page" );
    56 
    57     req.type   = KMEM_PPM;
    58     req.order  = 0;
     118    uint32_t * nic_ptr  = GET_PTR( chdev->base );
     119
     120#if DEBUG_HAL_NIC_TX || DEBUG_HAL_NIC_RX
     121thread_t * this  = CURRENT_THREAD;
     122uint32_t   cycle = (uint32_t)hal_get_cycles();
     123if( (is_rx == false) && DEBUG_HAL_NIC_RX < cycle )
     124printk("\n[%s] thread[%x,%x] enter : NIC_TX channel %d / chdev %x / base %x / cycle %d\n",
     125__FUNCTION__, this->process->pid, this->trdid, channel, chdev, nic_ptr, cycle );
     126if( is_rx && DEBUG_HAL_NIC_RX < cycle )
     127printk("\n[%s] thread[%x,%x] enter : NIC_RX channel %d / chdev %x / base %x / cycle %d\n",
     128__FUNCTION__, this->process->pid, this->trdid, channel, chdev, nic_ptr, cycle );
     129#endif
     130
     131    // get number of channels from hardware
     132    uint32_t channels = hal_remote_l32( XPTR( nic_cxy,
     133                        nic_ptr + NIC_GLOBAL_OFFSET + NIC_G_CHANNELS ));
     134
     135    // check value registered in cluster descriptor
     136    if( LOCAL_CLUSTER->nb_nic_channels != channels )
     137    {
     138        printk("\n[PANIC] in %s : channels[soft] (%d) != channels[hard] (%d)\n",
     139        __FUNCTION__, LOCAL_CLUSTER->nb_nic_channels, channels );
     140        return;
     141    }
     142
     143    // check channel index
     144    if( channel >= channels )
     145    {
     146        printk("\n[PANIC] in %s illegal channel index\n", __FUNCTION__ );
     147        return;
     148    }
     149
     150    // allocate memory for chbuf descriptor
     151    req.type   = KMEM_KCM;
     152    req.order  = bits_log2( sizeof(nic_chbuf_t) );
    59153    req.flags  = AF_KERNEL;
    60 
    61154    nic_chbuf_t * chbuf = kmem_alloc( &req );
    62155
    63156    if( chbuf == NULL )
    64157    {
    65         printk("\n[PANIC] in %s : cannot allocate chbuf descriptor\n",
    66         __FUNCTION__ );
    67     }
    68 
    69     // initialise chbuf state
    70     chbuf->cont_id  = 0;
    71     chbuf->pkt_id   = 0;
    72     chbuf->word_id  = 34;
     158        printk("\n[PANIC] in %s : cannot allocate chbuf descriptor\n", __FUNCTION__ );
     159        return;
     160    }
     161
     162    // initialise chbuf indexes
     163    chbuf->wid  = 0;
     164    chbuf->rid  = 0;
     165     
     166    // software L2/L3 cache coherence for chbuf WID & RID     
     167    if( chdev_dir.iob ) dev_mmc_sync( XPTR( local_cxy , chbuf ) , 8 );
    73168   
    74     // allocate containers (one page per container)
    75     // and complete chbuf descriptor initialization
    76     assert( (CONFIG_PPM_PAGE_SIZE == 4096) ,
    77             "chbuf container must be 4 Kbytes" );
    78 
    79     for( i = 0 ; i < CONFIG_NIC_CHBUF_DEPTH ; i++ )
    80     {
    81         uint32_t * container = kmem_alloc( &req );   
    82 
    83         assert( (container != NULL) ,
    84                 "cannot allocate container" );
     169    // allocate containers and complete chbuf initialisation
     170    for( i = 0 ; i < SOCLIB_NIC_CHBUF_DEPTH ; i++ )
     171    {
     172        // 2048 bytes per container
     173        req.type   = KMEM_KCM;
     174        req.order  = 11;
     175        req.flags  = AF_KERNEL;
     176        uint32_t * container  = kmem_alloc( &req );
     177
     178        if( container == NULL )
     179        {
     180            printk("\n[PANIC] in %s : cannot allocate container\n", __FUNCTION__ );
     181            return;
     182        }
     183
     184        // initialize container as empty
     185        container[511] = 0;
     186
     187        // software L2/L3 cache coherence for container STS       
     188        if( chdev_dir.iob ) dev_mmc_sync( XPTR( local_cxy , &container[511] ) , 4 );
     189
     190        // compute container physical address
     191        ppn  = ppm_base2ppn( XPTR( local_cxy , container ) );
     192        padr = ((uint64_t)ppn << CONFIG_PPM_PAGE_SHIFT) |
     193               ((intptr_t)container & CONFIG_PPM_PAGE_MASK);
     194
     195        // complete chbuf initialisation       
     196        chbuf->cont_ptr[i] = container;
     197        chbuf->cont_pad[i] = padr;
     198    }
     199
     200    // software L2/L3 cache coherence for chbuf descriptor
     201    if( chdev_dir.iob ) dev_mmc_sync( XPTR( local_cxy , chbuf ),
     202                                      sizeof(nic_chbuf_t) );
     203
     204    // get NIC channel segment base and chbuf depth
     205    uint32_t * channel_base = nic_ptr + NIC_CHANNEL_SPAN * channel;
     206    uint32_t   nbufs        = SOCLIB_NIC_CHBUF_DEPTH;
     207   
     208    // compute chbuf physical address
     209    ppn  = ppm_base2ppn( XPTR( local_cxy , chbuf ) );
     210    padr = ((uint64_t)ppn  << CONFIG_PPM_PAGE_SHIFT) |
     211           ((intptr_t)chbuf & CONFIG_PPM_PAGE_MASK);
     212
     213    uint32_t low  = (uint32_t)(padr);
     214    uint32_t high = (uint32_t)(padr >> 32);
     215
     216    // initialize the NIC channel registers
     217    if( is_rx )
     218    {
     219        hal_remote_s32( XPTR( nic_cxy , channel_base + NIC_RX_CHBUF_DESC_LO ) , low );
     220        hal_remote_s32( XPTR( nic_cxy , channel_base + NIC_RX_CHBUF_DESC_HI ) , high );
     221        hal_remote_s32( XPTR( nic_cxy , channel_base + NIC_RX_CHBUF_NBUFS   ) , nbufs );
     222
     223        hal_fence();
     224
     225        hal_remote_s32( XPTR( nic_cxy , channel_base + NIC_RX_CHANNEL_RUN   ) , 1 );
     226    }
     227    else
     228    {
     229        hal_remote_s32( XPTR( nic_cxy , channel_base + NIC_TX_CHBUF_DESC_LO ) , low );
     230        hal_remote_s32( XPTR( nic_cxy , channel_base + NIC_TX_CHBUF_DESC_HI ) , high );
     231        hal_remote_s32( XPTR( nic_cxy , channel_base + NIC_TX_CHBUF_NBUFS   ) , nbufs );
     232
     233        hal_fence();
     234
     235        hal_remote_s32( XPTR( nic_cxy , channel_base + NIC_TX_CHANNEL_RUN   ) , 1 );
     236    }
     237
     238    // register chbuf pointer in chdev descriptor extension
     239    chdev->ext.nic.queue = chbuf;
    85240       
    86         chbuf->cont[i] = container;
    87         chbuf->full[i] = (paddr_t)XPTR( local_cxy , container );
    88     }
     241#if DEBUG_HAL_NIC_TX || DEBUG_HAL_NIC_RX
     242cycle = (uint32_t)hal_get_cycles();
     243if( (is_rx == false) && DEBUG_HAL_NIC_RX < cycle )
     244printk("\n[%s] thread[%x,%x] exit / NIC_TX channel %d / chbuf %x / cycle %d\n",
     245__FUNCTION__, this->process->pid, this->trdid, channel, chbuf, cycle );
     246if( is_rx && DEBUG_HAL_NIC_RX < cycle )
     247printk("\n[%s] thread[%x,%x] exit / NIC_RX channel %d / chbuf %x / cycle %d\n",
     248__FUNCTION__, this->process->pid, this->trdid, channel, chbuf, cycle );
     249soclib_nic_chbuf_display( chbuf , chdev->name );
     250#endif
     251
    89252} // end soclib_nic_init()
    90 
    91253
    92254//////////////////////////////////////////////////////////////////
     
    94256{
    95257    uint32_t       type;         // command type   
    96     char         * buffer;       // pointer on command buffer   
     258    uint8_t      * buffer;       // pointer on command buffer   
    97259    uint32_t       length;       // Ethernet packet length
    98     xptr_t         dev_xp;       // extended pointer on NIC device
     260    xptr_t         dev_xp;       // extended pointer on NIC chdev
     261    chdev_t      * dev_ptr;      // local pointer on NIC chdev
     262    cxy_t          dev_cxy;      // NIC chdev cluster identifier
    99263    nic_chbuf_t  * chbuf;        // pointer on chbuf descriptor
    100     uint32_t       cont_id;      // index of current container in chbuf
    101     uint32_t       pkt_id;       // index of current packet in container
    102     uint32_t       word_id;      // index of first word of current packet in container
     264    uint32_t       index;        // index of current container in chbuf
    103265    uint32_t     * container;    // pointer on container (array of uint32_t)
    104     uint16_t     * header;       // pointer on container header (array of uint16_t)
    105     uint32_t       npackets;     // number of packets in current container
    106 
    107     // get local pointer for client thread
    108     thread_t * thread_ptr = (thread_t *)GET_PTR( thread_xp );
    109 
    110     // get command arguments
    111     type   = thread_ptr->nic_cmd.type;
    112     buffer = thread_ptr->nic_cmd.buffer;
    113     length = thread_ptr->nic_cmd.length;
    114     dev_xp = thread_ptr->nic_cmd.dev_xp;
    115 
    116     // get local pointer for device
    117     chdev_t * dev_ptr = (chdev_t *)GET_PTR( dev_xp );
    118 
    119     // get chbuf descriptor pointer
    120     chbuf = (nic_chbuf_t *)dev_ptr->ext.nic.queue;
     266
     267    thread_t * this = CURRENT_THREAD;
     268
     269// check calling thread == client thread
     270assert( (thread_xp == XPTR( local_cxy , this )), "calling thread must be the client thread");
     271 
     272    // get command type
     273    type    = this->nic_cmd.type;
     274
     275    // get chdev pointers for device
     276    dev_xp  = this->nic_cmd.dev_xp;
     277    dev_ptr = GET_PTR( dev_xp );
     278    dev_cxy = GET_CXY( dev_xp );
    121279
    122280    // analyse command type
    123281    switch( type )
    124282    {
    125         /////////////////////////////////////////////////////////////////////////////
    126         case NIC_CMD_READ:   // transfer one packet from RX queue to command buffer
    127         {
    128             // get current container index
    129             cont_id = chbuf->cont_id;
     283        //////////////////////////////////////////////////////////////////////////
     284        case NIC_CMD_WRITE:  // move one packet from command buffer to TX queue
     285        {
     286
     287// check chdev is local
     288assert( (dev_cxy == local_cxy), "illegal cluster for a WRITE command");
    130289           
    131             assert( chbuf->full[cont_id] == 0 , "Read an empty container\n" );
    132 
    133             // get pointer on container and header
    134             container = chbuf->cont[cont_id];
    135             header    = (uint16_t *)container;
    136 
    137             // get  expected packet index and first word index in container
    138             pkt_id  = chbuf->pkt_id;
    139             word_id = chbuf->word_id;
    140 
    141             // get packet length and number of packets from container header
    142             length    = header[pkt_id + 2];
    143             npackets  = header[0];
    144 
    145             assert( pkt_id >= npackets,
    146                 "Read a non readable container, packet index too large\n");
    147 
    148             // move the packet from container to buffer
    149             memcpy( buffer , container + word_id , length );
    150 
    151             // update current packet index and first word index
    152             chbuf->pkt_id  = pkt_id + 1;
    153             if( length & 0x3 ) chbuf->word_id = word_id + (length>>2) + 1;
    154             else               chbuf->word_id = word_id + (length>>2);
     290            // get command arguments
     291            buffer = this->nic_cmd.buffer;
     292            length = this->nic_cmd.length;
     293
     294// check packet length
     295assert( (length <= 2040), "packet length too large");
     296
     297            // get chbuf descriptor pointer
     298            chbuf = (nic_chbuf_t *)dev_ptr->ext.nic.queue;
     299
     300            // software L2/L3 cache coherence for chbuf WID read
     301            if( chdev_dir.iob )  dev_mmc_inval( XPTR ( local_cxy , chbuf ) , 8 );
     302
     303            // get container write index
     304            index = chbuf->wid;
     305
     306            // get pointer on container (no L2/L3 cache coherence required)
     307            container = chbuf->cont_ptr[index];
     308
     309            // software L2/L3 cache coherence for container STS read
     310            if( chdev_dir.iob )  dev_mmc_inval( XPTR ( local_cxy , &container[511]) , 4 );
     311
     312#if DEBUG_HAL_NIC_TX
     313uint32_t   cycle = (uint32_t)hal_get_cycles();
     314if( DEBUG_HAL_NIC_TX < cycle )
     315printk("\n[%s] thread[%x,%x] enter / WRITE / chdev %x / chbuf %x / len %d / cycle %d\n",
     316__FUNCTION__, this->process->pid, this->trdid, dev_ptr, chbuf, length, cycle );
     317soclib_nic_chbuf_display( chbuf , dev_ptr->name );
     318#endif
     319            // check container STS
     320            if( container[511] != 0 )   // container full
     321            {
     322                // return failure
     323                this->nic_cmd.status = 0;
     324                this->nic_cmd.error  = 0;
     325
     326#if DEBUG_HAL_NIC_TX
     327cycle = (uint32_t)hal_get_cycles();
     328if( DEBUG_HAL_NIC_TX < cycle )
     329printk("\n[%s] thread[%x,%x] WRITE failure : NIC_TX[%d] queue full / cycle %d\n",
     330__FUNCTION__, this->process->pid , this->trdid , dev_ptr->channel , cycle );
     331soclib_nic_chbuf_display( chbuf , dev_ptr->name );
     332#endif
     333            }
     334            else                                       // container empty
     335            {
     336                // move the packet from buffer to container
     337                memcpy( container , buffer , length );
     338
     339                // update packet length in container header
     340                container[510] = length;
     341
     342                hal_fence();
     343
     344                // update container STS
     345                container[511] = 1;
     346
     347                // update current container WID
     348                chbuf->wid = (index + 1) % SOCLIB_NIC_CHBUF_DEPTH;
     349
     350                // software L2/L3 cache coherence for container DATA write
     351                if( chdev_dir.iob ) dev_mmc_sync( XPTR( local_cxy , container ), length );
     352
     353                // software L2/L3 cache coherence for container LENGTH and STS write
     354                if( chdev_dir.iob ) dev_mmc_sync( XPTR( local_cxy , &container[510] ) , 8 );
     355               
     356                // software L2/L3 cache coherence for chbuf WID write
     357                if( chdev_dir.iob ) dev_mmc_sync( XPTR( local_cxy , chbuf ) , 8 );
     358
     359                // return success
     360                this->nic_cmd.status = length;
     361                this->nic_cmd.error  = 0;
     362
     363#if DEBUG_HAL_NIC_TX
     364cycle = (uint32_t)hal_get_cycles();
     365if( DEBUG_HAL_NIC_TX < cycle )
     366printk("\n[%s] thread[%x,%x] WRITE success on NIC_TX[%d] / len %d / cycle %d\n",
     367__FUNCTION__, this->process->pid, this->trdid, dev_ptr->channel , length, cycle );
     368soclib_nic_chbuf_display( chbuf , dev_ptr->name );
     369#endif
     370            }
     371        }
     372        break;  // end WRITE
     373
     374        /////////////////////////////////////////////////////////////////////////
     375        case NIC_CMD_READ:   // move one packet from RX queue to kernel buffer
     376        {
     377
     378// check chdev is local
     379assert( (dev_cxy == local_cxy), "illegal cluster for a READ command");
     380           
     381            // get target buffer
     382            buffer = this->nic_cmd.buffer;
     383
     384            // get chbuf descriptor pointer
     385            chbuf = (nic_chbuf_t *)dev_ptr->ext.nic.queue;
     386
     387            // software L2/L3 cache coherence for chbuf WID & RID read
     388            if( chdev_dir.iob )  dev_mmc_inval( XPTR ( local_cxy , chbuf ) , 8 );
     389
     390            // get container read index
     391            index = chbuf->rid;
     392           
     393            // get pointer on container (no L2/L3 cache coherence required)
     394            container = chbuf->cont_ptr[index];
     395
     396            // software L2/L3 cache coherence for container STS & PLEN read
     397            if( chdev_dir.iob ) dev_mmc_inval( XPTR( local_cxy , container + 510 ), 8 );
     398
     399#if DEBUG_HAL_NIC_RX
     400uint32_t   cycle = (uint32_t)hal_get_cycles();
     401if( DEBUG_HAL_NIC_RX < cycle )
     402printk("\n[%s] thread[%x,%x] enter / READ / chdev %x / chbuf %x / cycle %d\n",
     403__FUNCTION__, this->process->pid, this->trdid, dev_ptr, chbuf, cycle );
     404soclib_nic_chbuf_display( chbuf , dev_ptr->name );
     405#endif
     406            // check container state
     407            if( container[511] == 0 )   // container empty
     408            {
     409                // return failure
     410                this->nic_cmd.status = 0;
     411                this->nic_cmd.error  = 0;
     412
     413#if DEBUG_HAL_NIC_RX
     414cycle = (uint32_t)hal_get_cycles();
     415if( DEBUG_HAL_NIC_RX < cycle )
     416printk("\n[%s] thread[%x,%x] READ failure : NIC_RX[%d] queue empty / cycle %d\n",
     417__FUNCTION__, this->process->pid, this->trdid, dev_ptr->channel , cycle );
     418soclib_nic_chbuf_display( chbuf , dev_ptr->name );
     419#endif
     420            }
     421            else                      // container full
     422            {
     423                // get packet length from container
     424                length = container[510];
     425
     426                // software L2/L3 cache coherence for container DATA
     427                if( chdev_dir.iob ) dev_mmc_inval( XPTR( local_cxy , container) , length );
     428
     429                // move the packet from container to buffer
     430                memcpy( buffer , container , length );
     431
     432                hal_fence();
     433
     434                // update container STS
     435                container[511] = 0;
     436
     437                // update current container WID
     438                chbuf->rid = (index + 1) % SOCLIB_NIC_CHBUF_DEPTH;
     439
     440                // software L2/L3 cache coherence for container STS write
     441                if( chdev_dir.iob ) dev_mmc_sync( XPTR( local_cxy , &container[511] ), 4 );
     442
     443                // software L2/L3 cache coherence for chbuf RID write
     444                if( chdev_dir.iob )  dev_mmc_sync( XPTR ( local_cxy , chbuf ) , 8 );
     445
     446                // return success
     447                this->nic_cmd.status = length;
     448                this->nic_cmd.error  = 0;
     449
     450#if DEBUG_HAL_NIC_RX
     451uint32_t   cycle = (uint32_t)hal_get_cycles();
     452if( DEBUG_HAL_NIC_RX < cycle )
     453printk("\n[%s] thread[%x,%x] READ success on NIC_RX[%d] queue / len %d / cycle %d\n",
     454__FUNCTION__, this->process->pid, this->trdid , dev_ptr->channel , length , cycle );
     455soclib_nic_chbuf_display( chbuf , dev_ptr->name );
     456#endif
     457            }
    155458        }
    156459        break;    // end READ
    157460           
    158         //////////////////////////////////////////////////////////////////////////
    159         case NIC_CMD_WRITE:  // move one packet from command buffer to TX queue
    160         {
    161             // get current TX container indexes
    162             cont_id = chbuf->cont_id;
    163             pkt_id  = chbuf->pkt_id;
    164             word_id = chbuf->word_id;
    165 
    166             assert( chbuf->full[cont_id] != 0, "Write to a full container\n" );
    167 
    168             // get pointer on container and header
    169             container = chbuf->cont[cont_id];
    170             header    = (uint16_t *)container;
    171 
    172             assert( length > ((1024 - word_id) << 2),
    173                 "Write to a non writable container, packet length too large\n");
    174 
    175             // update packet length in container header
    176             header[pkt_id + 2] = (uint16_t)length;
    177 
    178             // move the packet from buffer to container
    179             memcpy( container + word_id , buffer , length );
    180 
    181             // update current packet index and first word index
    182             chbuf->pkt_id  = pkt_id + 1;
    183             if( length & 0x3 ) chbuf->word_id = word_id + (length>>2) + 1;
    184             else               chbuf->word_id = word_id + (length>>2);
    185         }
    186         break;  // end WRITE
    187 
    188         ////////////////////////////////////////////////////////////////////////////
    189         case NIC_CMD_WRITABLE:  // analyse chbuf status / update status if required
    190         {
    191             // get current container state
    192             cont_id = chbuf->cont_id;
    193             word_id = chbuf->word_id;
    194 
    195             // compute current container writable
    196             bool_t ok = ( chbuf->full[cont_id] == 0 ) &&
    197                         ( length <= ((1024 - word_id)<<2) );
    198 
    199             if( ok )                // current container writable
    200             {
    201                 // return chbuf writable
    202                 thread_ptr->nic_cmd.status = true;
    203             }
    204             else                    // current container not writable
    205             {
    206                 // release current container
    207                 chbuf->full[cont_id] = 1;
    208 
    209                 // check next container
    210                 cont_id = (cont_id + 1) % CONFIG_NIC_CHBUF_DEPTH;
    211 
    212                 if( chbuf->full[cont_id] == 0 ) // next container empty
    213                 {
    214                     // update chbuf status
    215                     chbuf->word_id = 34;
    216                     chbuf->cont_id = cont_id;
    217                     chbuf->pkt_id  = 0;
    218                      
    219                     // return chbuf writable
    220                     thread_ptr->nic_cmd.status = true;
    221                 }
    222                 else                            // next container full     
    223                 {
    224                     // return chbuf non writable
    225                     thread_ptr->nic_cmd.status = false;
    226                 }
    227             }
    228         }
    229         break;  // end WRITABLE
    230 
    231         /////////////////////////////////////////////////////////////////////////////
    232         case NIC_CMD_READABLE:  // analyse chbuf status / update status if required
    233         {
    234             // get current container state
    235             cont_id  = chbuf->cont_id;
    236             pkt_id   = chbuf->pkt_id;
    237             npackets = chbuf->cont[cont_id][0] & 0x0000FFFF;
    238            
    239             // compute current container readable
    240             bool_t ok = ( chbuf->full[cont_id] == 1 ) &&
    241                         ( pkt_id < npackets );
    242 
    243             if( ok )                    // current container readable
    244             {
    245                 // return chbuf readable     
    246                 thread_ptr->nic_cmd.status = true;
    247             }
    248             else                        // current container non readable
    249             {
    250                 // release current container
    251                 chbuf->full[cont_id] = 0;
    252 
    253                 // check next container
    254                 cont_id = (cont_id + 1) % CONFIG_NIC_CHBUF_DEPTH;
    255 
    256                 if( chbuf->full[cont_id] == 1 ) // next container full
    257                 {
    258                     // update chbuf status
    259                     chbuf->word_id = 34;
    260                     chbuf->cont_id = cont_id;
    261                     chbuf->pkt_id  = 0;
    262                      
    263                     // return chbuf readable
    264                     thread_ptr->nic_cmd.status = true;
    265                 }
    266                 else                            // next container empty   
    267                 {
    268                     // return chbuf non readable
    269                     thread_ptr->nic_cmd.status = false;
    270                 }
    271             }
    272    
    273         }
    274         break;  // end READABLE
    275         default: {
     461        /////////////////////////////////////////////////////////////////////
     462        case NIC_CMD_GET_KEY:      // return channel from IP addr & port
     463        {
     464            // get number of NIC channels
     465            uint32_t channels = LOCAL_CLUSTER->nb_nic_channels;
     466 
     467            // get IP address and port from command in thread descriptor
     468            uint32_t addr = (intptr_t)this->nic_cmd.buffer;
     469            uint16_t port = (uint16_t)this->nic_cmd.length;
     470 
     471            // compute NIC channel index
     472            uint32_t key = ( ((addr     ) & 0xFF) +
     473                             ((addr > 8 ) & 0xFF) +
     474                             ((addr > 16) & 0xFF) +
     475                             ((addr > 24) & 0xFF) +
     476                             ((port     ) & 0xFF) +
     477                             ((port > 8 ) & 0xFF) ) % channels;
     478
     479            // return key in "status" and return "error"
     480            this->nic_cmd.status = key;
     481            this->nic_cmd.error  = 0;
     482        }
     483        break;  // end GET_KEY
     484
     485        /////////////////////////////////////////////////////////////////////
     486        case NIC_CMD_SET_RUN:       // activate/desactivate one NIC channel
     487        {
     488            // get pointers on NIC peripheral
     489            xptr_t     base_xp  = dev_ptr->base;
     490            uint32_t * base_ptr = GET_PTR( base_xp );
     491            cxy_t      base_cxy = GET_CXY( base_xp );
     492
     493            // get channel and run from the "length" and "status" arguments
     494            uint32_t channel = this->nic_cmd.length;
     495            uint32_t run     = this->nic_cmd.status;
     496
     497            // build pointers on channel base
     498            uint32_t * channel_ptr = base_ptr + NIC_CHANNEL_SPAN * channel;
     499
     500            // set new value in NIC_RX_CHANNEL_RUN & NIC_TX_CHANNEL_RUN registers
     501            hal_remote_s32( XPTR( base_cxy , channel_ptr + NIC_RX_CHANNEL_RUN ) , run );
     502            hal_remote_s32( XPTR( base_cxy , channel_ptr + NIC_TX_CHANNEL_RUN ) , run );
     503
     504            // return "error"
     505            this->nic_cmd.error  = 0;
     506        }
     507        break;  // end SET_RUN
     508
     509        /////////////////////////////////////////////////////////////////////
     510        case NIC_CMD_GET_INSTRU:     // diplay packets counters on TXT0
     511        {
     512            // get pointers on NIC peripheral
     513            xptr_t     base_xp  = dev_ptr->base;
     514            uint32_t * base_ptr = GET_PTR( base_xp );
     515            cxy_t      base_cxy = GET_CXY( base_xp );
     516
     517            // build pointer on global register base
     518            uint32_t * global_ptr = base_ptr + NIC_GLOBAL_OFFSET;
     519
     520            uint32_t rx_g2s_received      = hal_remote_l32( XPTR( base_cxy ,
     521                                            global_ptr + NIC_G_NPKT_RX_G2S_RECEIVED ));
     522            uint32_t rx_g2s_discarded     = hal_remote_l32( XPTR( base_cxy ,
     523                                            global_ptr + NIC_G_NPKT_RX_G2S_DISCARDED ));
     524            uint32_t rx_des_success       = hal_remote_l32( XPTR( base_cxy ,
     525                                            global_ptr + NIC_G_NPKT_RX_DES_SUCCESS ));
     526            uint32_t rx_des_too_small     = hal_remote_l32( XPTR( base_cxy ,
     527                                            global_ptr + NIC_G_NPKT_RX_DES_TOO_SMALL ));
     528            uint32_t rx_des_too_big       = hal_remote_l32( XPTR( base_cxy ,
     529                                            global_ptr + NIC_G_NPKT_RX_DES_TOO_BIG ));
     530            uint32_t rx_des_mfifo_full    = hal_remote_l32( XPTR( base_cxy ,
     531                                            global_ptr + NIC_G_NPKT_RX_DES_MFIFO_FULL ));
     532            uint32_t rx_des_crc_fail      = hal_remote_l32( XPTR( base_cxy ,
     533                                            global_ptr + NIC_G_NPKT_RX_DES_CRC_FAIL ));
     534            uint32_t rx_disp_received     = hal_remote_l32( XPTR( base_cxy ,
     535                                            global_ptr + NIC_G_NPKT_RX_DISP_RECEIVED ));
     536            uint32_t rx_disp_dst_fail     = hal_remote_l32( XPTR( base_cxy ,
     537                                            global_ptr + NIC_G_NPKT_RX_DISP_DST_FAIL ));
     538            uint32_t rx_disp_ch_full      = hal_remote_l32( XPTR( base_cxy ,
     539                                            global_ptr + NIC_G_NPKT_RX_DISP_CH_FULL ));
     540
     541            uint32_t tx_disp_received     = hal_remote_l32( XPTR( base_cxy ,
     542                                            global_ptr + NIC_G_NPKT_TX_DISP_RECEIVED ));
     543            uint32_t tx_disp_too_small    = hal_remote_l32( XPTR( base_cxy ,
     544                                            global_ptr + NIC_G_NPKT_TX_DISP_TOO_SMALL ));
     545            uint32_t tx_disp_too_big      = hal_remote_l32( XPTR( base_cxy ,
     546                                            global_ptr + NIC_G_NPKT_TX_DISP_TOO_BIG ));
     547            uint32_t tx_disp_transmit     = hal_remote_l32( XPTR( base_cxy ,
     548                                            global_ptr + NIC_G_NPKT_TX_DISP_TRANSMIT ));
     549
     550            printk("\n*** NIC device Instrumentation ***\n\n"
     551                   " - rx_g2s_received   = %d\n"
     552                   " - rx_g2s_discarded  = %d\n"
     553                   " - rx_des_success    = %d\n"
     554                   " - rx_des_too_small  = %d\n"
     555                   " - rx_des_too_big    = %d\n"
     556                   " - rx_des_mfifo_full = %d\n"
     557                   " - rx_des_crc_fail   = %d\n"
     558                   " - rx_disp_received  = %d\n"
     559                   " - rx_disp_dsp_fail  = %d\n"
     560                   " - rx_disp_ch_full   = %d\n\n"
     561                   " - tx_disp_received  = %d\n"
     562                   " - tx_disp_too_small = %d\n"
     563                   " - tx_disp_too_big   = %d\n"
     564                   " - tx_disp_transmit  = %d\n",
     565                   rx_g2s_received,
     566                   rx_g2s_discarded,
     567                   rx_des_success,
     568                   rx_des_too_small,
     569                   rx_des_too_big,
     570                   rx_des_mfifo_full,
     571                   rx_des_crc_fail,
     572                   rx_disp_received,
     573                   rx_disp_dst_fail,
     574                   rx_disp_ch_full,
     575                   tx_disp_received,
     576                   tx_disp_too_small,
     577                   tx_disp_too_big,
     578                   tx_disp_transmit );
     579
     580            // return "error"
     581            this->nic_cmd.error  = 0;
     582        }
     583        break;  // end CLEAR_INSTRU
     584
     585        /////////////////////////////////////////////////////////////////////
     586        case NIC_CMD_CLEAR_INSTRU:  // reset instrumentation registers
     587        {
     588            // get pointers on NIC peripheral
     589            xptr_t     base_xp  = dev_ptr->base;
     590            uint32_t * base_ptr = GET_PTR( base_xp );
     591            cxy_t      base_cxy = GET_CXY( base_xp );
     592
     593            // build pointer on relevant NIC register
     594            uint32_t * reset_ptr = base_ptr + NIC_GLOBAL_OFFSET + NIC_G_NPKT_RESET;
     595
     596            // reset all NIC instrumentation registers
     597            hal_remote_s32( XPTR( base_cxy , reset_ptr ) , 0 );
     598
     599            // return "error"
     600            this->nic_cmd.error  = 0;
     601        }
     602        break;  // end GET_INSTRU
     603
     604        default:
     605        {
    276606            assert( false, "Unknown command <%x>\n", type );
    277607        }
     
    284614{
    285615    // get base, size, channel, is_rx from NIC channel device NIC
    286     xptr_t     base    = chdev->base;
     616    xptr_t     base_xp = chdev->base;
    287617    uint32_t   channel = chdev->channel;
    288618    bool_t     is_rx   = chdev->is_rx;
    289619
    290620    // get NIC peripheral cluster and local pointer
    291     cxy_t      cxy_nic = GET_CXY( base );
    292     uint32_t * ptr_nic = (uint32_t *)GET_PTR( base );
    293 
    294     // compute local pointer on status register
    295     uint32_t * offset;
    296     if( is_rx ) offset = ptr_nic + (NIC_CHANNEL_SPAN * (channel + 1)) + NIC_RX_STATUS;
    297     else        offset = ptr_nic + (NIC_CHANNEL_SPAN * (channel + 1)) + NIC_TX_STATUS;
     621    cxy_t      nic_cxy = GET_CXY( base_xp );
     622    uint32_t * nic_ptr = GET_PTR( base_xp );
     623
     624    // compute local pointer on state register
     625    uint32_t  * ptr;
     626    if( is_rx ) ptr = nic_ptr + (NIC_CHANNEL_SPAN * channel) + NIC_RX_CHANNEL_STATE;
     627    else        ptr = nic_ptr + (NIC_CHANNEL_SPAN * channel) + NIC_TX_CHANNEL_STATE;
    298628
    299629    // read NIC channel status and acknowledge IRQ
    300     uint32_t status = hal_remote_l32( XPTR( cxy_nic , offset ) );
    301 
    302     assert( status != 0, "Illegal address: \n" );
     630    uint32_t status = hal_remote_l32( XPTR( nic_cxy , ptr ) );
     631
     632// check status value
     633if( is_rx &&  (status != NIC_CHANNEL_STATUS_IDLE) )
     634printk("\n[PANIC] in %s : error reported by NIC_RX[%d]\n", __FUNCTION__, channel );
     635if( (is_rx == false) &&  (status != NIC_CHANNEL_STATUS_IDLE) )
     636printk("\n[PANIC] in %s : error reported by NIC_TX[%d]\n", __FUNCTION__, channel );
    303637
    304638    // unblock server thread
    305639    thread_t * server = chdev->server;
    306     thread_unblock( XPTR( local_cxy , server ) , THREAD_BLOCKED_IO );
     640    thread_unblock( XPTR( local_cxy , server ) , THREAD_BLOCKED_ISR );
     641
     642#if (DEBUG_HAL_NIC_RX || DEBUG_HAL_NIC_TX)
     643uint32_t   cycle = (uint32_t)hal_get_cycles();
     644if( is_rx && DEBUG_HAL_NIC_RX < cycle )
     645printk("\n[%s] ISR unblocks NIC_RX[%d] server thread / cycle %d\n",
     646__FUNCTION__, channel, cycle );
     647if( (is_rx == false) && DEBUG_HAL_NIC_TX < cycle )
     648printk("\n[%s] ISR unblocks NIC_TX[%d] server thread / cycle %d\n",
     649__FUNCTION__, channel, cycle );
     650#endif
    307651
    308652} // end soclib_nic_isr()
    309653
    310 
    311 
  • trunk/hal/tsar_mips32/drivers/soclib_nic.h

    r451 r658  
    22 * soclib_nic.h - SOCLIB_NIC (Network Interface Controler) driver definition.
    33 *
    4  * Author    Alain Greiner (2016)
     4 * Author    Alain Greiner (2016,2017,2018,2019,2020)
    55 *
    66 * Copyright (c) UPMC Sorbonne Universites
     
    3030/********************************************************************************************
    3131 * This driver supports the Soclib VciMasterNic component, that is a GMII compliant
    32  * multi-channels Gigabit Ethernet controler.
    33  *
    34  * The VciMasterNic component supports up to 4 channels, indexed by the source IP address
    35  * for the RX packets, and by the destination IP address for the TX packets.
     32 * multi-channels Gigabit Ethernet controler with a DMA capability.
     33 *
     34 * To improve the throughput, this component supports several channels.
     35 * The channel index is derived from the (source) remote IP address and port
     36 * for the received (RX) packets, and from the (destination) remote IP address
     37 * and port for the sent (TX) packets. The actual number of channels is an
     38 * hardware parameter that cannot be larger than 8.
     39 *
     40 * The Ethernet packet length can have any value, in range [42,1538] bytes.
    3641 *
    37  * The Ethernet packet length can have any value, between 64 to 1538 bytes.
    38  * The data transfer unit between software and the NIC is a 4 Kbytes "container",
    39  * containing an integer number of variable size packets.
    40  *
    41  * The max number of packets in a container is 66 packets.
    42  * The first 34 words of a container are the container header :
    43  *
    44  *     word0    |       NB_WORDS        |       NB_PACKETS      |
    45  *     word1    |       PLEN[0]         |       PLEN[1]         |
    46  *      ...         |   .......         |       ........        |
    47  *     word33   |       PLEN[64]        |       PLEN[65]        |
    48  *
    49  *  - NB_PACKETS is the actual number of packets in the container.
    50  *      - NB_WORDS   is the number of useful words in the container.
    51  *      - PLEN[i]    is the number of bytes for the packet[i].
    52  *
    53  * Packets are stored in the (1024 - 34) following words, and the packets are word-aligned.
    54  *
    55  * The TX and RX queues are implemented as chained buffers, where each buffer is a 4 Kbytes
    56  * container. Each container is protected by a SET/RESET synchronisation variable.
    57  * The structure implementing the chbuf descriptor is described below.
    58  *
    59  * To access both the container status, and the data contained in the container, the NIC
    60  * uses two physical addresses, that are packed in a 64 bits "container descriptor".
    61  * - desc[25:0]  contain bits[31:6] of the status physical address.
    62  * - desc[51:26] contain bits[31:6] of the buffer physical address.
    63  * - desc[63:52] contain the common 12 physical address extension bits.
    64  *******************************************************************************************/
    65 
    66 /********************************************************************************************
    67  *       Addressable registers offsets
     42 * For each channel, the received packets (RX) and the sent packets (TX) are stored
     43 * in two memory mapped software FIFOs, called NIC_TX_QUEUE and NIC_RX_QUEUE, implemented
     44 * as chained buffers (chbuf). Each slot in these FIFOs is a container, containing one
     45 * single packet. The number of containers, defining the queue depth, is a software defined
     46 * parameter. The data transfer unit between is a container (one single packet).
     47 *
     48 * - The "container" structure contains a 2040 bytes data buffer, the packet length, and
     49 *   the container state : full (owned by the reader) / empty (owned by the writer).
     50 *   For each container, the state variable is used as a SET/RESET flip-flop to synchronize
     51 *   the software server thread, and the hardware NIC DMA engines.
     52 *
     53 * - The "chbuf" descriptor contains an array of local pointers on the containers, used
     54 *   by the software driver, an array of physical addresses, used by the DMA engines and
     55 *   two "pointers", defining the current container to be written (wid) by the writer,
     56 *   and the current container to be read (rid) by the reader.
     57 *
     58 * WARNING : Both the chbuf descriptor (containing the <rid> and wid> indexes), and the
     59 *           containers themselve containing the <data> and the <sts> are shared variables
     60 *           accessed by the server threads (accessing the L2 caches), and by the NIC_DMA
     61 *           engines (accessing directly the L3 caches).
     62 *           Therefore, the L2/L3 cache coherence must be handled by this NIC driver for
     63 *           the INIT, READ & WRITE commands, using the MMC SYNC & INVAL commands. 
     64 *******************************************************************************************/
     65
     66/********************************************************************************************
     67 *   This section defines the NIC device addressable registers offsets:
     68 * - The 8 channels registers are stored in the first 512 bytes (8 * 64 bytes).
     69 * - The global registers are stored in the next 256 bytes (global offset is 512 bytes).
     70 *   All values defined below are number of words (one word = 4 bytes). 
    6871 *******************************************************************************************/
    6972
    7073enum SoclibMasterNicGlobalRegisters
    7174{
    72     NIC_G_RUN                        = 0,   /*! read_write : NIC component activated       */
    73     NIC_G_NB_CHANNELS                = 1,   /*! read_only  : number of channels            */
    74     NIC_G_BC_ENABLE                  = 2,   /*! read_write : broadcast enabled if non zero */
    75     NIC_G_PERIOD                     = 3,   /*! read-write : container status poll period  */
    76     NIC_G_MAC_4                      = 4,   /*! read-write : mac address 32 LSB bits       */
    77     NIC_G_MAC_2                      = 5,   /*! read-write : mac address 16 MSB bits       */
     75    NIC_G_CHANNELS                   = 1,   /*! read_only  : number of channels            */
     76    NIC_G_NPKT_RESET                 = 2,   /*! write-only : reset packets counters        */
    7877
    7978    NIC_G_NPKT_RX_G2S_RECEIVED       = 10,  /*! number of packets received                 */
    8079    NIC_G_NPKT_RX_G2S_DISCARDED      = 11,  /*! number of RX packets discarded by RX_G2S   */
     80
    8181    NIC_G_NPKT_RX_DES_SUCCESS        = 12,  /*! number of RX packets transmited by RX_DES  */
    8282    NIC_G_NPKT_RX_DES_TOO_SMALL      = 13,  /*! number of discarded too small RX packets   */
     
    8484    NIC_G_NPKT_RX_DES_MFIFO_FULL     = 15,  /*! number of discarded RX packets fifo full   */
    8585    NIC_G_NPKT_RX_DES_CRC_FAIL       = 16,  /*! number of discarded RX packets CRC32       */
    86     NIC_G_NPKT_RX_DISPATCH_RECEIVED  = 17,  /*! number of packets received by RX_DISPATCH  */
    87     NIC_G_NPKT_RX_DISPATCH_BROADCAST = 18,  /*! number of broadcast RX packets received    */
    88     NIC_G_NPKT_RX_DISPATCH_DST_FAIL  = 19,  /*! number of discarded RX packets for DST MAC */
    89     NIC_G_NPKT_RX_DISPATCH_CH_FULL   = 20,  /*! number of discarded RX packets cont full   */
    90 
    91     NIC_G_NPKT_TX_DISPATCH_RECEIVED  = 41,  /*! number of packets received by TX_DISPATCH  */
    92     NIC_G_NPKT_TX_DISPATCH_TOO_SMALL = 42,  /*! number of discarded too small TX packets   */
    93     NIC_G_NPKT_TX_DISPATCH_TOO_BIG   = 43,  /*! number of discarded too big TX packets     */
    94     NIC_G_NPKT_TX_DISPATCH_SRC_FAIL  = 44,  /*! number of discarded TX packets for SRC MAC */
    95     NIC_G_NPKT_TX_DISPATCH_BROADCAST = 45,  /*! number of broadcast TX packets received    */
    96     NIC_G_NPKT_TX_DISPATCH_TRANSMIT  = 46,  /*! number of transmit TX packets              */
    97 
    98     NIC_GLOBAL_SPAN                  = 64   /*! 256 bytes for global registers             */
     86
     87    NIC_G_NPKT_RX_DISP_RECEIVED      = 17,  /*! number of packets received by RX_DISPATCH  */
     88    NIC_G_NPKT_RX_DISP_DST_FAIL      = 18,  /*! number of discarded RX packets for DST MAC */
     89    NIC_G_NPKT_RX_DISP_CH_FULL       = 19,  /*! number of discarded RX packets cont full   */
     90
     91    NIC_G_NPKT_TX_DISP_RECEIVED      = 41,  /*! number of packets received by TX_DISPATCH  */
     92    NIC_G_NPKT_TX_DISP_TOO_SMALL     = 42,  /*! number of discarded too small TX packets   */
     93    NIC_G_NPKT_TX_DISP_TOO_BIG       = 43,  /*! number of discarded too big TX packets     */
     94    NIC_G_NPKT_TX_DISP_TRANSMIT      = 44,  /*! number of discarded TX packets for SRC MAC */
     95
     96    NIC_GLOBAL_OFFSET                = 128, /*! 512  bytes reserved for channel registers  */
    9997};
    10098
    10199enum SoclibMasterNicChannelRegisters
    102100{
    103     NIC_RX_STATUS             = 0,    /*! read-only  : RX channel status                  */
    104     NIC_RX_CHBUF_DESC_L0      = 1,    /*! read-write : RX chbuf descriptor 32 LSB bits     */
    105     NIC_RX_CHBUF_DESC_HI      = 2,    /*! read-write : RX chbuf descriptor 32 MSB bits     */ 
     101    NIC_RX_CHANNEL_RUN        = 0,    /*! write-only : RX channel activation/desactivation */
     102    NIC_RX_CHBUF_DESC_LO      = 1,    /*! read-write : RX chbuf descriptor 32 LSB bits     */
     103    NIC_RX_CHBUF_DESC_HI      = 2,    /*! read-write : RX chbuf descriptor 32 MSB bits     */
    106104    NIC_RX_CHBUF_NBUFS        = 3,    /*! read-write : RX chbuf depth (number of buffers)  */
    107    
    108     NIC_TX_STATUS             = 8,    /*! read-only  : TX channel status                   */
    109     NIC_TX_CHBUF_DESC_L0      = 9,    /*! read-write : TX chbuf descriptor 32 LSB bits     */
    110     NIC_TX_CHBUF_DESC_HI      = 10,   /*! read-write : TX chbuf descriptor 32 MSB bits     */
     105    NIC_RX_CHANNEL_STATE      = 4,    /*! read-only  : RX channel status                   */
     106
     107    NIC_TX_CHANNEL_RUN        = 8,    /*! write-only : TX channel activation               */
     108    NIC_TX_CHBUF_DESC_LO      = 9,    /*! read-write : TX chbuf descriptor 32 LSB bits     */
     109    NIC_TX_CHBUF_DESC_HI      = 10,   /*! read-write : TX chbuf descriptor 32 MSB bits     */
    111110    NIC_TX_CHBUF_NBUFS        = 11,   /*! read-write : TX chbuf depth (number of buffers)  */
     111    NIC_TX_CHANNEL_STATE      = 12,   /*! read-only  : TX channel status                   */
    112112
    113113    NIC_CHANNEL_SPAN          = 16    /*! 64 bytes per channel                             */
    114114};
    115    
    116 
    117 
    118 /********************************************************************************************
    119  * This structure defines the chained buffer descriptor, used to implement both
    120  * the RX and TX packets queues. Each buffer in a chbuf is a 4 Kbytes container
    121  * containing a variable number of packets. All containers are allocated in
    122  * the same cluster as the associated NIC device descriptor. The chbuf descriptor contains:
    123  * - an array of container pointers cont[], used by the kernet threads to access the
    124  *   packets contained in the containers.
    125  * - an array of set/reset Boolean full[] used by both the software threads and
    126  *   by the hardware FSMs for lock-less synchronisation.
    127  * - an array of containers descriptors containing the physical addresses of the
    128  *   "full[i]" and "cont[i]" variables, used by the DMA FSMs.
    129  * Moreover, It contains three pointers (cont_id, pkt_id, and word_id) that are private
    130  * variables used by the software thread to scan the chbuf.
    131  *******************************************************************************************/
     115
     116/********************************************************************************************
     117 *  Return values for the RX/TX channel master FSM status
     118 *******************************************************************************************/
     119
     120enum SoclibMasterNicStatusValues
     121{
     122    NIC_CHANNEL_STATUS_IDLE  = 0,
     123    NIC_CHANNEL_STATUS_ERROR = 1,
     124    NIC_CHANNEL_STATUS_BUSY  = 2,     // busy for any value >= 2
     125};
     126
     127/********************************************************************************************
     128 * This structure defines the chbuf descriptor, used to implement both the RX and TX packets
     129 * queues. Each container contains one single packet, and has only two states (full/empty).
     130 * All containers are allocated in the same cluster as the associated NIC chdev descriptor.
     131 * The chbuf descriptor contains:
     132 * - an array of containers physical addresses cont_pad[], used by the DMA engines.
     133 * - an array of container pointers cont_ptr[], used by the kernel threads.
     134 * - two indexes rid and wid, defining the next container for read & write respectively.
     135 * WARNING : dont modify this structure, used by the DMA engines.
     136 *******************************************************************************************/
     137
     138#define SOCLIB_NIC_CHBUF_DEPTH   8
    132139
    133140typedef struct nic_chbuf_s
    134141{
    135     uint32_t * cont[CONFIG_NIC_CHBUF_DEPTH]; /*! container virtual base address            */
    136     uint32_t   full[CONFIG_NIC_CHBUF_DEPTH]; /*! Boolean : container full if non zero      */
    137     uint64_t   desc[CONFIG_NIC_CHBUF_DEPTH]; /*! container & status physical addresses     */
    138     uint32_t   cont_id;                      /*! current container index                   */
    139     uint32_t   pkt_id;                       /*! current packet index in container         */
    140     uint32_t   word_id;                      /*! first word of current packet              */
     142    uint32_t   wid;                              /*! current container write index         */
     143    uint32_t   rid;                              /*! current container read index          */
     144    uint64_t   cont_pad[SOCLIB_NIC_CHBUF_DEPTH]; /*! containers physical base addresses    */
     145    uint32_t * cont_ptr[SOCLIB_NIC_CHBUF_DEPTH]; /*! containers virtual base addresses     */
    141146}
    142147nic_chbuf_t;
    143148
    144149/********************************************************************************************
    145  *        SOCLIB_NIC driver access functions
    146  *******************************************************************************************/
    147 
    148 /********************************************************************************************
    149  * This function initializes the SOCLIB_NIC hardware registers, allocates memory for
    150  * the RX and TX containers, allocates and initializes the RX and TX chbuf descriptors.
     150 * This structure defines the container descriptor format.
     151 *******************************************************************************************/
     152
     153typedef struct nic_cont_s
     154{
     155    uint8_t    buf[2040];                        /*! Ethernet packet (42 to 1538 bytes     */
     156    uint32_t   length;                           /*! actual packet length in bytes         */
     157    uint32_t   state;                            /*! zero == empty / non zero == full      */
     158}
     159nic_cont_t;
     160
     161/********************************************************************************************
     162 *    Driver access functions
     163 *******************************************************************************************/
     164
     165/********************************************************************************************
     166 * This function initializes the SOCLIB_NIC hardware registers, for one NIC chdev
     167 * (one direction of one channel). It allocates memory for the RX and TX containers,
     168 * it allocates and initializes the RX and TX chbuf descriptors.
    151169 * It allocates one WTI mailbox for the IRQ signaling availability of an RX full container,
    152170 * or a TX empty container, and route the WTI IRQ to the core running the server thread.
     171 * It activates the TX and RX DMA engines.
    153172 ********************************************************************************************
    154173 * @ chdev  :  pointer on NIC chdev descriptor.
     
    157176
    158177/********************************************************************************************
    159  * This function implement the READ / WRITE / READABLE / WRITABLE commands for TX/RX queues.
    160  * These command don't access the NIC peripheral but only the TX and TX chbufs.
    161  * It must be executed by a dedicated kernel thread running in the cluster containing
    162  * the CHBUF implementing the TX/RX queues.
    163  * It implements also the SET_MAC, SET_BC, SET_RUN configuration commands, that directly
    164  * access the NIC peripheral registers.
    165  * - READABLE
    166  *   Returns in the command "status" a non zero value if a packet is available in RX queue.
    167  *   Update the RX queue read pointer if required.
    168  * - READ
    169  *   Move a packet from the RX queue to the command "buffer", and returns the packet
    170  *   "length" in the command. The READABLE command must be called before the READ command.
    171  * - WRITABLE
    172  *   Returns in the command "status" a non zero value if a packet with a given "length"
    173  *   can be written in the TX queue. Update the RX queue read pointer if required.
    174  * - WRITE
     178 * 1) This function implement the READ & WRITE commands, used by the local server threads
     179 *    to access the NIC_TX & NIC_RX packets queues. These commands don't access the NIC
     180 *    registers but only the TX and RX chbufs implementing the queues:
     181 *
     182 * <READ>
     183 *   Move a packet from the NIC_RX queue to the command "buffer".
     184 *   Return 0 in "status" if queue empty / return length in "status" if success.
     185 *
     186 * <WRITE>
    175187 *   Move a packet of a given "length" from the command "buffer" to the TX queue.
    176  *   The WRITABLE command must be called before the WRITE command.
    177  * - SET_MAC
    178  *   Set the values defined in the "length" and "status" command arguments,
    179  *   into the NIC_C_MAC4 and NIG_G_MAC2  registers.
    180  * - SET_BC
    181  *   Enable/disable broadcast packets, as defined in the "status" command argument,
    182  *   into the NIC_G_BC_ENABLE register.
    183  * - SET_RUN
    184  *   Enable/disable NIC, as defined in the "status" command argument,
    185  *   into the NIC_G_RUN register.
    186  * @ dev_xp  : extended pointer on the generic NIC device descriptor.
    187  ********************************************************************************************
    188  $ @ thread_xp : extended pointer on client thread (containing the command arguments).
     188 *   Return 0 in "status" if queue full / return length in "status" if success.
     189 *
     190 * 2) It implements the GET_KEY / SET_RUN / GET_INSTRU / CLEAR_INSTRU commands,
     191 *    directly called by any thread running in any cluster to access the NIC registers :
     192 *
     193 * <GET_KEY>
     194 *   Return in "status" argument the channel index (key) computed from the IP address
     195 *   defined in the "buffer" argument, and from the port defined by the "length" argument.
     196 *
     197 * <SET_RUN>
     198 *   Enable/disable the NIC_TX_CHANNEL_RUN & NIC_RX_CHANNEL_RUN registers.The channel
     199 *   is defined in the "length" argument / run value defined in the "status" argument.
     200 *
     201 * <GET_INSTRU>
     202 *   Display on kernel TXT0 the contaent of all NIC instrumentation registers.
     203 *
     204 * <CLEAR_INSTRU>
     205 *   Reset all NIC instrumentation registers.
     206 *
     207 * Note (i)  For the NIC device, the command arguments are always registered in the calling
     208 *           thread descriptor (i.e. the calling thread is always the client thread).
     209 * Note (ii) The actual command mnemonics are defined in the <dev_nic.h> file.
    189210 *******************************************************************************************/
    190211extern void soclib_nic_cmd( xptr_t thread_xp );
    191212
    192213/********************************************************************************************
    193  * This ISR acknowledge the NIC_RX or NIC_TX channel ISR signaling that a new container
    194  * has beeen moved, and reactivate the corresponding server thread.
    195  * In case of address error reported by the NIC controler in accessing the kernel chbuf,
    196  * it goes to kernel panic.
     214 * This ISR is executed when a new RX container has been moved to an empty TX queue,
     215 * or when a TX container has been removed from a full TX queue. In both cases, it
     216 * reactivate the corresponding server thread from the BLOCKED_ISR condition.
     217 * It is also executed in case of error reported by the DMA engines accessing the TX or RX
     218 * queues. It simply print an error message on the kernel terminal.
     219 * TODO improve this error handling...
    197220 ********************************************************************************************
    198221 * @ chdev     : local pointer on NIC chdev descriptor.
  • trunk/hal/tsar_mips32/drivers/soclib_tty.c

    r625 r658  
    22 * soclib_tty.c - soclib tty driver 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
     
    418418
    419419                // remove process from TXT list
    420                 // process_txt_detach( owner_xp );
     420                process_txt_detach( owner_xp );
     421
     422                // close all open files
     423                process_fd_clean_all( owner_xp );
    421424
    422425                // mark for delete all thread in all clusters, but the main
Note: See TracChangeset for help on using the changeset viewer.