Index: soft/giet_vm/sys/drivers.c
===================================================================
--- soft/giet_vm/sys/drivers.c	(revision 216)
+++ soft/giet_vm/sys/drivers.c	(revision 218)
@@ -24,5 +24,5 @@
 // - NB_TTYS    
 //
-// The following virtual base addresses must be defined in the giet.ld file:
+// The following virtual base addresses must be defined in the giet_vsegs.ld file:
 // - seg_icu_base
 // - seg_tim_base
@@ -32,4 +32,5 @@
 // - seg_fbf_base
 // - seg_ioc_base
+// - seg_nic_base
 // As some peripherals can be replicated in the clusters (ICU, TIMER, DMA)
 // These addresses must be completed by an offset depending on the cluster index
@@ -713,8 +714,7 @@
 //////////////////////////////////////////////////////////////////////////////////
 
-//+1: for the case where the NB_DMAS_MAX == 0
 #if NB_DMAS_MAX > 0
 in_unckdata unsigned int			_dma_lock[NB_DMAS_MAX * NB_CLUSTERS]
-                                       = { [0 ... ((NB_DMAS_MAX) * NB_CLUSTERS)-1] = 0 };
+                                       = { [0 ... (NB_DMAS_MAX * NB_CLUSTERS)-1] = 0 };
 
 in_unckdata volatile unsigned int	_dma_done[NB_DMAS_MAX * NB_CLUSTERS]
@@ -749,4 +749,5 @@
 #endif
 }
+
 //////////////////////////////////////////////////////////////////////////////////
 // _dma_get_status()
@@ -773,82 +774,19 @@
 
 //////////////////////////////////////////////////////////////////////////////////
-// 	VciFrameBuffer driver
-//////////////////////////////////////////////////////////////////////////////////
-// The vci_frame_buffer device can be accessed directly by software with memcpy(),
-// or it can be accessed through a multi-channels DMA component:
-//  
-// The '_fb_sync_write' and '_fb_sync_read' functions use a memcpy strategy to
-// implement the transfer between a data buffer (user space) and the frame
-// buffer (kernel space). They are blocking until completion of the transfer.
-//
-// The '_fb_write()', '_fb_read()' and '_fb_completed()' functions use the DMA
-// controlers (distributed in the clusters) to transfer data 
-// between the user buffer and the frame buffer. A  DMA channel is
-// allocated to each task requesting it in the mapping_info data structure.
-//////////////////////////////////////////////////////////////////////////////////
-
-//////////////////////////////////////////////////////////////////////////////////
-// _fb_sync_write()
-// Transfer data from an memory buffer to the frame_buffer device using 
-// a memcpy. The source memory buffer must be in user address space.
-// - offset : offset (in bytes) in the frame buffer.
-// - buffer : base address of the memory buffer.
-// - length : number of bytes to be transfered.
-// Returns 0 if success, > 0 if error.
-//////////////////////////////////////////////////////////////////////////////////
-unsigned int _fb_sync_write( unsigned int	offset, 
-                             const void* 	buffer, 
-                             unsigned int 	length )
-{
-
-    // buffer must be mapped in user space 
-    if ( ((unsigned int)buffer + length ) >= 0x80000000 )
-    {
-        return 1;
-    }
-    else
-    {
-        unsigned char *fb_address = (unsigned char*)&seg_fbf_base + offset;
-        memcpy((void*)fb_address, (void*)buffer, length);
-        return 0;
-    }
-}
-
-//////////////////////////////////////////////////////////////////////////////////
-// _fb_sync_read()
-// Transfer data from the frame_buffer device to a memory buffer using
-// a memcpy. The destination memory buffer must be in user address space.
-// - offset : offset (in bytes) in the frame buffer.
-// - buffer : base address of the memory buffer.
-// - length : number of bytes to be transfered.
-// Returns 0 if success, > 0 if error.
-//////////////////////////////////////////////////////////////////////////////////
-unsigned int _fb_sync_read( unsigned int 	offset, 
-                            const void*		buffer, 
-                            unsigned int 	length )
-{
-    // buffer must be mapped in user space 
-    if ( ((unsigned int)buffer + length ) >= 0x80000000 )
-    {
-        return 1;
-    }
-    else
-    {
-        unsigned char *fb_address = (unsigned char*)&seg_fbf_base + offset;
-        memcpy((void*)buffer, (void*)fb_address, length);
-        return 0;
-    }
-}
-
-//////////////////////////////////////////////////////////////////////////////////
-// _fb_dma_access()
-// Transfer data between a user buffer and the frame_buffer using DMA.
-// - to_user    : from frame buffer to user buffer when true.
-// - offset     : offset (in bytes) in the frame buffer.
-// - user_vaddr : virtual base address of the memory buffer.
-// - length     : number of bytes to be transfered.
+// _dma_transfer()
+// Transfer data between a user buffer and a device buffer using DMA.
+// Two devices types are supported: Frame Buffer if dev_type == 0
+//                                  Multi-Nic if dev_type != 0
+// Arguments are:
+// - dev_type     : device type.
+// - to_user      : from  device buffer to user buffer when true.
+// - offset       : offset (in bytes) in the device buffer.
+// - user_vaddr   : virtual base address of the user buffer.
+// - length       : number of bytes to be transfered.
+// 
+// The DMA channel is obtained from task context (CTX_FBDMA_ID / CTX_NIDMA_ID.
 // The user buffer must be mapped in user address space and word-aligned.
 // The user buffer length must be multiple of 4 bytes. 
