metalsvm/drivers/net/mmnif.c

1139 lines
30 KiB
C

/*
* mmnif.c --- memmory mapped interface
*
* Virutal IP Interface for the concept processor SCC
*
* virutally tested under Windows 7
*
* Carl-Benedikt Krüger 2011
*
*
* EXPERIMENTAL VERSION
*/
#include "mmnif.h" /* definitions */
#include <lwip/netif.h> /* lwip netif */
#include <lwip/stats.h> /* inteface stats */
#include <netif/etharp.h> /* ethernet arp packets */
#include <lwip/ip.h> /* struct iphdr*/
#include <lwip/tcpip.h> /* tcpip_input()*/
#if defined(CONFIG_LWIP) && defined(CONFIG_ROCKCREEK)
#ifdef WIN32
#define kmalloc malloc
#define kfree(x,y) free(x)
#define RCCE_shfree(x) VirtualFree(x,NULL,NULL);
#define RCCE_shmalloc(x) VirtualAlloc((char*)0x41000000,x,MEM_COMMIT|MEM_RESERVE,PAGE_READWRITE);
#include "mailbox.h" /* mailbox_ptr_t */
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <system/threads/bthread.h>
typedef bthread_sem_t sem_t;
typedef bthread_t tid_t;
/* "interrupt" of the other virutal network card*/
extern HANDLE remote_process_event;
extern HANDLE remote_process_mutex;
extern HANDLE own_process_mutex;
/* HANDLE to the other Process (for WPM and RPM)*/
extern HANDLE hProc;
#define DEBUGPRINTF(x,...) printf(x,__VA_ARGS__)
#else
#include <metalsvm/mailbox.h> /* mailbox_ptr_t */
#include <metalsvm/semaphore.h>
#include <metalsvm/spinlock.h>
#include <metalsvm/page.h>
#include <asm/RCCE.h>
#include <asm/RCCE_lib.h>
#include <asm/iRCCE.h>
#include <asm/iRCCE_lib.h>
#include <asm/SCC_API.h>
#include <metalsvm/time.h>
#define DEBUGPRINTF(x,...) kprintf(x,##__VA_ARGS__)
#endif
#define DEBUG_MMNIF
//#define DEBUG_MMNIF_PACKET
#ifdef DEBUG_MMNIF
#include "util.h" /* hex dump */
#endif
/* define constants
* regarding the driver & its configuration
*/
#define MMNIF_TX_BUFFERLEN 1792
#define MMNIF_TX_QUEUELEN 4
#define MMNIF_RX_BUFFERLEN 8192
#define MMNIF_MAX_DESCRIPTORS 32
#define MMNIF_CORES 48
#define MMNIF_POLL_BUDGET 0x100000
#define MMNIF_STATUS_FREE 0x00
#define MMNIF_STATUS_PENDING 0x01
#define MMNIF_STATUS_RDY 0x02
#define MMNIF_STATUS_INPROC 0x03
#define MMNIF_STATUS_PROC 0x04
/* decide whether it's polling mode or not
*/
static int no_irq = 0;
/* this will be set by open() and close() and shows wether the driver is running or not
*/
static int active = 0;
/* decide wheter it's uses locking or not
*/
static int disable_locking = 0;
/* decide whether deliver work to a worker thread or instantly process all packets
*/
static int instant_process = 1;
/* IP address of the local core and the router core to get packets forwarded
*/
static unsigned int own_ip_address = 0xC0A80000; /* 192.168.0.0 */
static unsigned int router_ip_address = 0xC0A80001; /* 192.168.0.1 */
/* "message passing buffer" specific constants:
* - start address
* - size
*/
char* mpb_start_address = NULL;
unsigned int mpb_size = NULL;
/*
* the memory mapped network device
*/
static struct netif* mmnif_dev = NULL;
/* thread variables */
static tid_t worker_thread;
static tid_t polling_thread;
typedef struct mmnif_device_stats
{
/* device stats (granularity in packets):
* - recieve errors
* - recieve successes
* - recieved bytes
* - transmit errors
* - transmit successes
* - transmitted bytes
*/
unsigned int rx_err;
unsigned int rx;
unsigned int rx_bytes;
unsigned int tx_err;
unsigned int tx;
unsigned int tx_bytes;
/* Heuristics :
* - how many times an budget overflow occured
* - how many times the polling thread polled without recieving a new message
* - how many messages are recieved via interrupt
* - how many messages are recieved via the polling thread
*/
unsigned int bdg_overflow;
unsigned int pll_empty;
unsigned int rx_intr;
unsigned int rx_poll;
} mmnif_device_stats_t;
/* receive descror structure */
typedef struct rx_desc
{
uint8_t stat;
uint16_t len;
uint32_t addr;
} rx_desc_t;
/* receive ring buffer structure */
typedef struct mm_rx_buffer
{
/* iv_intr: inform via interrupt
* states whether the interface wants to recieve an interrupt for
* incoming packet
*/
uint16_t iv_intr;
/* memory "pseudo-ring/heap"
* packets are always in one single chunk of memory
* head : head of allocated memory region
* tail : tail of allocated memory region
*/
uint16_t head;
uint16_t tail;
spinlock_t rlock;
/* descritpor queue
* desc_table : descriptor table
* dcount : descriptor's free in queue
* dread : next descriptor to read
* dwrite : next descriptor to write
* dlock : lock to protect these members
*/
rx_desc_t desc_table[MMNIF_MAX_DESCRIPTORS];
uint8_t dcount;
uint8_t dread;
uint8_t dwrite;
spinlock_t dlock;
} mm_rx_buffer_t;
typedef struct mmnif
{
struct mmnif_device_stats stats;
/* Interface constants:
* - ehternet address
* - local ip address
*/
struct eth_addr* ethaddr;
uint32_t ipaddr;
/* memory interaction variables:
* - transmit queue
* - pointer to transmit buffer
* - pointer to recive buffer
*/
uint8_t tx_queue;
uint8_t* tx_buff[MMNIF_TX_QUEUELEN];
mm_rx_buffer_t* rx_buff;
/* lock to protect members
*/
spinlock_t lock;
/*
*/
sem_t com_poll;
}mmnif_t;
#ifdef WIN32
__inline int RCCE_ue(void){
#ifndef RECV
return 1;
#else
return 0;
#endif
}
#endif
/*
* memory maped interface helper functions
*/
#ifdef WIN32
#define __MEMCPY(x,y,z) memcpy(x,y,z)
#else
#define __MEMCPY(x,y,z) memcpy(x,y,z)
#endif
/* mmnif_device_schedule() :
* if there is no interupt used to indicate new packets
* this creates a polling thread which looks for data
* itself
*/
__inline int mmnif_device_schedule()
{
#ifdef WIN32
bthread_create(&polling_thread,NULL,mmnif_poll,NULL);
return NULL;
#else
create_kernel_task(&polling_thread,mmnif_poll,NULL, NORMAL_PRIO);
return NULL;
#endif
}
/* trigger an interrupt on the remote processor
* so he knows there is a packet to read
*/
__inline int mmnif_trigger_irq(dest_ip)
{
#ifdef WIN32
return SetEvent(remote_process_event);
#else
int tmp, x, y, z, addr;
int ue = dest_ip -1;
z = Z_PID(RC_COREID[ue]);
x = X_PID(RC_COREID[ue]);
y = Y_PID(RC_COREID[ue]);
addr = CRB_ADDR(x,y) + (z==0 ? GLCFG0 : GLCFG1);
// send interrupt to ue
do {
NOP1;
tmp=ReadConfigReg(addr);
} while(tmp & 2);
tmp |= 2;
SetConfigReg(addr, tmp);
return 0;
#endif
}
/* mmnif_get_device_stats(): Returns a copy of the
* current device
*/
mmnif_device_stats_t mmnif_get_device_stats(void)
{
mmnif_device_stats_t stats = {0};
if(!mmnif_dev)
DEBUGPRINTF("mmnif_get_device_stats(): the device is not initialized yet.\n");
else
stats = ((mmnif_t*)mmnif_dev->state)->stats;
return stats;
}
/* mmnif_print_stats(): Print the devices stats of the
* current device
*/
void mmnif_print_stats(void)
{
mmnif_t* mmnif;
if (!mmnif_dev)
{
DEBUGPRINTF("mmnif_print_stats(): the device is not initialized yet.\n");
return;
}
mmnif = (mmnif_t*)mmnif_dev->state;
DEBUGPRINTF("/dev/mmnif - stats:\n");
DEBUGPRINTF("Received: %d packets successfull\n",mmnif->stats.rx);
DEBUGPRINTF("Received: %d bytes\n",mmnif->stats.rx_bytes);
DEBUGPRINTF("interrupts: %d\n",mmnif->stats.rx_intr);
DEBUGPRINTF("polling: %d\n",mmnif->stats.rx_poll);
DEBUGPRINTF("Received: %d packets containuing errors\n",mmnif->stats.rx_err);
DEBUGPRINTF("Transmitted: %d packests successfull\n",mmnif->stats.tx);
DEBUGPRINTF("Transmitted: %d bytes\n",mmnif->stats.tx_bytes);
DEBUGPRINTF("Transmitted: %d packests were dropped due to errors\n",mmnif->stats.tx_err);
}
/*
* memory maped interface main functions
*/
/* mmnif_get_destination(): low level transmid helper function
* this function deals with some HW details, it checks to wich core this packet
* should be routed and returns the destination
*/
uint8_t mmnif_get_destination(struct netif* netif, struct pbuf* p)
{
struct ip_hdr* iphdr;
uint8_t core;
uint8_t* ip4addr;
uint8_t addr[4];
uint32_t netmask = 0xFFFFFF00;
/* grab the destination ip address out of the ip header
* for internal routing the last ocet is interpreted as core ID.
*/
iphdr = (struct ip_hdr*)(p->payload);
ip4addr = &iphdr->dest.addr;
/* revert the address to host format */
addr[3] = ip4addr[0]; addr[2] = ip4addr[1];
addr[1] = ip4addr[2]; addr[0] = ip4addr[3];
/* check if the ip address is in the Local Area Network of the 48 cores */
/* if it's not the same network the router core is addressed
* Note: the router core is core 1
*/
if (!((netmask & *(uint32_t*)addr) == (netmask & own_ip_address) ))
return 1;
core = addr[0];
/* check if the address is legitimata else return router core again */
if ((core) < 1 || (core > MMNIF_CORES))
core = 1;
return core;
}
/* mmnif_rxbuff_alloc():
* this function allocates a continues chunk of memory
* right inside of the buffer which is used for communication
* with the remote end
*/
uint32_t mmnif_rxbuff_alloc(uint8_t dest,uint16_t len)
{
mm_rx_buffer_t* rb = (mm_rx_buffer_t*)((char*)mpb_start_address + ( dest -1 ) * mpb_size);
char* memblock = (char*)rb + sizeof(mm_rx_buffer_t);
uint32_t ret;
spinlock_lock(&rb->dlock);
if (rb->dcount)
{
if (rb->tail > rb->head)
{
if (MMNIF_RX_BUFFERLEN - rb->tail > len)
{
rb->desc_table[rb->dwrite].stat = MMNIF_STATUS_PENDING;
ret = memblock + rb->tail;
rb->desc_table[rb->dwrite].addr = ret;
rb->desc_table[rb->dwrite].len = len;
rb->dcount--;
rb->dwrite = (++rb->dwrite)%MMNIF_MAX_DESCRIPTORS;
rb->tail = (rb->tail + len);
spinlock_unlock(&rb->dlock);
return ret;
}
else if (rb->head > len)
{
rb->desc_table[rb->dwrite].stat = MMNIF_STATUS_PENDING;
ret = memblock;
rb->desc_table[rb->dwrite].addr = ret;
rb->desc_table[rb->dwrite].len = len;
rb->dcount--;
rb->dwrite = (++rb->dwrite)%MMNIF_MAX_DESCRIPTORS;
rb->tail = len;
spinlock_unlock(&rb->dlock);
return ret;
}
else
{
spinlock_unlock(&rb->dlock);
return NULL;
}
}
else
{
if (rb->head - rb->tail > len)
{
rb->desc_table[rb->dwrite].stat = MMNIF_STATUS_PENDING;
ret = memblock + rb->tail;
rb->desc_table[rb->dwrite].addr = ret;
rb->desc_table[rb->dwrite].len = len;
rb->dcount--;
rb->dwrite = (++rb->dwrite)%MMNIF_MAX_DESCRIPTORS;
rb->tail = (rb->tail + len);
spinlock_unlock(&rb->dlock);
return ret;
}
else if (rb->tail == rb->head)
{
if (MMNIF_RX_BUFFERLEN - rb->tail < len)
{
rb->tail = 0;
if (rb->dread == rb->dwrite)
rb->head = 0;
}
rb->desc_table[rb->dwrite].stat = MMNIF_STATUS_PENDING;
ret = memblock + rb->tail;
rb->desc_table[rb->dwrite].addr = ret;
rb->desc_table[rb->dwrite].len = len;
rb->dcount--;
rb->dwrite = (++rb->dwrite)%MMNIF_MAX_DESCRIPTORS;
rb->tail = (rb->tail + len);
spinlock_unlock(&rb->dlock);
return ret;
}
else
{
spinlock_unlock(&rb->dlock);
return NULL;
}
}
}
else
{
spinlock_unlock(&rb->dlock);
return NULL;
}
}
/* mmnif_commit_packet: this function set the state of the (in advance)
* allocated packet to RDY so the recieve queue knows that it can be
* processed further
*/
int mmnif_commit_packet(uint8_t dest,uint32_t addr)
{
mm_rx_buffer_t* rb = (mm_rx_buffer_t*)((char*)mpb_start_address + ( dest -1 ) * mpb_size);
uint32_t i;
for (i = 0; i < MMNIF_MAX_DESCRIPTORS; i++)
{
if (rb->desc_table[i].addr == addr && rb->desc_table[i].stat == MMNIF_STATUS_PENDING)
{
rb->desc_table[i].stat = MMNIF_STATUS_RDY;
return 0;
}
}
return -1;
}
/* mmnif_rxbuff_free() : the opposite to mmnif_rxbuff_alloc() a from the receiver
* already processed chunk of memory is freed so that it can be allocated again
*/
void mmnif_rxbuff_free(void)
{
mmnif_t* mmnif = mmnif_dev->state;
mm_rx_buffer_t* b = mmnif->rx_buff;
uint32_t i,j;
uint32_t rpos;
spinlock_lock(&b->dlock);
rpos = b->dread;
for (i = 0, j = rpos; i < MMNIF_MAX_DESCRIPTORS; i++)
{
j = (j+i)%MMNIF_MAX_DESCRIPTORS;
if (b->desc_table[j].stat == MMNIF_STATUS_PROC)
{
b->dcount++;
b->dread = (b->dread +1)%MMNIF_MAX_DESCRIPTORS;
b->desc_table[j].stat = MMNIF_STATUS_FREE;
if (b->tail > b->head)
{
b->head += b->desc_table[j].len;
}
else
{
if ( (b->desc_table[(j+1)%MMNIF_MAX_DESCRIPTORS].stat != MMNIF_STATUS_FREE )
&& ( b->desc_table[j].addr > b->desc_table[(j+1)%MMNIF_MAX_DESCRIPTORS].addr))
{
b->head = 0;
}
else
{
b->head += b->desc_table[j].len;
}
}
}
else
break;
}
spinlock_unlock(&b->dlock);
}
/*
* Transmid a packet (called by the lwip)
*/
err_t mmnif_tx(struct netif* netif, struct pbuf* p)
{
mmnif_t* mmnif = netif->state;
uint8_t slot = mmnif->tx_queue;
uint32_t write_address;
uint32_t i;
struct pbuf* q; /* interator */
uint8_t build_buff = TRUE;
uint32_t dest_ip = mmnif_get_destination(netif,p);
mm_rx_buffer_t* rb = (mm_rx_buffer_t*)((char*)mpb_start_address + ( dest_ip -1 ) * mpb_size);
#ifdef WIN32
ReadProcessMemory(hProc, (char*)mpb_start_address + ( dest_ip -1 ) * mpb_size, (char*)mpb_start_address + ( dest_ip -1 ) * mpb_size,mpb_size,NULL);
WaitForSingleObject(remote_process_mutex,INFINITE);
#endif
spinlock_lock(&mmnif->lock);
mmnif->tx_queue++;
spinlock_unlock(&mmnif->lock);
/* Perform serveral sanity checks on the packet and the buffers:
* - is the queue full?
* - is the output packet to big?
*/
if (mmnif->tx_queue > MMNIF_TX_QUEUELEN)
{
DEBUGPRINTF("mmnif_tx(): too many packets at once for tx_queue\n");
goto drop_packet;
}
if (p->tot_len > MMNIF_TX_BUFFERLEN)
{
DEBUGPRINTF("mmnif_tx(): packet is longer than %d bytes\n",MMNIF_TX_BUFFERLEN);
goto drop_packet;
}
/* check if the pbuf consists only of one element
* if that is the case it would be much overhead
* copying that packet again
*/
if (!p->next)
build_buff = FALSE;
if (build_buff)
{
/* build the payload out of the p's
* ensure that the packet is in one memory chunk stored in the transmid buffer
*/
for (q = p, i = 0; q != 0; q = q->next)
{
memcpy(mmnif->tx_buff[slot] + i, q->payload, q->len);
i += q->len;
}
}
/* allocate memory for the packet in the remote buffer */
write_address = mmnif_rxbuff_alloc(dest_ip,p->tot_len);
if (!write_address)
goto drop_packet;
/* write buffer to buffer & increment the queued packet count
* this can be safely done without locking because this place is
* reserved for us because it has the status "pending"
*/
if (build_buff)
memcpy(write_address,mmnif->tx_buff[slot],p->tot_len);
else
memcpy(write_address,p->payload,p->tot_len);
if (mmnif_commit_packet(dest_ip,write_address))
{
DEBUGPRINTF("mmnif_tx(): packet somehow lost during commit\n");
}
#ifdef DEBUG_MMNIF_PACKET
DEBUGPRINTF("\n SEND 0x%.8X with length: %d\n",(char*)mpb_start_address + (dest_ip -1)*mpb_size + pos * 1792,p->tot_len +2);
hex_dump(p->tot_len, p->payload);
#endif
/* release the tx_queue because it's finished */
spinlock_lock(&mmnif->lock);
mmnif->tx_queue--;
spinlock_unlock(&mmnif->lock);
/* just gather some stats */
LINK_STATS_INC(link.xmit);
mmnif->stats.tx++;
mmnif->stats.tx_bytes += p->tot_len;
#ifdef WIN32
WriteProcessMemory(hProc, (char*)mpb_start_address + ( dest_ip -1 ) * mpb_size, (char*)mpb_start_address + ( dest_ip -1 ) * mpb_size,mpb_size,NULL);
SetEvent(remote_process_event);
ReleaseMutex(remote_process_mutex);
#endif
if (rb->iv_intr)
mmnif_trigger_irq(dest_ip);
return ERR_OK;
drop_packet:
/* drop packet for one or another reason
*/
spinlock_lock(&mmnif->lock);
mmnif->tx_queue--;
spinlock_unlock(&mmnif->lock);
LINK_STATS_INC(link.drop);
mmnif->stats.tx_err++;
#ifdef WIN32
WriteProcessMemory(hProc, (char*)mpb_start_address + ( dest_ip -1 ) * mpb_size,(char*)mpb_start_address + ( dest_ip -1 ) * mpb_size,mpb_size,NULL);
#endif
return ERR_IF;
}
/* mmnif_link_layer(): wrapper function called by ip_output()
* adding all needed headers for the link layer
* because we have no link layer and everything is reliable we don't need
* to add anything so we just pass it to our tx function
*/
static void mmnif_link_layer(struct netif *netif, struct pbuf *q, ip_addr_t *ipaddr)
{
netif->linkoutput(netif,q);
}
/*
* Init the device (called from lwip)
* It's invoked in netif_add
*/
err_t mmnif_init(struct netif* netif)
{
mmnif_t* mmnif;
uint32_t i;
int num = 0;
/* Alloc and clear memory for the device struct
*/
mmnif = kmalloc(sizeof(mmnif_t));
if (!mmnif)
{
DEBUGPRINTF("mmnif init():out of memory\n");
return ERR_MEM;
}
memset(mmnif, 0, sizeof(mmnif_t));
/* Alloc and clear shared memory for rx_buff
*/
mpb_size = (sizeof(mm_rx_buffer_t) + MMNIF_RX_BUFFERLEN);
// align mpb size to the granularity of a page size
mpb_size = (mpb_size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
mpb_start_address = RCCE_shmalloc(mpb_size*MMNIF_CORES);
// map physical address in the virtual address space
mpb_start_address = map_region(0, mpb_start_address, mpb_size >> PAGE_SHIFT, MAP_KERNEL_SPACE|MAP_NO_CACHE);
mmnif->rx_buff = mpb_start_address + (mpb_size) * (own_ip_address - router_ip_address);
if (!(mpb_start_address))
{
DEBUGPRINTF("mmnif init(): allocating shared memory failed\n");
return ERR_MEM;
}
memset(mmnif->rx_buff, 0, mpb_size);
/* set initial values
*/
mmnif->rx_buff->dcount = MMNIF_MAX_DESCRIPTORS;
/* init the lock's for the hdr
*/
spinlock_init(&mmnif->rx_buff->rlock);
spinlock_init(&mmnif->rx_buff->dlock);
spinlock_init(&mmnif->lock);
/* init the sems for communication art
*/
sem_init(&mmnif->com_poll,1);
/* since there is no possibilty to create a full semaphore we just block it manually
*/
sem_wait(&mmnif->com_poll,0);
/* inform via interrupt should be the dafault
*/
if (!no_irq)
mmnif->rx_buff->iv_intr = TRUE;
/* Alloc and clear internal memory for tx_buff
*/
mmnif->tx_buff[0] = kmalloc(MMNIF_TX_QUEUELEN * MMNIF_TX_BUFFERLEN);
if (!(mmnif->tx_buff[0]))
{
DEBUGPRINTF("mmnif init: out of memory tx\n");
return ERR_MEM;
}
mmnif->tx_queue = 0;
memset(mmnif->tx_buff[0], 0, MMNIF_TX_QUEUELEN * MMNIF_TX_BUFFERLEN);
for (i = 0; i < MMNIF_TX_QUEUELEN -1 ; i++)
mmnif->tx_buff[i+1] = mmnif->tx_buff[i] + MMNIF_TX_BUFFERLEN;
/* pass the device state to lwip */
netif->state = mmnif;
mmnif_dev = netif;
/* administrative details */
netif->name[0] = 'e';
netif->name[1] = 'n';
netif->num = num;
num++;
/* downward functions */
netif->output = mmnif_link_layer;
/* there is no special link layer just the ip layer */
netif->linkoutput = mmnif_tx;
/* maximum transfer unit */
netif->mtu = 1500;
/* broadcast capability, keep all default flags*/
netif->flags |= NETIF_FLAG_BROADCAST | NETIF_FLAG_LINK_UP;
/* hardware address length */
netif->hwaddr_len = 6;
active = TRUE;
#ifdef MMNIF_DEBUG
DEBUGPRINTF("mmnif init complete\n");
#endif
return NULL;
}
/*
* Receive a packet : recieve, pack it up and pass over to higher levels
*/
static void mmnif_rx(struct netif* netif)
{
mmnif_t* mmnif = netif->state;
mm_rx_buffer_t* b = mmnif->rx_buff;
uint16_t length;
struct pbuf* p = NULL;
struct pbuf* q;
char* packet;
uint32_t i,j;
uint8_t rdesc = 0xFF;
err_t err = NULL;
#ifdef WIN32
ReadProcessMemory(hProc, (char*)mpb_start_address + ( !((own_ip_address && 0xFF)-1) ) * mpb_size, (char*)mpb_start_address + ( !((own_ip_address && 0xFF)-1) ) * mpb_size,mpb_size,NULL);
WaitForSingleObject(own_process_mutex,INFINITE);
#endif
spinlock_lock(&b->rlock);
/* check if this call to mmnif_rx makes any sense
*/
if (b->desc_table[b->dread].stat == MMNIF_STATUS_FREE)
{
spinlock_unlock(&b->rlock);
#ifdef WIN32
WriteProcessMemory(hProc, (char*)mpb_start_address + ( !((own_ip_address && 0xFF)-1) ) * mpb_size, (char*)mpb_start_address + ( !((own_ip_address && 0xFF)-1) ) * mpb_size,mpb_size,NULL);
#endif
return;
}
/* search the packet whose transmission is finished
*/
for (i = 0,j = b->dread; i < MMNIF_MAX_DESCRIPTORS; i++)
{
if (b->desc_table[(j + i)% MMNIF_MAX_DESCRIPTORS].stat == MMNIF_STATUS_RDY)
{
rdesc = (j + i)% MMNIF_MAX_DESCRIPTORS;
b->desc_table[rdesc].stat = MMNIF_STATUS_INPROC;
packet = (char*)b->desc_table[rdesc].addr;
length = b->desc_table[rdesc].len;
break;
}
}
spinlock_unlock(&b->rlock);
/* if there is no packet finished we encountered a random error
*/
if (rdesc == 0xFF)
{
#ifdef WIN32
WriteProcessMemory(hProc, (char*)mpb_start_address + ( !((own_ip_address && 0xFF)-1) ) * mpb_size, (char*)mpb_start_address + ( !((own_ip_address && 0xFF)-1) ) * mpb_size,mpb_size,NULL);
#endif
return;
}
/* If length is zero return silently
*/
if (length == 0)
{
DEBUGPRINTF("mmnif_rx(): empty packet error\n");
return;
}
if (length < sizeof(struct ip_hdr) ||length > netif->mtu)
{
DEBUGPRINTF("mmnif_rx(): illegal packet length %d => drop the packet\n",length);
goto drop_packet;
}
/* From now on there is a real packet and it
* has to be worked on
*/
#ifdef DEBUG_MMNIF_PACKET
DEBUGPRINTF("\n RECIEVED - 0x%.8X with legth: %d\n",packet,length);
hex_dump(length,packet);
#endif
/* Build the pbuf for the packet so the lwip
* and other higher layer can handle it
*/
p = pbuf_alloc(PBUF_RAW, length, PBUF_POOL);
if (!p)
{
DEBUGPRINTF("mmnif_rx(): low on mem - packet dropped\n");
goto drop_packet;
}
/* copy packet to pbuf structure going through linked list */
for (q=p, i = 0; q!=NULL; q=q->next)
{
memcpy((uint8_t*)q->payload,&packet[i],q->len);
i +=q->len;
}
/* indicate that the copy process is done and the packet can be freed
* note that we did not lock here because we are the only one editing this value
*/
mmnif->rx_buff->desc_table[rdesc].stat = MMNIF_STATUS_PROC;
/* everything is copied to a new buffer so it's save to release
* the old one for new incoming packets
*/
mmnif_rxbuff_free();
/* full packet send to tcpip_thread to process */
if ((err = mmnif_dev->input(p, mmnif_dev)) != ERR_OK)
{
DEBUGPRINTF("mmnif_rx: IP input error\n");
pbuf_free(p);
}
/* gather some stats and leave the rx handler */
LINK_STATS_INC(link.xmit);
mmnif->stats.rx++;
mmnif->stats.rx_bytes += p->tot_len;
if (mmnif->rx_buff->iv_intr)
mmnif->stats.rx_intr++;
else
mmnif->stats.rx_poll++;
#ifdef WIN32
WriteProcessMemory(hProc, (char*)mpb_start_address + ( !((own_ip_address && 0xFF)-1) ) * mpb_size, (char*)mpb_start_address + ( !((own_ip_address && 0xFF)-1) ) * mpb_size,mpb_size,NULL);
ReleaseMutex(own_process_mutex);
#endif
return;
drop_packet:
spinlock_lock(&mmnif->rx_buff->rlock);
/*error handling*/
spinlock_unlock(&mmnif->rx_buff->rlock);
LINK_STATS_INC(link.drop);
mmnif->stats.rx_err++;
#ifdef WIN32
WriteProcessMemory(hProc, (char*)mpb_start_address + ( !((own_ip_address && 0xFF)-1) ) * mpb_size, (char*)mpb_start_address + ( !((own_ip_address && 0xFF)-1) ) * mpb_size,mpb_size,NULL);
#endif
return;
}
/* mmnif_irqhandler():
* handles the incomint interrupts
*/
void mmnif_irqhandler(void)
{
mmnif_t* mmnif;
/* return if mmnif_dev is not yet initialized*/
if (!mmnif_dev)
{
DEBUGPRINTF("mmnif_irqhandler(): the driver is not initialized yet\n");
return;
}
mmnif = (mmnif_t*) mmnif_dev->state;
while (mmnif->rx_buff->dcount < MMNIF_MAX_DESCRIPTORS)
{
mmnif_rx(mmnif_dev);
// if (instant_process)
// mmnif_wait(mmnif_dev,1,MMNIF_WORKER_BUDGET);
}
}
/*
* the poll function wich is used if no interrupt wake up our mmnif_rx functions
*/
int mmnif_poll(void* e)
{
mmnif_t* mmnif;
if (!mmnif_dev)
{
DEBUGPRINTF("mmnif_poll(): the driver is not initialized yet\n");
return -1;
}
mmnif = (mmnif_t*) mmnif_dev->state;
#ifdef DEBUG_MMNIF
DEBUGPRINTF("mmnif_poll(): polling thread launched",mmnif->rx_buff);
#endif
if (!no_irq)
{
sem_wait(&mmnif->com_poll,0);
}
/*run while driver is up*/
while (active)
{
while (!mmnif->rx_buff->dcount == MMNIF_MAX_DESCRIPTORS)
{
mmnif->stats.pll_empty++;
if (mmnif->stats.pll_empty >= MMNIF_POLL_BUDGET)
{
/* enable interrupts and suspend polling
*
*/
mmnif->rx_buff->iv_intr = TRUE;
mmnif->stats.pll_empty = 0;
#ifdef DEBUG_MMNIF
DEBUGPRINTF("mmnif_poll(): heuristical interrupts enabled\n");
#endif
sem_wait(&mmnif->com_poll,0);
}
/* uncomment this to test only polling
*/
// mmnif->stats.pll_empty = 0;
}
mmnif->stats.pll_empty=0;
mmnif_rx(mmnif_dev);
}
return NULL;
}
/*
* Open the interface should be called by kernel to use this network interface
*/
int mmnif_open(void)
{
struct ip_addr ipaddr;
struct ip_addr netmask;
struct ip_addr gw;
/* calculate my own ip address from core number
* Note: core 1 is the router core
*/
IP4_ADDR(&gw, 0,0,0,0);
IP4_ADDR(&ipaddr, 192,168,0,RCCE_ue() +1);
IP4_ADDR(&netmask, 255,255,255,0);
own_ip_address+= RCCE_ue() +1;
mmnif_dev = kmalloc(sizeof(struct netif));
/* register our Memory Mapped Virtual IP interface in the lwip stack
* and tell him how to use the interface:
* - mmnif_dev : the device data storage
* - ipaddr : the ip address wich should be used
* - gw : the gateway wicht should be used
* - mmnif_init : the initialization which has to be done in order to use our interface
* - ethernet_input : tells him that he should get ethernet input (inclusice ARP)
*
* Note: Ethernet Input will be removed because its NOT needed and will
* be replaced with ip_input
*/
if (!netif_add(mmnif_dev, &ipaddr, &netmask, &gw, NULL,(netif_init_fn)mmnif_init, tcpip_input))
{
DEBUGPRINTF("mmnif_open() : unable to add network interface\n");
return -1;
}
/* set our network interface to the default interface for lwip*/
//netif_set_default(mmnif_dev);
/* tell lwip all initialization is done and we want to set it ab*/
netif_set_up(mmnif_dev);
/* test if interface is really up */
if (!netif_is_up(mmnif_dev))
{
DEBUGPRINTF("mmnif_open(): network interface is not up\n");
return -2;
}
/* indicate that the driver is active now*/
active = TRUE;
/* If interrupts are not used we immediately add the polling function
* to the queue which would otherwise be done through the IRQ handler.
*/
mmnif_device_schedule();
/* Start the device worker thread wich actually processes the incoming
* packet's this is not done in the "interrupt handler" to shorten them up
*/
// if (!instant_process)
// mmnif_worker_schedule();
// mmnif_retrigger_schedule();
#ifdef DEBUG_MMNIF
DEBUGPRINTF("mmnif_dev is open\n");
#endif
return 0;
}
/*
* close the interface should be called by kernel to close this interface and release resources
* Note: it's temporarly empty. Support will be added.
*/
int mmnif_close(void)
{
size_t phyaddr;
mmnif_t* mmnif;
if (!mmnif_dev)
{
DEBUGPRINTF("mmnif_close(): you closed the device before it was properly opened -.-* \n");
}
mmnif = (mmnif_t*)mmnif_dev->state;
/* indicate that the driver is not active anymore
* - this will stop the polling thread i.e.
*/
active = FALSE;
kfree(mmnif->tx_buff[0],MMNIF_TX_QUEUELEN * MMNIF_TX_BUFFERLEN);
kfree(mmnif_dev,sizeof(mmnif_t));
// determine physical address
phyaddr = virt_to_phys(mpb_start_address);
// unmap shared memory regeion
unmap_region(mpb_start_address, mpb_size >> PAGE_SHIFT);
RCCE_shfree(phyaddr);
return NULL;
}
#endif