Model of the network card with bus mastering DMA for QEMU.
Sources are published as PUBLIC DOMAIN. No warranty at all.
Sources were prepared for qemu 0.14.
#!/bin/sh
# This is a shell archive (produced by GNU sharutils 4.11).
# To extract the files from this archive, save it to some FILE, remove
# everything before the `#!/bin/sh' line above, then type `sh FILE'.
#
lock_dir=_sh06732
# Made on 2012-04-07 01:05 CEST by <wzab@WZLap>.
# Source directory was `/home/wzab/tmp/wz_nic'.
#
# Existing files will *not* be overwritten, unless `-c' is specified.
#
# This shar contains:
# length mode name
# ------ ---------- ------------------------------------------
# 530 -rw-r--r-- wzab_enc1.h
# 22545 -rw-r--r-- wzab_nic1.c
#
MD5SUM=${MD5SUM-md5sum}
f=`${MD5SUM} --version | egrep '^md5sum .*(core|text)utils'`
test -n "${f}" && md5check=true || md5check=false
${md5check} || \
echo 'Note: not verifying md5sums. Consider installing GNU coreutils.'
if test "X$1" = "X-c"
then keep_file=''
else keep_file=true
fi
echo=echo
save_IFS="${IFS}"
IFS="${IFS}:"
gettext_dir=
locale_dir=
set_echo=false
for dir in $PATH
do
if test -f $dir/gettext \
&& ($dir/gettext --version >/dev/null 2>&1)
then
case `$dir/gettext --version 2>&1 | sed 1q` in
*GNU*) gettext_dir=$dir
set_echo=true
break ;;
esac
fi
done
if ${set_echo}
then
set_echo=false
for dir in $PATH
do
if test -f $dir/shar \
&& ($dir/shar --print-text-domain-dir >/dev/null 2>&1)
then
locale_dir=`$dir/shar --print-text-domain-dir`
set_echo=true
break
fi
done
if ${set_echo}
then
TEXTDOMAINDIR=$locale_dir
export TEXTDOMAINDIR
TEXTDOMAIN=sharutils
export TEXTDOMAIN
echo="$gettext_dir/gettext -s"
fi
fi
IFS="$save_IFS"
if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null
then if (echo -n test; echo 1,2,3) | grep n >/dev/null
then shar_n= shar_c='
'
else shar_n=-n shar_c= ; fi
else shar_n= shar_c='\c' ; fi
f=shar-touch.$$
st1=200112312359.59
st2=123123592001.59
st2tr=123123592001.5 # old SysV 14-char limit
st3=1231235901
if touch -am -t ${st1} ${f} >/dev/null 2>&1 && \
test ! -f ${st1} && test -f ${f}; then
shar_touch='touch -am -t $1$2$3$4$5$6.$7 "$8"'
elif touch -am ${st2} ${f} >/dev/null 2>&1 && \
test ! -f ${st2} && test ! -f ${st2tr} && test -f ${f}; then
shar_touch='touch -am $3$4$5$6$1$2.$7 "$8"'
elif touch -am ${st3} ${f} >/dev/null 2>&1 && \
test ! -f ${st3} && test -f ${f}; then
shar_touch='touch -am $3$4$5$6$2 "$8"'
else
shar_touch=:
echo
${echo} 'WARNING: not restoring timestamps. Consider getting and
installing GNU `touch'\'', distributed in GNU coreutils...'
echo
fi
rm -f ${st1} ${st2} ${st2tr} ${st3} ${f}
#
if test ! -d ${lock_dir} ; then :
else ${echo} "lock directory ${lock_dir} exists"
exit 1
fi
if mkdir ${lock_dir}
then ${echo} "x - created lock directory ${lock_dir}."
else ${echo} "x - failed to create lock directory ${lock_dir}."
exit 1
fi
# ============= wzab_enc1.h ==============
if test -n "${keep_file}" && test -f 'wzab_enc1.h'
then
${echo} "x - SKIPPING wzab_enc1.h (file already exists)"
else
${echo} "x - extracting wzab_enc1.h (text)"
sed 's/^X//' << 'SHAR_EOF' > 'wzab_enc1.h' &&
//Definitions of 32-bit registers
#define WZENC1_NOF_PAGES 4
typedef struct WzEnc1Page {
X uint32_t PhysAddr;
X uint32_t Offset;
X uint32_t Length;
} WzEnc1Page;
X
typedef struct WzEnc1Regs {
X uint32_t Ctrl;
X uint32_t Status;
X WzEnc1Page Pages[WZENC1_NOF_PAGES];
} WzEnc1Regs;
X
X
//Commands
#define ENC1_CMD_DECR 1
#define ENC1_CMD_ENCR 2
#define ENC1_CMD_DATA 3
#define ENC1_CMD_STOP 4
#define ENC1_CMD_ENAIRQ 5
#define ENC1_CMD_DISIRQ 6
#define ENC1_CMD_ACKIRQ 7
X
//Errors
#define ENC1_ERR_NOTINIT 1
#define ENC1_ERR_BUSY 2
X
X
SHAR_EOF
(set 20 11 06 16 13 16 00 'wzab_enc1.h'
eval "${shar_touch}") && \
chmod 0644 'wzab_enc1.h'
if test $? -ne 0
then ${echo} "restore of wzab_enc1.h failed"
fi
if ${md5check}
then (
${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'wzab_enc1.h': 'MD5 check failed'
) << \SHAR_EOF
1bfb98c4cf516aaa9e539570047bd7bc wzab_enc1.h
SHAR_EOF
else
test `LC_ALL=C wc -c < 'wzab_enc1.h'` -ne 530 && \
${echo} "restoration warning: size of 'wzab_enc1.h' is not 530"
fi
fi
# ============= wzab_nic1.c ==============
if test -n "${keep_file}" && test -f 'wzab_nic1.c'
then
${echo} "x - SKIPPING wzab_nic1.c (file already exists)"
else
${echo} "x - extracting wzab_nic1.c (text)"
sed 's/^X//' << 'SHAR_EOF' > 'wzab_nic1.c' &&
/*
X * QEMU - Emulation of network adapter with Bus Mastering DMA and scattered packet buffers
X *
X * Copyright Wojciech M. Zabolotny (
wz...@ise.pw.edu.pl ) 17.06.2011
X *
X * Permission is hereby granted, free of charge, to any person obtaining a copy
X * of this software and associated documentation files (the "Software"), to deal
X * in the Software without restriction, including without limitation the rights
X * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
X * copies of the Software, and to permit persons to whom the Software is
X * furnished to do so, subject to the following conditions:
X *
X * The above copyright notice and this permission notice shall be included in
X * all copies or substantial portions of the Software.
X *
X * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
X * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
X * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
X * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
X * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
X * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
X * THE SOFTWARE.
X */
X
/* based on mipsnet.c taken from original QEMU sources */
X
//#define DEBUG_wzab1 1
#define MAX_ETH_FRAME_SIZE 1514
//PCI IDs below are not registred! Use only for experiments!
#define PCI_VENDOR_ID_WZAB 0xabba
#define PCI_DEVICE_ID_WZAB_WZNIC1 0x0232
X
//Simulated processing time
#define NIC1_PROCESSING_TIME 5000000
#include <string.h>
#include "hw.h"
#include "pci.h"
#include "net.h"
#include "qemu-timer.h"
#include "wzab_nic1.h"
#include <stdint.h>
X
#define min(x,y) ((x<y) ? x : y)
/*
X Description of functionalities.
X The emulated hardware is a network adapter working with packet buffers
X located in the host's memory.
X There are two packet buffers - transmit buffer and receive buffer.
X Each of them may span across several pages.
X
X Packet buffers are served as circular buffers.
X Each packet is stored in a special form, allowing to separate individual
X packets:
X A. Header:
X 1. Packet magic number
X 2. Packet length (including the header and the contents)
X 3. Packet flags (not used yet)
X B. Packet contents
X
X Packet transmission:
X Driver writes the packet to the packet buffer. After the packet is stored,
X the driver updates the head pointer in the Tx packet buffer.
*/
/* Structure used as a pointer to data in Tx/Rx buffers */
typedef struct
{
X int page;
X int offset; //in 32 bit words!
} WzNic1Ptr;
X
typedef struct WzNic1State
{
X PCIDevice dev;
X union
X {
X WzNic1Regs r;
X uint32_t u32[sizeof ( WzNic1Regs ) /sizeof ( uint32_t ) ];
X } regs;
X WzNic1Ptr Tx_Tail;
X WzNic1Ptr Tx_Head;
X WzNic1Ptr Rx_Tail;
X WzNic1Ptr Rx_Head;
X uint32_t wz_nic1_mmio_io_addr;
X QEMUTimer * timer;
X NICState *nic;
X NICConf conf;
unsigned int Error:
X 1;
unsigned int TxCorruptedBuffer:
X 1 ;
unsigned int Tx_Irq_Enabled :
X 1;
unsigned int Rx_Irq_Enabled :
X 1;
unsigned int Rx_Enabled :
X 1;
unsigned int tx_irq_pending :
X 1;
unsigned int rx_irq_pending :
X 1;
unsigned int irq_pending :
X 1;
unsigned int promiscous :
X 1;
} WzNic1State;
X
//Some prototypes...
uint32_t wz_nic1_mem_readl ( void *opaque, target_phys_addr_t addr );
void wz_nic1_mem_writel ( void *opaque, target_phys_addr_t addr, uint32_t val );
int wz_nic1_init ( PCIBus *bus );
void wz_nic1_send_packets ( WzNic1State * s );
void wz_nic1_update_irq(WzNic1State * s);
static NetClientInfo wz_nic1_nc_info;
X
X
static void wz_nic1_reset ( WzNic1State *s )
{
X memset ( ( void * ) s->regs.u32,0,sizeof ( s->regs.u32 ) );
#ifdef DEBUG_wzab1
X printf ( "wzab_nic1 reset!\n" );
#endif
}
X
/* called for read accesses to our register memory area */
uint32_t wz_nic1_mem_readl ( void *opaque, target_phys_addr_t addr )
{
X int i_addr;
#ifdef DEBUG_wzab1
X printf ( "Memory read: address %x\n ", ( unsigned int ) addr );
#endif
X WzNic1State *s = opaque;
X if ( addr>=sizeof ( WzNic1Regs ) )
X {
X //Read above registers area - return "0xbada4ea" to show it
X return 0xbada4ea;
X }
X else if ( addr == offsetof ( WzNic1Regs, Status ) )
X {
X //Reading of the Status - synthesize the correct value
X uint32_t res = s->Error & 0xffff ; //Lower 16 bits!
X if ( s->irq_pending ) res |= NIC1_ST_IRQ;
X if ( s->tx_irq_pending ) res |= NIC1_ST_TX_IRQ;
X if ( s->Tx_Irq_Enabled ) res |= NIC1_ST_TX_IRQ_ENA;
X if ( s->rx_irq_pending ) res |= NIC1_ST_RX_IRQ;
X if ( s->Rx_Irq_Enabled ) res |= NIC1_ST_RX_IRQ_ENA;
X if ( s->promiscous ) res |= NIC1_ST_PROMISCOUS;
X //
X if (s->Rx_Enabled) res |= NIC1_ST_ENA_RX;
X if (s->TxCorruptedBuffer) res |= NIC1_ST_TX_COR_BUF;
X if (s->Error) res |= NIC1_ST_ERROR;
#ifdef DEBUG_wzab1
X printf ( "Status=%d\n",res );
#endif
X return res;
X }
X else if ( addr == offsetof ( WzNic1Regs, RxTail ) )
X {
X uint32_t res;
X qemu_mutex_lock_iothread();
X res = s->Rx_Tail.offset+(s->Rx_Tail.page<<10);
X qemu_mutex_unlock_iothread();
X return res;
X }
X else if ( addr == offsetof ( WzNic1Regs, RxHead ) )
X {
X uint32_t res;
X qemu_mutex_lock_iothread();
X res = s->Rx_Head.offset+(s->Rx_Head.page<<10);
X qemu_mutex_unlock_iothread();
X return res;
X }
X else if ( addr == offsetof ( WzNic1Regs, RxNumOfBytes ) )
X {
X uint32_t res;
X qemu_mutex_lock_iothread();
X res = WZNIC1_NOF_RX_PAGES * 4096;
X qemu_mutex_unlock_iothread();
X return res;
X }
X else if ( addr == offsetof ( WzNic1Regs, TxTail ) )
X {
X uint32_t res;
X qemu_mutex_lock_iothread();
X res = s->Tx_Tail.offset+(s->Tx_Tail.page<<10);
X qemu_mutex_unlock_iothread();
X return res;
X }
X else if ( addr == offsetof ( WzNic1Regs, TxHead ) )
X {
X uint32_t res;
X qemu_mutex_lock_iothread();
X res = s->Tx_Head.offset+(s->Tx_Head.page<<10);
X qemu_mutex_unlock_iothread();
X return res;
X }
X else if ( addr == offsetof ( WzNic1Regs, TxNumOfBytes ) )
X {
X uint32_t res;
X qemu_mutex_lock_iothread();
X res = WZNIC1_NOF_TX_PAGES * 4096;
X qemu_mutex_unlock_iothread();
X return res;
X }
X else
X {
X i_addr = addr/4;
X //Read the register
X return s->regs.u32[i_addr];
X }
}
X
/* Function used to dereference bytes/words in the Tx buffer */
static inline uint32_t tx_buf_addr ( WzNic1State *s, WzNic1Ptr ptr )
{
X return ( s->regs.r.TxPages[
ptr.page].PhysAddr ) +4* ( ptr.offset );
}
X
static inline void tx_increase_ptr ( WzNic1State *s, WzNic1Ptr * ptr )
{
X int tmp = ptr->offset + 1;
X if ( tmp>=1024 )
X {
X tmp -= 1024;
X ptr->page ++;
X if ( ptr->page >= WZNIC1_NOF_TX_PAGES )
X ptr->page= ptr->page % WZNIC1_NOF_TX_PAGES;
X }
X ptr->offset = tmp;
}
X
static inline void tx_add_ptr (WzNic1State *s, WzNic1Ptr * ptr, uint32_t val)
{
X uint32_t tmp = ptr->offset+val;
X uint32_t npages = tmp >> 10; //Number of pages
X ptr->offset = tmp & 0x3ff; //lower 10 bits, as pages are 4096 bytes long
X ptr->page = (ptr->page + npages) % WZNIC1_NOF_TX_PAGES;
}
X
/* Function used to dereference bytes/words in the Rx buffer */
static inline uint32_t rx_buf_addr ( WzNic1State *s, WzNic1Ptr ptr )
{
X return ( s->regs.r.RxPages[
ptr.page].PhysAddr ) +4* ( ptr.offset );
}
X
static inline void rx_increase_ptr ( WzNic1State *s, WzNic1Ptr * ptr )
{
X int tmp = ptr->offset + 1;
X if ( tmp>=1024 )
X {
X tmp -= 1024;
X ptr->page ++;
X if ( ptr->page >= WZNIC1_NOF_RX_PAGES )
X ptr->page= ptr->page % WZNIC1_NOF_RX_PAGES;
X }
X ptr->offset = tmp;
}
X
static inline void rx_add_ptr (WzNic1State *s, WzNic1Ptr * ptr, uint32_t val)
{
X uint32_t tmp = ptr->offset+val;
X uint32_t npages = tmp >> 10; //Number of pages
X ptr->offset = tmp & 0x3ff; //lower 10 bits, as pages are 4096 bytes long
X ptr->page = (ptr->page + npages) % WZNIC1_NOF_RX_PAGES;
}
X
static inline uint32_t rx_buf_space(WzNic1State *s)
{
X const uint32_t num_of_bytes = WZNIC1_NOF_RX_PAGES*4096;
X int space;
X qemu_mutex_lock_iothread();
X int head = s->Rx_Head.page*4096+s->Rx_Head.offset*4;
X int tail = s->Rx_Tail.page*4096+s->Rx_Tail.offset*4;
X qemu_mutex_unlock_iothread();
X space = tail-head;
X if (space <= 0) space += num_of_bytes;
X space --;
X return space;
}
/* Procedure sending the packets from the Tx buffer */
void wz_nic1_send_packets ( WzNic1State * s )
{
X //Check if there is anything to send
X //We have a few options to send the packets
X //either we send all packets immediately, or we simulate delay associated
X //with sending of packets
X /* Sending of all packets at the same time is easier */
X while (1)
X {
X //There is something to send
X //Check the header
X WzNic1Ptr ptr;
X uint32_t flags, tmp;
X int bptr;
X uint32_t len_in_bytes; //Length of the packet without the header
X uint32_t len_in_u32; //Length of the packet in 32-bit words
X int niov; //Number of iovecs to send the packet
X qemu_mutex_lock_iothread();
X if ((s->Tx_Tail.offset == s->Tx_Head.offset) &&
X (s->Tx_Tail.page == s->Tx_Head.page)) {
X qemu_mutex_unlock_iothread();
X return; //No more packets to send
X }
X memcpy ( &ptr,&s->Tx_Tail,sizeof ( ptr ) );
X qemu_mutex_unlock_iothread();
X bptr = tx_buf_addr ( s, ptr );
X cpu_physical_memory_read(bptr,&tmp,4);
X if (tmp != WZNIC1_PKT_MAGIC_NUMBER )
X {
X s->TxCorruptedBuffer = 1;
X s->Error = 1;
X //Error - set the error flag and return
X return;
X }
X //Take the packet length in bytes
X tx_increase_ptr ( s,&ptr );
X cpu_physical_memory_read(tx_buf_addr ( s,ptr ),&len_in_bytes,4);
X len_in_u32 = ( len_in_bytes+3 ) >>2;
X tx_increase_ptr ( s,&ptr );
X //Take the flags
X cpu_physical_memory_read(tx_buf_addr ( s,ptr ),&flags,4);
X //Mark the packet as serviced
X {
X //To be done!!!
X }
X tx_increase_ptr ( s,&ptr );
X //Now the pointer points to the first word containing the packet data
X //Send the packet
X {
X //Allocate temporary buffer on stack (hmmm... is it safe for long buffers?)
X uint32_t pkt_buf[len_in_u32];
X int len = len_in_bytes;
X int i=0;
X while (len>0) {
X //Copy the whole world
X cpu_physical_memory_read(tx_buf_addr ( s,ptr ),&pkt_buf[i],4);
X tx_increase_ptr ( s,&ptr );
X len -= 4;
X i++;
X }
X if(0){
X int i;
X printf("send: ");
X for(i=0;i<10;i++) printf("%2.2x ",(int) pkt_buf[i]);
X printf("\n");
X }
X qemu_send_packet ( &s->nic->nc, pkt_buf, len_in_bytes);
X }
X /*
X * The code below could be nice and efficient, but requires
X * use of cpu_physical_memory_map,
X //Send the packet using the iovec
X //Calculate the number of iovecs needed to send
X niov = ( 4*ptr.offset + len_in_bytes + 0xfff ) >>12;
X {
X struct iovec iov[niov]; //Use the GCC extension - dynamic allocation on stack
X //Fill the iovec structures
X int bytes_left = len_in_bytes;
X int offs=ptr.offset;
X int i;
X for ( i=0;i<niov;i++ )
X {
X iov[i].iov_base = s->regs.r.TxPages[ (
ptr.page+i ) % WZNIC1_NOF_TX_PAGES].PhysAddr+offs;
X iov[i].iov_len = min ( 4096-offs,bytes_left );
X bytes_left -= min ( 4096-offs,bytes_left );
X offs=0;
X }
X //After this loop our packet is ready, so transmit it!
X qemu_sendv_packet ( &s->nic->nc, iov, niov );
X //Finally update interrupts
X wz_nic1_update_irq ( s );
X }
X */
X qemu_mutex_lock_iothread();
X memcpy ( &s->Tx_Tail,&ptr,sizeof ( ptr ) );
X qemu_mutex_unlock_iothread();
X wz_nic1_update_irq(s);
X }
X return;
}
X
static int wz_nic1_buffer_full ( WzNic1State *s )
{
X //Calculate the amount of free buffer
X
X if ( rx_buf_space(s) <= MAX_ETH_FRAME_SIZE+20 )
X return 1;
X return 0;
}
X
static int wz_nic1_can_receive ( VLANClientState *nc )
{
X WzNic1State *s = DO_UPCAST ( NICState, nc, nc )->opaque;
X if (s->Rx_Enabled==0) return 0;
X return !wz_nic1_buffer_full ( s );
}
X
static ssize_t wz_nic1_receive ( VLANClientState *nc, const uint8_t *buf, size_t size )
{
X WzNic1State *s = DO_UPCAST ( NICState, nc, nc )->opaque;
X
X if ( !wz_nic1_can_receive ( nc ) )
X return -1;
#ifdef DEBUG_wzab1
X printf ( "wz_nic1: receiving len=%zu\n", size );
#endif
X
X /* Just accept everything. */
X {
X WzNic1Ptr ptr;
X int bptr;
X size_t tmp_size;
X uint32_t tmp;
X int i;
X memcpy ( &ptr,&s->Rx_Head,sizeof ( ptr ) );
X bptr = rx_buf_addr ( s, ptr ); //To jest adres w maszynie wirtualnej!!!
X tmp = WZNIC1_PKT_MAGIC_NUMBER;
X cpu_physical_memory_write(bptr,&tmp,4);
X /* Write packet header */
X //We are already sure, that the packet will fit
X rx_increase_ptr ( s,&ptr );
X bptr = rx_buf_addr (s, ptr );
X cpu_physical_memory_write(bptr,&size,4); //Length of the packet
X rx_increase_ptr ( s, &ptr );
X bptr = rx_buf_addr (s, ptr );
X tmp = 0 ; //Flags - @@ to be corrected!
X cpu_physical_memory_write(bptr,&tmp,4); //Flags of the packet
X rx_increase_ptr ( s, &ptr );
X //Now we can copy the data
X tmp_size = size;
X while ( tmp_size >= 4 )
X {
X bptr = rx_buf_addr (s, ptr );
X cpu_physical_memory_write(bptr,buf,4); //Contents of the packet
X rx_increase_ptr ( s, &ptr );
X tmp_size -= 4;
X buf+=4;
X }
X //Last part of the buffer must be copied byte by byte...
X //We are working on a LE platform, so we can handle it as follows:
X if (tmp_size) {
X //First we have to check if such "remainder" exists...
X tmp = 0;
X i=0;
X while (tmp_size) {
X tmp |= ((uint32_t) *buf) << (8*i);
X i++;
X buf++;
X tmp_size--;
X }
X bptr = rx_buf_addr (s, ptr );
X cpu_physical_memory_write(bptr,&tmp,4); //Rest of the content of the packet
X //OK. The whole packet is stored, so now we have to update the pointer
X rx_increase_ptr ( s, &ptr );
X }
X qemu_mutex_lock_iothread();
X memcpy ( &s->Rx_Head, &ptr, sizeof ( ptr ) );
X qemu_mutex_unlock_iothread();
X }
X wz_nic1_update_irq( s );
X return size;
}
X
X
/* called for write accesses to our register memory area */
void wz_nic1_mem_writel ( void *opaque, target_phys_addr_t addr, uint32_t val )
{
X WzNic1State *s = opaque;
X int i_addr;
#ifdef DEBUG_wzab1
X printf ( "wzab1: zapis pod adres = 0x%08x, 0x%08x\n", ( unsigned int ) addr, val );
#endif
X /* Check which register is accessed */
X if ( addr>=sizeof ( WzNic1Regs ) )
X {
X //Write above registers area - ignore it!
X }
X else
X {
X i_addr = addr/4;
X //Write the value
X s->regs.u32[i_addr]=val;
X //Interprete its special meaning
X if (addr==offsetof (WzNic1Regs,RxTail))
X {
X uint32_t tmp;
X qemu_mutex_lock_iothread();
X s->Rx_Tail.offset=val & 0x3ff;
X tmp=val >> 10;
X if (tmp >= WZNIC1_NOF_RX_PAGES) tmp = 0;
X s->Rx_Tail.page = tmp;
X qemu_mutex_unlock_iothread();
X }
X if (addr==offsetof (WzNic1Regs,TxHead))
X {
X uint32_t tmp;
X qemu_mutex_lock_iothread();
X s->Tx_Head.offset=val & 0x3ff;
X tmp=val >> 10;
X if (tmp >= WZNIC1_NOF_TX_PAGES) tmp = 0;
X s->Tx_Head.page = tmp;
X qemu_mutex_unlock_iothread();
X }
X if ( addr==offsetof ( WzNic1Regs,Ctrl ) )
X {
X //Write to control register - we need to check what operation is required
X switch ( val )
X {
X case NIC1_CMD_ENA_TX_IRQ:
X s->Tx_Irq_Enabled = 1;
X break;
X case NIC1_CMD_DIS_TX_IRQ:
X s->Tx_Irq_Enabled = 0;
X break;
X case NIC1_CMD_ENA_RX_IRQ:
X s->Rx_Irq_Enabled = 1;
X break;
X case NIC1_CMD_DIS_RX_IRQ:
X s->Rx_Irq_Enabled = 0;
X break;
X case NIC1_CMD_ENA_RX:
X s->Rx_Enabled = 1;
X break;
X case NIC1_CMD_DIS_RX:
X s->Rx_Enabled = 0;
X break;
X case NIC1_CMD_SEND:
X wz_nic1_send_packets(s);
X break;
X case NIC1_CMD_CLEAR:
X s->Rx_Enabled = 0;
X s->TxCorruptedBuffer = 0;
X s->Error = 0;
X s->Rx_Tail.offset=0;
X s->Rx_Tail.page=0;
X s->Rx_Head.offset=0;
X s->Rx_Head.page=0;
X s->Tx_Tail.offset=0;
X s->Tx_Tail.page=0;
X s->Tx_Head.offset=0;
X s->Tx_Head.page=0;
X break;
X case NIC1_CMD_ENA_PROMISCOUS:
X s->promiscous = 1;
X break;
X case NIC1_CMD_DIS_PROMISCOUS:
X s->promiscous = 0;
X break;
X
X }
X }
X }
X wz_nic1_update_irq(s);
}
X
/* The procedure below performs the real encryption, after simulated processing time is expired */
static void wzab1_tick ( void *opaque )
{
X WzNic1State * s = opaque;
X //Encrypt the data
X {
X }
#ifdef DEBUG_wzab1
X printf ( "Data processed - request IRQ!\n" );
#endif
X
}
X
X
static void wz_nic1_map ( PCIDevice *pci_dev, int region_num,
X pcibus_t addr, pcibus_t size, int type )
{
X WzNic1State *s = DO_UPCAST ( WzNic1State, dev, pci_dev );
X
X ( void ) region_num;
X ( void ) size;
X ( void ) type;
X
X cpu_register_physical_memory ( addr,size,s->wz_nic1_mmio_io_addr );
}
X
X
/* We handle only 32-bit accesses! */
CPUReadMemoryFunc * const wz_nic1_mmio_read[3] =
{
X NULL,
X NULL,
X wz_nic1_mem_readl,
};
X
/* We handle only 32-bit accesses! */
CPUWriteMemoryFunc * const wz_nic1_mmio_write[3] =
{
X NULL,
X NULL,
X wz_nic1_mem_writel,
};
X
//Sorry, but the state description below is not complete!
//You are free to fix it!
static const VMStateDescription vmstate_wz_nic1 =
{
X .name = "wz_nic1",
X .version_id = 2,
X .minimum_version_id = 2,
X .minimum_version_id_old = 2,
X .fields = ( VMStateField [] )
X {
X VMSTATE_PCI_DEVICE ( dev, WzNic1State ),
X VMSTATE_TIMER ( timer,WzNic1State ),
X VMSTATE_END_OF_LIST()
X }
};
X
static void wz_nic1_on_reset ( void *opaque )
{
X WzNic1State *s = opaque;
X wz_nic1_reset ( s );
}
X
static int wz_nic1_initfn ( PCIDevice *dev )
{
X WzNic1State *s = DO_UPCAST ( WzNic1State, dev, dev );
X uint8_t *c = s->dev.config;
X s->Rx_Irq_Enabled=0;
X s->Tx_Irq_Enabled=0;
X s->Rx_Enabled=0;
X s->Rx_Head.offset=0;
X s->Rx_Head.page=0;
X s->Rx_Tail.offset=0;
X s->Rx_Tail.page=0;
X s->Tx_Head.offset=0;
X s->Tx_Head.page=0;
X s->Tx_Tail.offset=0;
X s->Tx_Tail.page=0;
X s->Error=0;
X s->TxCorruptedBuffer=0;
X //Set values in the configuration space
X pci_config_set_vendor_id ( c, PCI_VENDOR_ID_WZAB );
X pci_config_set_device_id ( c, PCI_DEVICE_ID_WZAB_WZNIC1 );
X pci_config_set_class ( c, PCI_CLASS_NETWORK_ETHERNET );
X
X /* TODO: RST# value should be 0. */
X c[PCI_INTERRUPT_PIN] = 1;
X //Register memory mapped registers
X s->wz_nic1_mmio_io_addr = cpu_register_io_memory ( wz_nic1_mmio_read, wz_nic1_mmio_write,
X s, DEVICE_LITTLE_ENDIAN );
X pci_register_bar ( &s->dev, 0, 0x1000, PCI_BASE_ADDRESS_SPACE_MEMORY, wz_nic1_map );
X qemu_register_reset ( wz_nic1_on_reset, s );
X qemu_macaddr_default_if_unset(&s->conf.macaddr);
X s->nic = qemu_new_nic(&wz_nic1_nc_info, &s->conf,
X dev->qdev.info->name, dev->
qdev.id, s);
X qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
X //Register timer used to simulate processing time
X s->timer = qemu_new_timer ( vm_clock, wzab1_tick, s );
X wz_nic1_reset ( s );
X return 0;
}
X
void wz_nic1_update_irq(WzNic1State * s)
{
X //Check Tx interrupt
X s->irq_pending = 0;
X qemu_mutex_lock_iothread();
X if ((s->Tx_Head.page==s->Tx_Tail.page) && (s->Tx_Head.offset==s->Tx_Tail.offset))
X s->tx_irq_pending = 1;
X else
X s->tx_irq_pending = 0;
X qemu_mutex_unlock_iothread();
X //Check Rx interrupt
X qemu_mutex_lock_iothread();
X if ((s->Rx_Head.page==s->Rx_Tail.page) && (s->Rx_Head.offset==s->Rx_Tail.offset))
X s->rx_irq_pending = 0;
X else
X s->rx_irq_pending = 1;
X qemu_mutex_unlock_iothread();
X if (s->Rx_Irq_Enabled && s->rx_irq_pending)
X s->irq_pending |= 1;
X if (s->Tx_Irq_Enabled && s->tx_irq_pending)
X s->irq_pending |= 1;
X if (s->irq_pending)
X qemu_irq_raise(s->dev.irq[0]);
X else
X qemu_irq_lower(s->dev.irq[0]);
}
X
static void wz_nic1_cleanup(VLANClientState *nc)
{
X struct WzNic1State *s = DO_UPCAST(NICState, nc, nc)->opaque;
X
X s->nic = NULL;
}
X
static NetClientInfo wz_nic1_nc_info = {
X .type = NET_CLIENT_TYPE_NIC,
X .size = sizeof(NICState),
X .can_receive = wz_nic1_can_receive,
X .receive = wz_nic1_receive,
X .cleanup = wz_nic1_cleanup,
};
X
X
int wz_nic1_init ( PCIBus *bus )
{
X pci_create_simple ( bus, -1, "WZNIC1" );
X return 0;
}
X
static PCIDeviceInfo wz_nic1_info =
{
X .
qdev.name = "WZNIC1",
X .qdev.desc = "WZNIC1 - Model of network adapter card",
X .qdev.size = sizeof ( WzNic1State ),
X .qdev.vmsd = &vmstate_wz_nic1,
X .init = wz_nic1_initfn,
X .qdev.props = (Property[]) {
X DEFINE_NIC_PROPERTIES(WzNic1State, conf),
X DEFINE_PROP_END_OF_LIST(),
X }
};
X
X
static void wz_nic1_register ( void )
{
X pci_qdev_register ( &wz_nic1_info );
}
X
device_init ( wz_nic1_register );
X
SHAR_EOF
(set 20 12 04 07 01 04 49 'wzab_nic1.c'
eval "${shar_touch}") && \
chmod 0644 'wzab_nic1.c'
if test $? -ne 0
then ${echo} "restore of wzab_nic1.c failed"
fi
if ${md5check}
then (
${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'wzab_nic1.c': 'MD5 check failed'
) << \SHAR_EOF
c99b6cde87428bd687959e943333d0ac wzab_nic1.c
SHAR_EOF
else
test `LC_ALL=C wc -c < 'wzab_nic1.c'` -ne 22545 && \
${echo} "restoration warning: size of 'wzab_nic1.c' is not 22545"
fi
fi
if rm -fr ${lock_dir}
then ${echo} "x - removed lock directory ${lock_dir}."
else ${echo} "x - failed to remove lock directory ${lock_dir}."
exit 1
fi
exit 0