= GIET-VM / NIC_MNC Driver = [[PageOutline]] The [source:soft/giet_vm/giet_drivers/mnc_driver.c mnc_driver.c] and [source:soft/giet_vm/giet_drivers/mnc_driver.h mnc_driver.h] files define the NIC_MNC driver. This driver supports the vci_master_nic component, that is a Gigabit Ethernet network controller. This component has a DMA capability, to access the memory mapped RX and TX ethernet packets queues. These queues are implemented as the chained buffers structure ''nic_chbuf_t'', defined [source:soft/giet_vm/giet_drivers/mnc_driver.h here] . It can exist only one Ethernet network controller in the architecture, but to improve the throughput, it supports up to 4 channels (i.e. 4 TX and 4 RX queues), indexed by a key depending on the source IP address for the RX packets, and depending on the destination IP address for the TX packets. All channels use the same source MAC address. The Ethernet packet length can have any value, from 60 to 1538 bytes. The data transfer unit between software and the NIC is a 4 Kbytes "container", containing an integer number of variable size packets. The max number of packets in a container is 66 packets. The first 34 words of a container are the container header : || word0 || NB_WORDS || NB_PACKETS || || word1 || PLEN[0] || PLEN[1] || || ... || ....... || ........ || || word33 || PLEN[64] || PLEN[65] || NB_PACKETS is the actual number of packets in the container, NB_WORDS is the number of useful words in the container, PLEN[i] is the number of bytes for packet[i]. Packets are stored in the (1024 - 34) following words, and are word-aligned. Each 4 Kbytes container is protected by a SET/RESET ''status'' synchronisation variable. To access both the container status, and the container itself, the NIC uses two physical addresses, that are packed in a 64 bits "container descriptor". * desc[31:0] contain bits[31:0] of the status physical address. * desc[51:32] contain bits[31:12] of the buffer physical address. * desc[63:52] contain the common 12 physical address extension bits. To each TX or RX queue is associated a kernel thread that is in charge of moving the infinite stream of containers between the NIC and the RX/TX queue. The RX/TX queues (and the associated kernel threads) are physically distributed on various clusters, using a round robin policy (modulo the number of clusters). The actual number of channels NB_NIC_CHANNELS parameter, and the segment SEG_NIC_BASE address must be defined'' in the hard_config.h'' file. The addressable registers map is defined [source:soft/giet_vm/giet_drivers/mnc_driver.h here]. == __TX/RX queues __ == The following structure defines the chained buffer descriptor, used by the MNC driver to implement both the NIC_RX_QUEUE and NIC_TX_QUEUE. Each buffer is a 4K bytes container containing a variable number of packets. All containers are allocated in the same cluster. {{{ typedef struct nic_chbuf_s { unsigned long long desc[NIC_CHBUF_DEPTH]; unsigned int * cont[NIC_CHBUF_DEPTH]; unsigned int full[NIC_CHBUF_DEPTH]; unsigned int cont_id; unsigned int pkt_id; unsigned int word_id; unsigned int timeout; } nic_chbuf_t; }}} The chbuf descriptor contains: * an array of container pointers '''cont[]''', used by the kernel thread to access the packets contained in the containers. * an array of set/reset Boolean '''full[]''', used by both the kernel thread and by the hardware FSM for lock-less synchronisation. * an array of containers descriptors '''desc[]''', containing the physical addresses of the full[i] and cont[i] variables, is used by the NIC FSM. * the '''cont_id''' variable defines the current container for the kernel thread. * the '''pkt_id''' variable defines the current packet index for the kernel thread. * the '''word_id''' variable defines the current word index for the kernel thread. * the '''timeout''' variable defines the number of timeout checks for the kernel thread. The container descriptor is a 64 bits containing three fields: * the 26 LSB bits contain bits[31:6] of the status physical address. * the 26 following bits contain bits[31:6] of the buffer physical address. * the 12 MSB bits contain the common address extension. Three hardware parameters can be redefined if required. #define NIC_CHBUF_DEPTH 4 // number of containers #define NIC_CHBUF_WIDTH 4096 // single container size (bytes) #define NIC_CHBUF_TIMEOUT 10 // max number of retry for a TX-CHBUF == __Access Functions__ == === 1) void '''_mnc_init'''( ) === This function allocates memory for the RX_CHBUF and TX_CHBUF implementing the RX and TX queues for all channels. It uses a round-robin policy, to distribute one CHBUF per cluster if the number of clusters is larger than 2 * NB_NIC_CHANNELS. It initialises both the CHBUF descriptors, and the hardware NIC registers. === 2) unsigned int '''_mnc_tx_writable'''( unsigned int channel, unsigned int length ) === This function returns a Boolean indicating if an Ethernet packet of a given length can be stored in the TX queue defined by the channel argument. The internal state of the queue (write pointer) can be modified if required. * '''channel''' : channel index * '''length''' : register index * return a non-zero value if packet can be written / return zero if queue is full. === 3) void '''_mnc_tx_timeout( unsigned int channel ) === This function implements a watch dog for the TX-QUEUE associated to a given channel: It must be periodically called to check that TX packets are not waiting indefinitely in a partially filled container. If the container state has not been modified after NIC_CHBUF_TIMEOUT checks, it releases the current container to the NIC hardware. === 4) void '''_mnc_tx_write'''( unsigned int channel , char * buffer , unsigned int length ) === This function writes an Ethernet packet in the TX queue defined by the channel argument. It should be called after the _mnc_writable() function. * '''channel''' : channel index * '''buffer''' : pointer on buffer containing packet * '''length''' : Ethernet packet length (bytes) === 5) unsigned int '''_mnc_rx_readable'''( unsigned int channel , unsigned int * src_ip , unsigned int * src_port , unsigned int * dst_ip , unsigned int * dst_port , unsigned int * length ) === This function returns a Boolean indicating if an Ethernet packet is available in the RX queue defined by the channel argument. It also returns various informations contained in the IP and TCP/UDP headers. The internal state of the queue (read pointer) can be modified if required. * '''channel''' : channel index * '''src_ip''' : source IP address (from IP header) * '''src_port''' : source port index (from TCP/UDP header) * '''src_ip''' : source IP address (from IP header) * '''src_port''' : source port index (from TCP/UDP header) * '''length''' : Ethernet packet length (bytes) * return a non-zero value if packet can be read / return zero if queue is empty. === 6) void '''_mnc_rx_read'''( unsigned int channel , char * buffer ) === This function read an Ethernet packet from the RX queue defined by the channel argument. It should be called after the _mnc_readable() function. * '''channel''' : channel index * '''buffer''' : pointer on buffer containing packet === 7) void '''_mnc_set_global_register'''( unsigned int index , unsigned int value ) === This function set a given value in a given NIC global register. * '''index''' : register index * '''value''' : value to be written === 8) unsigned int '''_mnc_get_global_register'''( unsigned int index ) === This function returns the value contained in a given NIC global register. * '''index''' : register index * return value == __ Interrupt Service Routines__ == === 1) void '''_mnc_rx_isr'''( unsigned int irq_type, unsigned int irq_id, unsigned int channel ) === This Interrupt Service Routine handles IRQs from a NIC_RX channel. === 2) void '''_mnc_tx_isr'''( unsigned int irq_type, unsigned int irq_id, unsigned int channel ) === This Interrupt Service Routine handles IRQs from a NIC_TX channel.