-// Me must compute the physical base addresses for both the frame buffer
+// Me must compute the physical base addresses for both the device buffer
 // and the user buffer before programming the DMA transfer.
 // The GIET being fully static, we don't need to split the transfer in 4 Kbytes
@@ -856,5 +794,6 @@
 // Returns 0 if success, > 0 if error.
 //////////////////////////////////////////////////////////////////////////////////
-unsigned int _fb_dma_access( unsigned int 	to_user,
+unsigned int _dma_transfer(  unsigned int   dev_type,
+                             unsigned int   to_user,
                              unsigned int   offset,
                              unsigned int   user_vaddr,
@@ -862,59 +801,58 @@
 {
 #if NB_DMAS_MAX > 0
-    unsigned int	ko;				// unsuccessfull V2P translation
-    unsigned int	flags;			// protection flags
-    unsigned int	ppn;			// physical page number
-    unsigned int    user_pbase;		// user buffer pbase address
-    unsigned int    fb_pbase;		// frame buffer pbase address
+    unsigned int	ko;				        // unsuccessfull V2P translation
+    unsigned int	flags;			        // protection flags
+    unsigned int	ppn;			        // physical page number
+    unsigned int    user_pbase;		        // user buffer pbase address
+    unsigned int    device_pbase;			// frame buffer pbase address
+    unsigned int	device_vaddr;			// device buffer vbase address
+
+    // check user buffer address and length alignment
+    if ( (user_vaddr & 0x3) || (length & 0x3) )
+    {
+        _get_lock(&_tty_put_lock);
+        _puts("\n[GIET ERROR] in _dma_transfer : user buffer not word aligned\n");
+        _release_lock(&_tty_put_lock);
+        return 1;
+    }
 
     // get DMA channel and compute DMA vbase address
     unsigned int	task_id    = _get_current_task_id();
-    unsigned int	dma_id     = _get_context_slot( task_id, CTX_FBDMA_ID );
+    unsigned int    dma_id     = _get_context_slot( task_id, CTX_DMA_ID );
     unsigned int    cluster_id = dma_id / NB_DMAS_MAX;
     unsigned int    loc_id     = dma_id % NB_DMAS_MAX;
-
-    unsigned int*	dma_base   = (unsigned int*)( (char*)&seg_dma_base +
-                                 (cluster_id * (unsigned)CLUSTER_SIZE) );
- 
-    // check user buffer address and length alignment
-    if ( (user_vaddr & 0x3) || (length & 0x3) )
-    {
-        _get_lock(&_tty_put_lock);
-        _puts("\n[GIET ERROR] in _fbdma_access() : user buffer not word aligned\n");
-        _release_lock(&_tty_put_lock);
-        return 1;
-    }
-
-    // get user space page table virtual address
+    unsigned int*	dma_base   = (unsigned int*)( (char*)&seg_dma_base + 
+                                    (cluster_id * (unsigned)CLUSTER_SIZE) );
+
+    // get page table address
     unsigned int	user_ptab = _get_context_slot( task_id, CTX_PTAB_ID );
 
-    // compute frame buffer pbase address
-    unsigned int fb_vaddr = (unsigned int)&seg_fbf_base + offset;
-
+    // get peripheral buffer virtual address
+    if ( dev_type)  device_vaddr = (unsigned int)&seg_nic_base + offset;
+    else            device_vaddr = (unsigned int)&seg_fbf_base + offset;
+
+    // get device buffer physical address
     ko = _v2p_translate( (page_table_t*)user_ptab,
-                         (fb_vaddr >> 12),
+                         (device_vaddr >> 12),
                          &ppn,
                          &flags );
-    fb_pbase = (ppn << 12) | (fb_vaddr & 0x00000FFF);
-
     if ( ko )
     {
         _get_lock(&_tty_put_lock);
-        _puts("\n[GIET ERROR] in _fbdma_access() : frame buffer unmapped\n");
+        _puts("\n[GIET ERROR] in _dma_transfer : device buffer unmapped\n");
         _release_lock(&_tty_put_lock);
         return 2;
     }
-
-    // Compute user buffer pbase address
+    device_pbase = (ppn << 12) | (device_vaddr & 0x00000FFF);
+
+    // Compute user buffer physical address
     ko = _v2p_translate( (page_table_t*)user_ptab,
                          (user_vaddr >> 12),
                          &ppn,
                          &flags );
-    user_pbase = (ppn << 12) | (user_vaddr & 0x00000FFF);
-
     if ( ko )
     {
         _get_lock(&_tty_put_lock);
-        _puts("\n[GIET ERROR] in _fbdma_access() : user buffer unmapped\n");
+        _puts("\n[GIET ERROR] in _dma_transfer() : user buffer unmapped\n");
         _release_lock(&_tty_put_lock);
         return 3;
@@ -923,5 +861,5 @@
     {
         _get_lock(&_tty_put_lock);
-        _puts("[GIET ERROR] in _fbdma_access() : user buffer not in user space\n");
+        _puts("[GIET ERROR] in _dma_transfer() : user buffer not in user space\n");
         _release_lock(&_tty_put_lock);
         return 4; 
@@ -930,12 +868,12 @@
     {
         _get_lock(&_tty_put_lock);
-        _puts("\n[GIET ERROR] in _fbdma_access() : user buffer not writable\n");
+        _puts("\n[GIET ERROR] in _dma_transfer() : user buffer not writable\n");
         _release_lock(&_tty_put_lock);
         return 5;
     }
-
-
-
-/*
+    user_pbase = (ppn << 12) | (user_vaddr & 0x00000FFF);
+
+/*  This is a draft for IOMMU support
+    
     // loop on all virtual pages covering the user buffer
     unsigned int user_vpn_min = user_vaddr >> 12;
@@ -987,5 +925,5 @@
     // invalidate data cache in case of memory write
     if ( to_user ) _dcache_buf_invalidate( (void*)user_vaddr, length );
-
+    
     // get the lock 
     _get_lock( &_dma_lock[dma_id] );
@@ -994,5 +932,5 @@
     if ( to_user )
     {
-        dma_base[loc_id*DMA_SPAN + DMA_SRC] = (unsigned int)fb_pbase;
+        dma_base[loc_id*DMA_SPAN + DMA_SRC] = (unsigned int)device_pbase;
         dma_base[loc_id*DMA_SPAN + DMA_DST] = (unsigned int)user_pbase;
     }
@@ -1000,5 +938,5 @@
     {
         dma_base[loc_id*DMA_SPAN + DMA_SRC] = (unsigned int)user_pbase;
-        dma_base[loc_id*DMA_SPAN + DMA_DST] = (unsigned int)fb_pbase;
+        dma_base[loc_id*DMA_SPAN + DMA_DST] = (unsigned int)device_pbase;
     }
     dma_base[loc_id*DMA_SPAN + DMA_LEN] = (unsigned int)length;
@@ -1007,7 +945,118 @@
 
 #else //NB_DMAS_MAX == 0
+
     return -1;
-#endif
-}  
+
+#endif
+}  // end _dma_transfer()  
+
+//////////////////////////////////////////////////////////////////////////////////
+// _dma_completed()
+// This function checks completion of a DMA transfer to or from a peripheral
+// device (Frame Buffer or Multi-Nic).
+// As it is a blocking call, the processor is busy waiting.
+// Returns 0 if success, > 0 if error 
+// (1 == read error / 2 == DMA idle error / 3 == write error)
+//////////////////////////////////////////////////////////////////////////////////
+unsigned int _dma_completed()
+{
+#if NB_DMAS_MAX > 0
+    unsigned int    task_id = _get_current_task_id();
+    unsigned int    dma_id  = _get_context_slot( task_id, CTX_DMA_ID );
+
+    // busy waiting with a pseudo random delay between bus access
+    while (_dma_done[dma_id] == 0)
+    {
+        unsigned int delay = (( _proctime() ^ _procid()<<4 ) & 0x3F) + 1;
+        asm volatile("move  $3,   %0		        \n"
+                     "loop_nic_completed:	        \n"
+                     "addi  $3, $3, -1	            \n"
+                     "bnez  $3,	loop_nic_completed	\n"
+                     "nop			                \n"
+                     :
+                     : "r"(delay)
+                     : "$3" ); 
+    }
+    
+/* draft support for IOMMU
+    // unmap the buffer from IOMMU page table if IOMMU is activated
+    if ( GIET_IOMMU_ACTIVE )
+    {
+        unsigned int* iob_address = (unsigned int*)&seg_iob_base;
+
+        unsigned int  ix1         = _dma_iommu_ix1 + dma_id;
+        unsigned int  ix2;
+
+        for ( ix2 = 0 ; ix2 < _dma_iommu_npages[dma_id] ; ix2++ )
+        {
+            // unmap the page in IOMMU page table
+            _iommu_inval_pte2( ix1,		// PT1 index 
+                               ix2 );   // PT2 index
+
+            // clear IOMMU TLB
+            iob_address[IOB_INVAL_PTE] = (ix1 << 21) | (ix2 << 12);
+        }
+    }
+*/
+
+    // reset synchronization variables
+    _dma_lock[dma_id] = 0;
+    _dma_done[dma_id] = 0;
+
+    return _dma_status[dma_id];
+
+#else //NB_DMAS_MAX == 0
+    return -1;
+#endif
+}  // end _dma_completed
+
+//////////////////////////////////////////////////////////////////////////////////
+// 	VciFrameBuffer driver
+//////////////////////////////////////////////////////////////////////////////////
+// The vci_frame_buffer device can be accessed directly by software with memcpy(),
+// or it can be accessed through a multi-channels DMA component:
+//  
+// The '_fb_sync_write' and '_fb_sync_read' functions use a memcpy strategy to
+// implement the transfer between a data buffer (user space) and the frame
+// buffer (kernel space). They are blocking until completion of the transfer.
+//
+// The '_fb_write()', '_fb_read()' and '_fb_completed()' functions use the 
+// VciMultiDma components (distributed in the clusters) to transfer data 
+// between the user buffer and the frame buffer. A  FBDMA channel is
+// allocated to each task requesting it in the mapping_info data structure.
+//////////////////////////////////////////////////////////////////////////////////
+
+//////////////////////////////////////////////////////////////////////////////////
+// _fb_sync_write()
+// Transfer data from an memory buffer to the frame_buffer device using a memcpy. 
+// - offset : offset (in bytes) in the frame buffer.
+// - buffer : base address of the memory buffer.
+// - length : number of bytes to be transfered.
+//////////////////////////////////////////////////////////////////////////////////
+unsigned int _fb_sync_write( unsigned int	offset, 
+                             const void* 	buffer, 
+                             unsigned int 	length )
+{
+    unsigned char *fb_address = (unsigned char*)&seg_fbf_base + offset;
+    memcpy((void*)fb_address, (void*)buffer, length);
+    return 0;
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+// _fb_sync_read()
+// Transfer data from the frame_buffer device to a memory buffer using a memcpy.
+// - offset : offset (in bytes) in the frame buffer.
+// - buffer : base address of the memory buffer.
+// - length : number of bytes to be transfered.
+//////////////////////////////////////////////////////////////////////////////////
+unsigned int _fb_sync_read( unsigned int 	offset, 
+                            const void*		buffer, 
+                            unsigned int 	length )
+{
+    unsigned char *fb_address = (unsigned char*)&seg_fbf_base + offset;
+    memcpy((void*)buffer, (void*)fb_address, length);
+    return 0;
+}
+
 //////////////////////////////////////////////////////////////////////////////////
 // _fb_write()
@@ -1019,11 +1068,12 @@
 //////////////////////////////////////////////////////////////////////////////////
 unsigned int _fb_write( unsigned int 	offset, 
-                        const void*		buffer, 
+                        const    void*	buffer, 
                         unsigned int 	length )
 {
-    return _fb_dma_access( 0,						// write to frame buffer
-                           offset,
-                           (unsigned int)buffer,
-                           length );	
+    return _dma_transfer( 0,						// frame buffer
+                          0,						// write 
+		                  offset,
+		                  (unsigned int)buffer,
+		                  length );	
 }
 
@@ -1040,8 +1090,9 @@
                        unsigned int 	length )
 {
-    return _fb_dma_access( 1,						// read from frame buffer
-                           offset,
-                           (unsigned int)buffer,
-                           length );	
+    return _dma_transfer( 0,						// frame buffer
+                          1,						// read 
+		                  offset,
+		                  (unsigned int)buffer,
+		                  length );	
 }
 
@@ -1055,47 +1106,103 @@
 unsigned int _fb_completed()
 {
-#if NB_DMAS_MAX > 0
-    unsigned int task_id = _get_current_task_id();
-    unsigned int dma_id  = _get_context_slot( task_id, CTX_FBDMA_ID );
-
-    // busy waiting with a pseudo random delay between bus access
-    while (_dma_done[dma_id] == 0)
-    {
-	    unsigned int i;
-        unsigned int delay = ( _proctime() ^ _procid()<<4 ) & 0xFF;
-        for (i = 0; i < delay; i++)
-            asm volatile("nop");
-    }
-    
-    // unmap the buffer from IOMMU page table if IOMMU is activated
-    if ( IOMMU_ACTIVE )
-    {
-        unsigned int* iob_address = (unsigned int*) &seg_iob_base;
-
-        unsigned int  ix1         = _dma_iommu_ix1 + dma_id;
-        unsigned int  ix2;
-
-        for ( ix2 = 0 ; ix2 < _dma_iommu_npages[dma_id] ; ix2++ )
-        {
-            // unmap the page in IOMMU page table
-            _iommu_inval_pte2( ix1,		// PT1 index 
-                               ix2 );   // PT2 index
-
-            // clear IOMMU TLB
-            iob_address[IOB_INVAL_PTE] = (ix1 << 21) | (ix2 << 12);
-        }
-    }
-
-    // reset synchronization variables
-    _dma_lock[dma_id] = 0;
-    _dma_done[dma_id] = 0;
-
-    return _dma_status[dma_id];
-
-#else //NB_DMAS_MAX == 0
-
-    return -1;
-
-#endif
-}
-
+    return _dma_completed();
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+// 	VciMultiNic driver
+//////////////////////////////////////////////////////////////////////////////////
+// The VciMultiNic device can be accessed directly by software with memcpy(),
+// or it can be accessed through a multi-channels DMA component:
+//  
+// The '_nic_sync_write' and '_nic_sync_read' functions use a memcpy strategy to
+// implement the transfer between a data buffer (user space) and the NIC
+// buffer (kernel space). They are blocking until completion of the transfer.
+//
+// The '_nic_write()', '_nic_read()' and '_nic_completed()' functions use the 
+// VciMultiDma components (distributed in the clusters) to transfer data 
+// between the user buffer and the NIC. A  NIDMA channel is allocated to each 
+// task requesting it in the mapping_info data structure.
+//////////////////////////////////////////////////////////////////////////////////
+
+//////////////////////////////////////////////////////////////////////////////////
+// _nic_sync_write()
+// Transfer data from an memory buffer to the NIC device using a memcpy.
+// - offset : offset (in bytes) in the frame buffer.
+// - buffer : base address of the memory buffer.
+// - length : number of bytes to be transfered.
+//////////////////////////////////////////////////////////////////////////////////
+unsigned int _nic_sync_write( unsigned int	offset, 
+                              const void* 	buffer, 
+                              unsigned int 	length )
+{
+    unsigned char *nic_address = (unsigned char*)&seg_nic_base + offset;
+    memcpy((void*)nic_address, (void*)buffer, length);
+    return 0;
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+// _nic_sync_read()
+// Transfer data from the NIC device to a memory buffer using a memcpy. 
+// - offset : offset (in bytes) in the frame buffer.
+// - buffer : base address of the memory buffer.
+// - length : number of bytes to be transfered.
+//////////////////////////////////////////////////////////////////////////////////
+unsigned int _nic_sync_read( unsigned int 	offset, 
+                             const void*	buffer, 
+                             unsigned int 	length )
+{
+    unsigned char *nic_address = (unsigned char*)&seg_nic_base + offset;
+    memcpy((void*)buffer, (void*)nic_address, length);
+    return 0;
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+// _nic_write()
+// Transfer data from a memory buffer to the NIC device using  DMA.
+// - offset : offset (in bytes) in the frame buffer.
+// - buffer : base address of the memory buffer.
+// - length : number of bytes to be transfered.
+// Returns 0 if success, > 0 if error.
+//////////////////////////////////////////////////////////////////////////////////
+unsigned int _nic_write( unsigned int 	offset, 
+                         const void*	buffer, 
+                         unsigned int 	length )
+{
+    return _dma_transfer( 1,            // NIC
+                          0,			// write
+			              offset,
+			              (unsigned int)buffer,
+			              length );	
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+// _nic_read()
+// Transfer data from the NIC device to a memory buffer using  DMA.
+// - offset : offset (in bytes) in the frame buffer.
+// - buffer : base address of the memory buffer.
+// - length : number of bytes to be transfered.
+// Returns 0 if success, > 0 if error.
+//////////////////////////////////////////////////////////////////////////////////
+unsigned int _nic_read( unsigned int 	offset, 
+                        const void*		buffer, 
+                        unsigned int 	length )
+{
+    return _dma_transfer( 1,            // NIC
+                          1,			// read
+                          offset,
+			              (unsigned int)buffer,
+			              length );	
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+// _nic_completed()
+// This function checks completion of a DMA transfer to or fom a NIC channel.
+// As it is a blocking call, the processor is busy waiting.
+// Returns 0 if success, > 0 if error 
+// (1 == read error / 2 == DMA idle error / 3 == write error)
+//////////////////////////////////////////////////////////////////////////////////
+unsigned int _nic_completed()
+{
+    return _dma_completed();
+}
+
