Safecopy support in ethernet drivers.

This commit is contained in:
Philip Homburg 2006-07-10 12:43:38 +00:00
parent 9392742cc4
commit 2cf649db2e
15 changed files with 2150 additions and 579 deletions

View file

@ -21,7 +21,7 @@ OBJ = 3c503.o dp8390.o ne2000.o rtl8029.o wdeth.o
all build: $(DRIVER)
$(DRIVER): $(OBJ)
$(CC) -o $@ $(LDFLAGS) $(OBJ) $(LIBS)
install -S 4096 $(DRIVER)
install -S 32k $(DRIVER)
# install with other drivers
install: /usr/sbin/$(DRIVER)

File diff suppressed because it is too large Load diff

View file

@ -172,14 +172,21 @@ typedef struct dp_rcvhdr
struct dpeth;
struct iovec_dat;
struct iovec_dat_s;
_PROTOTYPE( typedef void (*dp_initf_t), (struct dpeth *dep) );
_PROTOTYPE( typedef void (*dp_stopf_t), (struct dpeth *dep) );
_PROTOTYPE( typedef void (*dp_user2nicf_t), (struct dpeth *dep,
struct iovec_dat *iovp, vir_bytes offset,
int nic_addr, vir_bytes count) );
_PROTOTYPE( typedef void (*dp_user2nicf_s_t), (struct dpeth *dep,
struct iovec_dat_s *iovp, vir_bytes offset,
int nic_addr, vir_bytes count) );
_PROTOTYPE( typedef void (*dp_nic2userf_t), (struct dpeth *dep,
int nic_addr, struct iovec_dat *iovp,
vir_bytes offset, vir_bytes count) );
_PROTOTYPE( typedef void (*dp_nic2userf_s_t), (struct dpeth *dep,
int nic_addr, struct iovec_dat_s *iovp,
vir_bytes offset, vir_bytes count) );
#if 0
_PROTOTYPE( typedef void (*dp_getheaderf_t), (struct dpeth *dep,
int page, struct dp_rcvhdr *h, u16_t *eth_type) );
@ -200,6 +207,15 @@ typedef struct iovec_dat
vir_bytes iod_iovec_addr;
} iovec_dat_t;
typedef struct iovec_dat_s
{
iovec_s_t iod_iovec[IOVEC_NR];
int iod_iovec_s;
int iod_proc_nr;
cp_grant_id_t iod_grant;
vir_bytes iod_iovec_offset;
} iovec_dat_s_t;
#define SENDQ_NR 2 /* Maximum size of the send queue */
#define SENDQ_PAGES 6 /* 6 * DP_PAGESIZE >= 1514 bytes */
@ -215,6 +231,7 @@ typedef struct dpeth
*/
port_t de_base_port;
phys_bytes de_linmem;
char *de_locmem;
int de_irq;
int de_int_pending;
irq_hook_t de_hook;
@ -261,13 +278,19 @@ typedef struct dpeth
int de_mode;
eth_stat_t de_stat;
iovec_dat_t de_read_iovec;
iovec_dat_s_t de_read_iovec_s;
int de_safecopy_read;
iovec_dat_t de_write_iovec;
iovec_dat_s_t de_write_iovec_s;
iovec_dat_t de_tmp_iovec;
iovec_dat_s_t de_tmp_iovec_s;
vir_bytes de_read_s;
int de_client;
message de_sendmsg;
dp_user2nicf_t de_user2nicf;
dp_user2nicf_s_t de_user2nicf_s;
dp_nic2userf_t de_nic2userf;
dp_nic2userf_s_t de_nic2userf_s;
dp_getblock_t de_getblockf;
} dpeth_t;

View file

@ -122,16 +122,19 @@ static void el3_write_fifo(dpeth_t * dep, int pktsize)
{
phys_bytes phys_user;
int bytes, ix = 0;
iovec_dat_t *iovp = &dep->de_write_iovec;
int padding = pktsize;
iovec_dat_s_t *iovp = &dep->de_write_iovec;
int r, padding = pktsize;
do { /* Writes chuncks of packet from user buffers */
bytes = iovp->iod_iovec[ix].iov_size; /* Size of buffer */
if (bytes > pktsize) bytes = pktsize;
/* Writes from user buffer to Tx FIFO */
outsb(dep->de_data_port, iovp->iod_proc_nr,
(void*)(iovp->iod_iovec[ix].iov_addr), bytes);
r= sys_safe_insb(dep->de_data_port, iovp->iod_proc_nr,
iovp->iod_iovec[ix].iov_grant, 0, bytes);
if (r != OK)
panic(__FILE__, "el3_write_fifo: sys_safe_insb failed", r);
if (++ix >= IOVEC_NR) { /* Next buffer of IO vector */
dp_next_iovec(iovp);
ix = 0;

View file

@ -1,3 +1,4 @@
#include <assert.h>
/*
** File: 8390.c May 02, 2000
**
@ -25,14 +26,18 @@
#include "8390.h"
#if 0
#define sys_nic2mem(srcOffs,dstProc,dstOffs,length) \
sys_vircopy(SELF,dep->de_memsegm,(vir_bytes)(srcOffs),\
(dstProc),D,(vir_bytes)(dstOffs),length)
#define sys_user2nic(srcProc,srcOffs,dstOffs,length) \
sys_vircopy((srcProc),D,(vir_bytes)(srcOffs),\
SELF,dep->de_memsegm,(vir_bytes)(dstOffs),length)
#endif
#if 0
#define sys_user2nic_s(srcProc,grant,dstOffs,length) \
sys_safecopyfrom((srcProc),(grant),0, \
(vir_bytes)(dstOffs),length,dep->de_memsegm)
#endif
static const char RdmaErrMsg[] = "remote dma failed to complete";
static char RdmaErrMsg[] = "remote dma failed to complete";
/*
** Name: void ns_rw_setup(dpeth_t *dep, int mode, int size, u16_t offset);
@ -72,9 +77,11 @@ static void ns_start_xmit(dpeth_t * dep, int size, int pageno)
*/
static void mem_getblock(dpeth_t *dep, u16_t offset, int size, void *dst)
{
panic(__FILE__, "mem_getblock: not converted to safecopies", NO_NUM);
#if 0
sys_nic2mem(dep->de_linmem + offset, SELF, dst, size);
return;
#endif
}
/*
@ -84,9 +91,12 @@ static void mem_getblock(dpeth_t *dep, u16_t offset, int size, void *dst)
static void mem_nic2user(dpeth_t * dep, int pageno, int pktsize)
{
phys_bytes offset, phys_user;
iovec_dat_t *iovp = &dep->de_read_iovec;
iovec_dat_s_t *iovp = &dep->de_read_iovec;
int bytes, ix = 0;
panic(__FILE__, "mem_nic2user: not converted to safecopies", NO_NUM);
#if 0
/* Computes shared memory address (skipping receive header) */
offset = pageno * DP_PAGESIZE + sizeof(dp_rcvhdr_t);
@ -100,16 +110,16 @@ static void mem_nic2user(dpeth_t * dep, int pageno, int pktsize)
/* Circular buffer wrap-around */
bytes = dep->de_stoppage * DP_PAGESIZE - offset;
sys_nic2mem(dep->de_linmem + offset, iovp->iod_proc_nr,
iovp->iod_iovec[ix].iov_addr, bytes);
sys_nic2mem_s(dep->de_linmem + offset, iovp->iod_proc_nr,
iovp->iod_iovec[ix].iov_grant, bytes);
pktsize -= bytes;
phys_user += bytes;
bytes = iovp->iod_iovec[ix].iov_size - bytes;
if (bytes > pktsize) bytes = pktsize;
offset = dep->de_startpage * DP_PAGESIZE;
}
sys_nic2mem(dep->de_linmem + offset, iovp->iod_proc_nr,
iovp->iod_iovec[ix].iov_addr, bytes);
sys_nic2mem_s(dep->de_linmem + offset, iovp->iod_proc_nr,
iovp->iod_iovec[ix].iov_grant, bytes);
offset += bytes;
if (++ix >= IOVEC_NR) { /* Next buffer of IO vector */
@ -119,6 +129,7 @@ static void mem_nic2user(dpeth_t * dep, int pageno, int pktsize)
/* Till packet done */
} while ((pktsize -= bytes) > 0);
return;
#endif
}
/*
@ -128,9 +139,12 @@ static void mem_nic2user(dpeth_t * dep, int pageno, int pktsize)
static void mem_user2nic(dpeth_t *dep, int pageno, int pktsize)
{
phys_bytes offset, phys_user;
iovec_dat_t *iovp = &dep->de_write_iovec;
iovec_dat_s_t *iovp = &dep->de_write_iovec;
int bytes, ix = 0;
panic(__FILE__, "mem_user2nic: not converted to safecopies", NO_NUM);
#if 0
/* Computes shared memory address */
offset = pageno * DP_PAGESIZE;
@ -140,7 +154,7 @@ static void mem_user2nic(dpeth_t *dep, int pageno, int pktsize)
if (bytes > pktsize) bytes = pktsize;
/* Reads from user area to board (shared memory) */
sys_user2nic(iovp->iod_proc_nr, iovp->iod_iovec[ix].iov_addr,
sys_user2nic_s(iovp->iod_proc_nr, iovp->iod_iovec[ix].iov_grant,
dep->de_linmem + offset, bytes);
offset += bytes;
@ -151,6 +165,7 @@ static void mem_user2nic(dpeth_t *dep, int pageno, int pktsize)
/* Till packet done */
} while ((pktsize -= bytes) > 0);
return;
#endif
}
/*
@ -183,8 +198,8 @@ static void pio_getblock(dpeth_t *dep, u16_t offset, int size, void *dst)
static void pio_nic2user(dpeth_t *dep, int pageno, int pktsize)
{
phys_bytes phys_user;
iovec_dat_t *iovp = &dep->de_read_iovec;
unsigned offset; int bytes, ix = 0;
iovec_dat_s_t *iovp = &dep->de_read_iovec;
unsigned offset, iov_offset; int r, bytes, ix = 0;
/* Computes memory address (skipping receive header) */
offset = pageno * DP_PAGESIZE + sizeof(dp_rcvhdr_t);
@ -192,6 +207,7 @@ static void pio_nic2user(dpeth_t *dep, int pageno, int pktsize)
ns_rw_setup(dep, CR_DM_RR, ((offset + pktsize) > (dep->de_stoppage * DP_PAGESIZE)) ?
(dep->de_stoppage * DP_PAGESIZE) - offset : pktsize, offset);
iov_offset= 0;
do { /* Reads chuncks of packet into user area */
bytes = iovp->iod_iovec[ix].iov_size; /* Size of a chunck */
@ -201,21 +217,31 @@ static void pio_nic2user(dpeth_t *dep, int pageno, int pktsize)
/* Circular buffer wrap-around */
bytes = dep->de_stoppage * DP_PAGESIZE - offset;
insb(dep->de_data_port, iovp->iod_proc_nr, (void*)(iovp->iod_iovec[ix].iov_addr), bytes);
r= sys_safe_insb(dep->de_data_port, iovp->iod_proc_nr,
iovp->iod_iovec[ix].iov_grant, iov_offset, bytes);
if (r != OK)
{
panic(__FILE__, "pio_nic2user: sys_safe_insb failed",
r);
}
pktsize -= bytes;
iovp->iod_iovec[ix].iov_addr += bytes;
iov_offset += bytes;
bytes = iovp->iod_iovec[ix].iov_size - bytes;
if (bytes > pktsize) bytes = pktsize;
offset = dep->de_startpage * DP_PAGESIZE;
ns_rw_setup(dep, CR_DM_RR, pktsize, offset);
}
insb(dep->de_data_port, iovp->iod_proc_nr, (void*)(iovp->iod_iovec[ix].iov_addr), bytes);
r= sys_safe_insb(dep->de_data_port, iovp->iod_proc_nr,
iovp->iod_iovec[ix].iov_grant, iov_offset, bytes);
if (r != OK)
panic(__FILE__, "pio_nic2user: sys_safe_insb failed", r);
offset += bytes;
if (++ix >= IOVEC_NR) { /* Next buffer of IO vector */
dp_next_iovec(iovp);
ix = 0;
}
iov_offset= 0;
/* Till packet done */
} while ((pktsize -= bytes) > 0);
return;
@ -228,8 +254,8 @@ static void pio_nic2user(dpeth_t *dep, int pageno, int pktsize)
static void pio_user2nic(dpeth_t *dep, int pageno, int pktsize)
{
phys_bytes phys_user;
iovec_dat_t *iovp = &dep->de_write_iovec;
int bytes, ix = 0;
iovec_dat_s_t *iovp = &dep->de_write_iovec;
int r, bytes, ix = 0;
/* Sets up board for writing */
ns_rw_setup(dep, CR_DM_RW, pktsize, pageno * DP_PAGESIZE);
@ -238,8 +264,10 @@ static void pio_user2nic(dpeth_t *dep, int pageno, int pktsize)
bytes = iovp->iod_iovec[ix].iov_size; /* Size of chunck */
if (bytes > pktsize) bytes = pktsize;
outsb(dep->de_data_port, iovp->iod_proc_nr,
(void*)(iovp->iod_iovec[ix].iov_addr), bytes);
r= sys_safe_outsb(dep->de_data_port, iovp->iod_proc_nr,
iovp->iod_iovec[ix].iov_grant, 0, bytes);
if (r != OK)
panic(__FILE__, "pio_user2nic: sys_safe_outsb failed", r);
if (++ix >= IOVEC_NR) { /* Next buffer of I/O vector */
dp_next_iovec(iovp);

View file

@ -2,6 +2,9 @@
## Makefile for ISA ethernet drivers May 02, 2000
##
## $Log$
## Revision 1.4 2006/07/10 12:43:38 philip
## Safecopy support in ethernet drivers.
##
## Revision 1.3 2005/07/19 13:21:48 jnherder
## Renamed src/lib/utils to src/lib/sysutil --- because of new src/lib/util
##
@ -26,7 +29,7 @@ debug = 0
CC = exec cc
LD = $(CC)
CPPFLAGS= -I.. -I/usr/include -Ddebug=$(debug)
CFLAGS = -ws $(CPPFLAGS)
CFLAGS = $(CPPFLAGS)
LDFLAGS = -i -o $@
SRCS = 3c501.c 3c509.c 3c503.c ne.c wd.c 8390.c devio.c netbuff.c dp.c

View file

@ -29,7 +29,7 @@ static void warning(const char *type, int err)
*/
PUBLIC unsigned int inb(unsigned short port)
{
unsigned int value;
unsigned long value;
int rc;
if ((rc = sys_inb(port, &value)) != OK) warning("inb", rc);
@ -42,7 +42,7 @@ PUBLIC unsigned int inb(unsigned short port)
*/
PUBLIC unsigned int inw(unsigned short port)
{
unsigned int value;
unsigned long value;
int rc;
if ((rc = sys_inw(port, &value)) != OK) warning("inw", rc);

View file

@ -1,3 +1,4 @@
#include <assert.h>
/*
** File: eth.c Version 1.00, Jan. 14, 1997
**
@ -29,7 +30,7 @@
** +------------+---------+---------+--------+-------+---------+
** | DL_READV | port nr | proc nr | count | | address | (6)
** +------------+---------+---------+--------+-------+---------+
** | DL_INIT | port nr | proc nr | | mode | address | (7)
** | DL_CONF | port nr | proc nr | | mode | address | (7)
** +------------+---------+---------+--------+-------+---------+
** | DL_STOP | port_nr | | | | | (8)
** +------------+---------+---------+--------+-------+---------+
@ -45,7 +46,7 @@
**
** m_type m3_i1 m3_i2 m3_ca1
** +------------+---------+---------+---------------+
** |DL_INIT_REPL| port nr |last port| ethernet addr | (20)
** |DL_CONF_REPL| port nr |last port| ethernet addr | (20)
** +------------+---------+---------+---------------+
**
** $Id$
@ -80,13 +81,13 @@ static dp_conf_t dp_conf[DE_PORT_NR] = {
{ 0x280, 10, 0xCC000, "DPETH1", },
};
static const char CopyErrMsg[] = "unable to read/write user data";
static const char PortErrMsg[] = "illegal port";
static const char RecvErrMsg[] = "receive failed";
static const char SendErrMsg[] = "send failed";
static const char SizeErrMsg[] = "illegal packet size";
static const char TypeErrMsg[] = "illegal message type";
static const char DevName[] = "eth#?";
static char CopyErrMsg[] = "unable to read/write user data";
static char PortErrMsg[] = "illegal port";
static char RecvErrMsg[] = "receive failed";
static char SendErrMsg[] = "send failed";
static char SizeErrMsg[] = "illegal packet size";
static char TypeErrMsg[] = "illegal message type";
static char DevName[] = "eth#?";
static void do_getname(message *mp);
@ -223,16 +224,17 @@ static void do_dump(message *mp)
}
/*
** Name: void get_userdata(int user_proc, vir_bytes user_addr, int count, void *loc_addr)
** Name: void get_userdata_s(int user_proc, vir_bytes user_addr, int count, void *loc_addr)
** Function: Copies data from user area.
*/
static void get_userdata(int user_proc, vir_bytes user_addr, int count, void *loc_addr)
static void get_userdata_s(int user_proc, cp_grant_id_t grant,
vir_bytes offset, int count, void *loc_addr)
{
int rc;
vir_bytes len;
len = (count > IOVEC_NR ? IOVEC_NR : count) * sizeof(iovec_t);
if ((rc = sys_datacopy(user_proc, user_addr, SELF, (vir_bytes)loc_addr, len)) != OK)
if ((rc = sys_safecopyfrom(user_proc, grant, 0, (vir_bytes)loc_addr, len, D)) != OK)
panic(DevName, CopyErrMsg, rc);
return;
}
@ -339,7 +341,7 @@ static void do_init(message * mp)
} else /* Port number is out of range */
port = ENXIO;
reply_mess.m_type = DL_INIT_REPLY;
reply_mess.m_type = DL_CONF_REPLY;
reply_mess.m3_i1 = port;
reply_mess.m3_i2 = DE_PORT_NR;
DEBUG(printf("\t reply %d\n", reply_mess.m_type));
@ -353,12 +355,12 @@ static void do_init(message * mp)
** Name: void dp_next_iovec(iovec_dat_t *iovp)
** Function: Retrieves data from next iovec element.
*/
PUBLIC void dp_next_iovec(iovec_dat_t * iovp)
PUBLIC void dp_next_iovec(iovec_dat_s_t * iovp)
{
iovp->iod_iovec_s -= IOVEC_NR;
iovp->iod_iovec_addr += IOVEC_NR * sizeof(iovec_t);
get_userdata(iovp->iod_proc_nr, iovp->iod_iovec_addr,
iovp->iod_iovec_offset += IOVEC_NR * sizeof(iovec_t);
get_userdata_s(iovp->iod_proc_nr, iovp->iod_grant, iovp->iod_iovec_offset,
iovp->iod_iovec_s, iovp->iod_iovec);
return;
}
@ -367,7 +369,7 @@ PUBLIC void dp_next_iovec(iovec_dat_t * iovp)
** Name: int calc_iovec_size(iovec_dat_t *iovp)
** Function: Compute the size of a request.
*/
static int calc_iovec_size(iovec_dat_t * iovp)
static int calc_iovec_size(iovec_dat_s_t * iovp)
{
int size, ix;
@ -385,10 +387,10 @@ static int calc_iovec_size(iovec_dat_t * iovp)
}
/*
** Name: void do_vwrite(message *mp, int vectored)
** Name: void do_vwrite_s(message *mp, int vectored)
** Function:
*/
static void do_vwrite(message * mp, int vectored)
static void do_vwrite_s(message * mp)
{
int port, size;
dpeth_t *dep;
@ -406,18 +408,12 @@ static void do_vwrite(message * mp, int vectored)
panic(dep->de_name, "send already in progress ", NO_NUM);
dep->de_write_iovec.iod_proc_nr = mp->DL_PROC;
if (vectored) {
get_userdata(mp->DL_PROC, (vir_bytes) mp->DL_ADDR,
mp->DL_COUNT, dep->de_write_iovec.iod_iovec);
dep->de_write_iovec.iod_iovec_s = mp->DL_COUNT;
dep->de_write_iovec.iod_iovec_addr = (vir_bytes) mp->DL_ADDR;
size = calc_iovec_size(&dep->de_write_iovec);
} else {
dep->de_write_iovec.iod_iovec[0].iov_addr = (vir_bytes) mp->DL_ADDR;
dep->de_write_iovec.iod_iovec[0].iov_size = size = mp->DL_COUNT;
dep->de_write_iovec.iod_iovec_s = 1;
dep->de_write_iovec.iod_iovec_addr = 0;
}
get_userdata_s(mp->DL_PROC, mp->DL_GRANT, 0,
mp->DL_COUNT, dep->de_write_iovec.iod_iovec);
dep->de_write_iovec.iod_iovec_s = mp->DL_COUNT;
dep->de_write_iovec.iod_grant = (vir_bytes) mp->DL_GRANT;
dep->de_write_iovec.iod_iovec_offset = 0;
size = calc_iovec_size(&dep->de_write_iovec);
if (size < ETH_MIN_PACK_SIZE || size > ETH_MAX_PACK_SIZE)
panic(dep->de_name, SizeErrMsg, size);
@ -432,10 +428,10 @@ static void do_vwrite(message * mp, int vectored)
}
/*
** Name: void do_vread(message *mp, int vectored)
** Name: void do_vread_s(message *mp, int vectored)
** Function:
*/
static void do_vread(message * mp, int vectored)
static void do_vread_s(message * mp)
{
int port, size;
dpeth_t *dep;
@ -453,18 +449,12 @@ static void do_vread(message * mp, int vectored)
panic(dep->de_name, "read already in progress", NO_NUM);
dep->de_read_iovec.iod_proc_nr = mp->DL_PROC;
if (vectored) {
get_userdata(mp->DL_PROC, (vir_bytes) mp->DL_ADDR,
mp->DL_COUNT, dep->de_read_iovec.iod_iovec);
dep->de_read_iovec.iod_iovec_s = mp->DL_COUNT;
dep->de_read_iovec.iod_iovec_addr = (vir_bytes) mp->DL_ADDR;
size = calc_iovec_size(&dep->de_read_iovec);
} else {
dep->de_read_iovec.iod_iovec[0].iov_addr = (vir_bytes) mp->DL_ADDR;
dep->de_read_iovec.iod_iovec[0].iov_size = size = mp->DL_COUNT;
dep->de_read_iovec.iod_iovec_s = 1;
dep->de_read_iovec.iod_iovec_addr = 0;
}
get_userdata_s(mp->DL_PROC, (vir_bytes) mp->DL_GRANT, 0,
mp->DL_COUNT, dep->de_read_iovec.iod_iovec);
dep->de_read_iovec.iod_iovec_s = mp->DL_COUNT;
dep->de_read_iovec.iod_grant = (vir_bytes) mp->DL_GRANT;
dep->de_read_iovec.iod_iovec_offset = 0;
size = calc_iovec_size(&dep->de_read_iovec);
if (size < ETH_MAX_PACK_SIZE) panic(dep->de_name, SizeErrMsg, size);
dep->de_flags |= DEF_READING;
@ -481,10 +471,10 @@ static void do_vread(message * mp, int vectored)
}
/*
** Name: void do_getstat(message *mp)
** Name: void do_getstat_s(message *mp)
** Function: Reports device statistics.
*/
static void do_getstat(message * mp)
static void do_getstat_s(message * mp)
{
int port, rc;
dpeth_t *dep;
@ -497,9 +487,9 @@ static void do_getstat(message * mp)
dep->de_client = mp->DL_PROC;
if (dep->de_mode == DEM_ENABLED) (*dep->de_getstatsf) (dep);
if ((rc = sys_datacopy(SELF, (vir_bytes)&dep->de_stat,
mp->DL_PROC, (vir_bytes)mp->DL_ADDR,
(vir_bytes) sizeof(dep->de_stat))) != OK)
if ((rc = sys_safecopyto(mp->DL_PROC, mp->DL_GRANT, 0,
(vir_bytes)&dep->de_stat,
(vir_bytes) sizeof(dep->de_stat), 0)) != OK)
panic(DevName, CopyErrMsg, rc);
reply(dep, OK);
return;
@ -592,23 +582,17 @@ PUBLIC int main(int argc, char **argv)
case DEV_PING: /* Status request from RS */
notify(m.m_source);
continue;
case DL_WRITE: /* Write message to device */
do_vwrite(&m, FALSE);
case DL_WRITEV_S: /* Write message to device */
do_vwrite_s(&m);
break;
case DL_WRITEV: /* Write message to device */
do_vwrite(&m, TRUE);
case DL_READV_S: /* Read message from device */
do_vread_s(&m);
break;
case DL_READ: /* Read message from device */
do_vread(&m, FALSE);
break;
case DL_READV: /* Read message from device */
do_vread(&m, TRUE);
break;
case DL_INIT: /* Initialize device */
case DL_CONF: /* Initialize device */
do_init(&m);
break;
case DL_GETSTAT: /* Get device statistics */
do_getstat(&m);
case DL_GETSTAT_S: /* Get device statistics */
do_getstat_s(&m);
break;
case DL_GETNAME:
do_getname(&m);

View file

@ -6,6 +6,9 @@
** Interface description for ethernet device driver
**
** $Log$
** Revision 1.5 2006/07/10 12:43:38 philip
** Safecopy support in ethernet drivers.
**
** Revision 1.4 2005/09/04 18:52:16 beng
** Giovanni's fixes to dpeth:
** Date: Sat, 03 Sep 2005 11:05:22 +0200
@ -83,12 +86,13 @@ typedef void (*dp_getblock_t) (struct dpeth *, u16_t, int, void *);
#define SENDQ_NR 2 /* Size of the send queue */
#define IOVEC_NR 16 /* Number of IOVEC entries at a time */
typedef struct iovec_dat {
iovec_t iod_iovec[IOVEC_NR];
typedef struct iovec_dat_s {
iovec_s_t iod_iovec[IOVEC_NR];
int iod_iovec_s;
int iod_proc_nr;
vir_bytes iod_iovec_addr;
} iovec_dat_t;
cp_grant_id_t iod_grant;
vir_bytes iod_iovec_offset;
} iovec_dat_s_t;
typedef struct dpeth {
/* The de_base_port field is the starting point of the probe. The
@ -161,8 +165,8 @@ typedef struct dpeth {
#define DEM_ENABLED 0x0002
/* Temporary storage for RECV/SEND requests */
iovec_dat_t de_read_iovec;
iovec_dat_t de_write_iovec;
iovec_dat_s_t de_read_iovec;
iovec_dat_s_t de_write_iovec;
vir_bytes de_read_s;
vir_bytes de_send_s;
int de_client;
@ -216,7 +220,7 @@ typedef struct dpeth {
*/
/* dp.c */
void dp_next_iovec(iovec_dat_t * iovp);
void dp_next_iovec(iovec_dat_s_t * iovp);
/* devio.c */
#if defined USE_IOPL

View file

@ -111,8 +111,8 @@ PUBLIC void mem2user(dpeth_t *dep, buff_t *rxbuff)
{
phys_bytes phys_user;
int bytes, ix = 0;
iovec_dat_t *iovp = &dep->de_read_iovec;
int pktsize = rxbuff->size;
iovec_dat_s_t *iovp = &dep->de_read_iovec;
int r, pktsize = rxbuff->size;
char *buffer = rxbuff->buffer;
do { /* Reads chuncks of packet into user buffers */
@ -121,8 +121,10 @@ PUBLIC void mem2user(dpeth_t *dep, buff_t *rxbuff)
if (bytes > pktsize) bytes = pktsize;
/* Reads from Rx buffer to user area */
sys_datacopy(SELF, (vir_bytes)buffer, iovp->iod_proc_nr,
iovp->iod_iovec[ix].iov_addr, bytes);
r= sys_safecopyto(iovp->iod_proc_nr, iovp->iod_iovec[ix].iov_grant, 0,
(vir_bytes)buffer, bytes, D);
if (r != OK)
panic(__FILE__, "mem2user: sys_safecopyto failed", r);
buffer += bytes;
if (++ix >= IOVEC_NR) { /* Next buffer of IO vector */
@ -142,16 +144,18 @@ PUBLIC void user2mem(dpeth_t *dep, buff_t *txbuff)
{
phys_bytes phys_user;
int bytes, ix = 0;
iovec_dat_t *iovp = &dep->de_write_iovec;
int pktsize = txbuff->size;
iovec_dat_s_t *iovp = &dep->de_write_iovec;
int r, pktsize = txbuff->size;
char *buffer = txbuff->buffer;
do { /* Reads chuncks of packet from user buffers */
bytes = iovp->iod_iovec[ix].iov_size; /* Size of buffer */
if (bytes > pktsize) bytes = pktsize;
sys_datacopy(iovp->iod_proc_nr, iovp->iod_iovec[ix].iov_addr,
SELF, (vir_bytes)buffer, bytes);
r= sys_safecopyfrom(iovp->iod_proc_nr, iovp->iod_iovec[ix].iov_grant,
0, (vir_bytes)buffer, bytes, D);
if (r != OK)
panic(__FILE__, "user2mem: sys_safecopyfrom failed", r);
buffer += bytes;
if (++ix >= IOVEC_NR) { /* Next buffer of IO vector */

View file

@ -21,7 +21,7 @@ OBJ = fxp.o mii.o
all build: $(DRIVER)
$(DRIVER): $(OBJ)
$(CC) -o $@ $(LDFLAGS) $(OBJ) $(LIBS)
install -S 4096 $(DRIVER)
install -S 8k $(DRIVER)
# install with other drivers
install: /usr/sbin/$(DRIVER)

View file

@ -6,24 +6,30 @@
*
* The valid messages and their parameters are:
*
* m_type DL_PORT DL_PROC DL_COUNT DL_MODE DL_ADDR
* |------------+----------+---------+----------+---------+---------|
* | HARDINT | | | | | |
* |------------|----------|---------|----------|---------|---------|
* | DL_WRITE | port nr | proc nr | count | mode | address |
* |------------|----------|---------|----------|---------|---------|
* | DL_WRITEV | port nr | proc nr | count | mode | address |
* |------------|----------|---------|----------|---------|---------|
* | DL_READ | port nr | proc nr | count | | address |
* |------------|----------|---------|----------|---------|---------|
* | DL_READV | port nr | proc nr | count | | address |
* |------------|----------|---------|----------|---------|---------|
* | DL_INIT | port nr | proc nr | mode | | address |
* |------------|----------|---------|----------|---------|---------|
* | DL_GETSTAT | port nr | proc nr | | | address |
* |------------|----------|---------|----------|---------|---------|
* | DL_STOP | port_nr | | | | |
* |------------|----------|---------|----------|---------|---------|
* m_type DL_PORT DL_PROC DL_COUNT DL_MODE DL_ADDR DL_GRANT
* |------------+----------+---------+----------+---------+---------+---------|
* | HARDINT | | | | | | |
* |------------|----------|---------|----------|---------|---------|---------|
* | DL_WRITE | port nr | proc nr | count | mode | address | |
* |------------|----------|---------|----------|---------|---------|---------|
* | DL_WRITEV | port nr | proc nr | count | mode | address | |
* |------------|----------|---------|----------|---------|---------|---------|
* | DL_WRITEV_S| port nr | proc nr | count | mode | | grant |
* |------------|----------|---------|----------|---------|---------|---------|
* | DL_READ | port nr | proc nr | count | | address | |
* |------------|----------|---------|----------|---------|---------|---------|
* | DL_READV | port nr | proc nr | count | | address | |
* |------------|----------|---------|----------|---------|---------|---------|
* | DL_READV_S | port nr | proc nr | count | | | grant |
* |------------|----------|---------|----------|---------|---------|---------|
* | DL_CONF | port nr | proc nr | | mode | address | |
* |------------|----------|---------|----------|---------|---------|---------|
* | DL_GETSTAT | port nr | proc nr | | | address | |
* |------------|----------|---------|----------|---------|---------|---------|
* |DL_GETSTAT_S| port nr | proc nr | | | | grant |
* |------------|----------|---------|----------|---------|---------|---------|
* | DL_STOP | port_nr | | | | | |
* |------------|----------|---------|----------|---------|---------|---------|
*
* The messages sent are:
*
@ -34,7 +40,7 @@
*
* m_type m3_i1 m3_i2 m3_ca1
* |-------------+---------+-----------+---------------|
* |DL_INIT_REPLY| port nr | last port | ethernet addr |
* |DL_CONF_REPLY| port nr | last port | ethernet addr |
* |-------------+---------+-----------+---------------|
*
* Created: Nov 2004 by Philip Homburg <philip@f-mnx.phicoh.com>
@ -169,6 +175,7 @@ typedef struct fxp
u8_t fxp_conf_bytes[CC_BYTES_NR];
char fxp_name[sizeof("fxp#n")];
iovec_t fxp_iovec[IOVEC_NR];
iovec_s_t fxp_iovec_s[IOVEC_NR];
}
fxp_t;
@ -223,8 +230,10 @@ _PROTOTYPE( static void fxp_confaddr, (fxp_t *fp) );
_PROTOTYPE( static void fxp_rec_mode, (fxp_t *fp) );
_PROTOTYPE( static void fxp_writev, (message *mp, int from_int,
int vectored) );
_PROTOTYPE( static void fxp_writev_s, (message *mp, int from_int) );
_PROTOTYPE( static void fxp_readv, (message *mp, int from_int,
int vectored) );
_PROTOTYPE( static void fxp_readv_s, (message *mp, int from_int) );
_PROTOTYPE( static void fxp_do_conf, (fxp_t *fp) );
_PROTOTYPE( static void fxp_cu_ptr_cmd, (fxp_t *fp, int cmd,
phys_bytes bus_addr, int check_idle) );
@ -232,6 +241,7 @@ _PROTOTYPE( static void fxp_ru_ptr_cmd, (fxp_t *fp, int cmd,
phys_bytes bus_addr, int check_idle) );
_PROTOTYPE( static void fxp_restart_ru, (fxp_t *fp) );
_PROTOTYPE( static void fxp_getstat, (message *mp) );
_PROTOTYPE( static void fxp_getstat_s, (message *mp) );
_PROTOTYPE( static void fxp_getname, (message *mp) );
_PROTOTYPE( static int fxp_handler, (fxp_t *fp) );
_PROTOTYPE( static void fxp_check_ints, (fxp_t *fp) );
@ -241,8 +251,6 @@ _PROTOTYPE( static void fxp_report_link, (fxp_t *fp) );
_PROTOTYPE( static void fxp_stop, (void));
_PROTOTYPE( static void reply, (fxp_t *fp, int err, int may_block) );
_PROTOTYPE( static void mess_reply, (message *req, message *reply) );
_PROTOTYPE( static void put_userdata, (int user_proc,
vir_bytes user_addr, vir_bytes count, void *loc_addr) );
_PROTOTYPE( static u16_t eeprom_read, (fxp_t *fp, int reg) );
_PROTOTYPE( static void eeprom_addrsize, (fxp_t *fp) );
_PROTOTYPE( static u16_t mii_read, (fxp_t *fp, int reg) );
@ -298,12 +306,13 @@ int main(int argc, char *argv[])
case DEV_PING: notify(m.m_source); continue;
case DL_WRITEV: fxp_writev(&m, FALSE, TRUE); break;
case DL_WRITE: fxp_writev(&m, FALSE, FALSE); break;
#if 0
case DL_READ: fxp_vread(&m, FALSE); break;
#endif
case DL_WRITEV_S: fxp_writev_s(&m, FALSE); break;
case DL_READ: fxp_readv(&m, FALSE, FALSE); break;
case DL_READV: fxp_readv(&m, FALSE, TRUE); break;
case DL_INIT: fxp_init(&m); break;
case DL_READV_S: fxp_readv_s(&m, FALSE); break;
case DL_CONF: fxp_init(&m); break;
case DL_GETSTAT: fxp_getstat(&m); break;
case DL_GETSTAT_S: fxp_getstat_s(&m); break;
case DL_GETNAME: fxp_getname(&m); break;
case HARD_INT:
for (i= 0, fp= &fxp_table[0]; i<FXP_PORT_NR; i++, fp++)
@ -361,7 +370,7 @@ message *mp;
port = mp->DL_PORT;
if (port < 0 || port >= FXP_PORT_NR)
{
reply_mess.m_type= DL_INIT_REPLY;
reply_mess.m_type= DL_CONF_REPLY;
reply_mess.m3_i1= ENXIO;
mess_reply(mp, &reply_mess);
return;
@ -374,7 +383,7 @@ message *mp;
if (fp->fxp_mode == FM_DISABLED)
{
/* Probe failed, or the device is configured off. */
reply_mess.m_type= DL_INIT_REPLY;
reply_mess.m_type= DL_CONF_REPLY;
reply_mess.m3_i1= ENXIO;
mess_reply(mp, &reply_mess);
return;
@ -399,7 +408,7 @@ message *mp;
fp->fxp_client = mp->m_source;
fxp_rec_mode(fp);
reply_mess.m_type = DL_INIT_REPLY;
reply_mess.m_type = DL_CONF_REPLY;
reply_mess.m3_i1 = mp->DL_PORT;
reply_mess.m3_i2 = FXP_PORT_NR;
*(ether_addr_t *) reply_mess.m3_ca1 = fp->fxp_address;
@ -1194,6 +1203,152 @@ suspend:
reply(fp, OK, FALSE);
}
/*===========================================================================*
* fxp_writev_s *
*===========================================================================*/
static void fxp_writev_s(mp, from_int)
message *mp;
int from_int;
{
cp_grant_id_t iov_grant;
vir_bytes iov_offset;
int i, j, n, o, r, s, dl_port, count, size, prev_head;
int fxp_client, fxp_tx_nbuf, fxp_tx_head;
u16_t tx_command;
fxp_t *fp;
iovec_s_t *iovp;
struct tx *txp, *prev_txp;
dl_port = mp->DL_PORT;
count = mp->DL_COUNT;
if (dl_port < 0 || dl_port >= FXP_PORT_NR)
panic("FXP","fxp_writev: illegal port", dl_port);
fp= &fxp_table[dl_port];
fxp_client= mp->DL_PROC;
fp->fxp_client= fxp_client;
assert(fp->fxp_mode == FM_ENABLED);
assert(fp->fxp_flags & FF_ENABLED);
if (from_int)
{
assert(fp->fxp_flags & FF_SEND_AVAIL);
fp->fxp_flags &= ~FF_SEND_AVAIL;
fp->fxp_tx_alive= TRUE;
}
if (fp->fxp_tx_idle)
{
txp= fp->fxp_tx_buf;
fxp_tx_head= 0; /* lint */
prev_txp= NULL; /* lint */
}
else
{
fxp_tx_nbuf= fp->fxp_tx_nbuf;
prev_head= fp->fxp_tx_head;
fxp_tx_head= prev_head+1;
if (fxp_tx_head == fxp_tx_nbuf)
fxp_tx_head= 0;
assert(fxp_tx_head < fxp_tx_nbuf);
if (fxp_tx_head == fp->fxp_tx_tail)
{
/* Send queue is full */
assert(!(fp->fxp_flags & FF_SEND_AVAIL));
fp->fxp_flags |= FF_SEND_AVAIL;
goto suspend;
}
prev_txp= &fp->fxp_tx_buf[prev_head];
txp= &fp->fxp_tx_buf[fxp_tx_head];
}
assert(!(fp->fxp_flags & FF_SEND_AVAIL));
assert(!(fp->fxp_flags & FF_PACK_SENT));
iov_grant= mp->DL_GRANT;
size= 0;
o= 0;
iov_offset= 0;
for (i= 0; i<count; i += IOVEC_NR,
iov_offset += IOVEC_NR * sizeof(fp->fxp_iovec_s[0]))
{
n= IOVEC_NR;
if (i+n > count)
n= count-i;
r= sys_safecopyfrom(fxp_client, iov_grant, iov_offset,
(vir_bytes)fp->fxp_iovec_s,
n * sizeof(fp->fxp_iovec_s[0]), D);
if (r != OK)
panic("FXP","fxp_writev: sys_safecopyfrom failed", r);
for (j= 0, iovp= fp->fxp_iovec_s; j<n; j++, iovp++)
{
s= iovp->iov_size;
if (size + s > ETH_MAX_PACK_SIZE_TAGGED)
{
panic("FXP","fxp_writev: invalid packet size",
size + s);
}
r= sys_safecopyfrom(fxp_client, iovp->iov_grant,
0, (vir_bytes)(txp->tx_buf+o), s, D);
if (r != OK)
{
panic("FXP",
"fxp_writev_s: sys_safecopyfrom failed",
r);
}
size += s;
o += s;
}
}
if (size < ETH_MIN_PACK_SIZE)
panic("FXP","fxp_writev: invalid packet size", size);
txp->tx_status= 0;
txp->tx_command= TXC_EL | CBL_XMIT;
txp->tx_tbda= TX_TBDA_NIL;
txp->tx_size= TXSZ_EOF | size;
txp->tx_tthresh= fp->fxp_tx_threshold;
txp->tx_ntbd= 0;
if (fp->fxp_tx_idle)
{
fp->fxp_tx_idle= 0;
fp->fxp_tx_head= fp->fxp_tx_tail= 0;
fxp_cu_ptr_cmd(fp, SC_CU_START, fp->fxp_tx_busaddr,
TRUE /* check idle */);
}
else
{
/* Link new request in transmit list */
tx_command= prev_txp->tx_command;
assert(tx_command == (TXC_EL | CBL_XMIT));
prev_txp->tx_command= CBL_XMIT;
fp->fxp_tx_head= fxp_tx_head;
}
fp->fxp_flags |= FF_PACK_SENT;
/* If the interrupt handler called, don't send a reply. The reply
* will be sent after all interrupts are handled.
*/
if (from_int)
return;
reply(fp, OK, FALSE);
return;
suspend:
if (from_int)
panic("FXP","fxp: should not be sending\n", NO_NUM);
fp->fxp_tx_mess= *mp;
reply(fp, OK, FALSE);
}
/*===========================================================================*
* fxp_readv *
*===========================================================================*/
@ -1374,6 +1529,179 @@ suspend:
reply(fp, OK, FALSE);
}
/*===========================================================================*
* fxp_readv_s *
*===========================================================================*/
static void fxp_readv_s(mp, from_int)
message *mp;
int from_int;
{
int i, j, n, o, r, s, dl_port, fxp_client, count, size,
fxp_rx_head, fxp_rx_nbuf;
cp_grant_id_t iov_grant;
port_t port;
unsigned packlen;
vir_bytes iov_offset;
u16_t rfd_status;
u16_t rfd_res;
u8_t scb_status;
fxp_t *fp;
iovec_s_t *iovp;
struct rfd *rfdp, *prev_rfdp;
dl_port = mp->DL_PORT;
count = mp->DL_COUNT;
if (dl_port < 0 || dl_port >= FXP_PORT_NR)
panic("FXP","fxp_readv: illegal port", dl_port);
fp= &fxp_table[dl_port];
fxp_client= mp->DL_PROC;
fp->fxp_client= fxp_client;
assert(fp->fxp_mode == FM_ENABLED);
assert(fp->fxp_flags & FF_ENABLED);
port= fp->fxp_base_port;
fxp_rx_head= fp->fxp_rx_head;
rfdp= &fp->fxp_rx_buf[fxp_rx_head];
rfd_status= rfdp->rfd_status;
if (!(rfd_status & RFDS_C))
{
/* Receive buffer is empty, suspend */
goto suspend;
}
if (!rfd_status & RFDS_OK)
{
/* Not OK? What happened? */
assert(0);
}
else
{
assert(!(rfd_status & (RFDS_CRCERR | RFDS_ALIGNERR |
RFDS_OUTOFBUF | RFDS_DMAOVR | RFDS_TOOSHORT |
RFDS_RXERR)));
}
rfd_res= rfdp->rfd_res;
assert(rfd_res & RFDR_EOF);
assert(rfd_res & RFDR_F);
packlen= rfd_res & RFDSZ_SIZE;
iov_grant = mp->DL_GRANT;
size= 0;
o= 0;
iov_offset= 0;
for (i= 0; i<count; i += IOVEC_NR,
iov_offset += IOVEC_NR * sizeof(fp->fxp_iovec_s[0]))
{
n= IOVEC_NR;
if (i+n > count)
n= count-i;
r= sys_safecopyfrom(fxp_client, iov_grant, iov_offset,
(vir_bytes)fp->fxp_iovec_s,
n * sizeof(fp->fxp_iovec_s[0]), D);
if (r != OK)
panic("FXP","fxp_readv_s: sys_safecopyfrom failed", r);
for (j= 0, iovp= fp->fxp_iovec_s; j<n; j++, iovp++)
{
s= iovp->iov_size;
if (size + s > packlen)
{
assert(packlen > size);
s= packlen-size;
}
r= sys_safecopyto(fxp_client, iovp->iov_grant,
0, (vir_bytes)(rfdp->rfd_buf+o), s, D);
if (r != OK)
{
panic("FXP","fxp_readv: sys_safecopyto failed",
r);
}
size += s;
if (size == packlen)
break;
o += s;
}
if (size == packlen)
break;
}
if (size < packlen)
{
assert(0);
}
fp->fxp_read_s= packlen;
fp->fxp_flags= (fp->fxp_flags & ~FF_READING) | FF_PACK_RECV;
/* Re-init the current buffer */
rfdp->rfd_status= 0;
rfdp->rfd_command= RFDC_EL;
rfdp->rfd_reserved= 0;
rfdp->rfd_res= 0;
rfdp->rfd_size= sizeof(rfdp->rfd_buf);
fxp_rx_nbuf= fp->fxp_rx_nbuf;
if (fxp_rx_head == 0)
{
prev_rfdp= &fp->fxp_rx_buf[fxp_rx_nbuf-1];
}
else
prev_rfdp= &rfdp[-1];
assert(prev_rfdp->rfd_command & RFDC_EL);
prev_rfdp->rfd_command &= ~RFDC_EL;
fxp_rx_head++;
if (fxp_rx_head == fxp_rx_nbuf)
fxp_rx_head= 0;
assert(fxp_rx_head < fxp_rx_nbuf);
fp->fxp_rx_head= fxp_rx_head;
if (!from_int)
reply(fp, OK, FALSE);
return;
suspend:
if (fp->fxp_rx_need_restart)
{
fp->fxp_rx_need_restart= 0;
/* Check the status of the RU */
scb_status= fxp_inb(port, SCB_STATUS);
if ((scb_status & SS_RUS_MASK) != SS_RU_NORES)
{
/* Race condition? */
printf("fxp_readv: restart race: 0x%x\n",
scb_status);
assert((scb_status & SS_RUS_MASK) == SS_RU_READY);
}
else
{
fxp_restart_ru(fp);
}
}
if (from_int)
{
assert(fp->fxp_flags & FF_READING);
/* No need to store any state */
return;
}
fp->fxp_rx_mess= *mp;
assert(!(fp->fxp_flags & FF_READING));
fp->fxp_flags |= FF_READING;
reply(fp, OK, FALSE);
}
/*===========================================================================*
* fxp_do_conf *
*===========================================================================*/
@ -1529,7 +1857,7 @@ static void fxp_getstat(mp)
message *mp;
{
clock_t t0,t1;
int dl_port;
int r, dl_port;
port_t port;
fxp_t *fp;
u32_t *p;
@ -1592,8 +1920,88 @@ message *mp;
stats.ets_CDheartbeat= 0;
stats.ets_OWC= fp->fxp_stat.sc_tx_latecol;
put_userdata(mp->DL_PROC, (vir_bytes) mp->DL_ADDR,
(vir_bytes) sizeof(stats), &stats);
r= sys_vircopy(SELF, D, (vir_bytes)&stats,
mp->DL_PROC, D, (vir_bytes) mp->DL_ADDR, sizeof(stats));
if (r != OK)
panic(__FILE__,"fxp_getstat: sys_vircopy failed", r);
reply(fp, OK, FALSE);
}
/*===========================================================================*
* fxp_getstat_s *
*===========================================================================*/
static void fxp_getstat_s(mp)
message *mp;
{
clock_t t0,t1;
int r, dl_port;
port_t port;
fxp_t *fp;
u32_t *p;
eth_stat_t stats;
dl_port = mp->DL_PORT;
if (dl_port < 0 || dl_port >= FXP_PORT_NR)
panic("FXP","fxp_getstat: illegal port", dl_port);
fp= &fxp_table[dl_port];
fp->fxp_client= mp->DL_PROC;
assert(fp->fxp_mode == FM_ENABLED);
assert(fp->fxp_flags & FF_ENABLED);
port= fp->fxp_base_port;
p= &fp->fxp_stat.sc_tx_fcp;
*p= 0;
/* The dump commmand doesn't take a pointer. Setting a pointer
* doesn't hurt though.
*/
fxp_cu_ptr_cmd(fp, SC_CU_DUMP_SC, 0, FALSE /* do not check idle */);
getuptime(&t0);
do {
/* Wait for CU command to complete */
if (*p != 0)
break;
} while (getuptime(&t1)==OK && (t1-t0) < MICROS_TO_TICKS(1000));
if (*p == 0)
panic("FXP","fxp_getstat: CU command failed to complete", NO_NUM);
if (*p != SCM_DSC)
panic("FXP","fxp_getstat: bad magic", NO_NUM);
stats.ets_recvErr=
fp->fxp_stat.sc_rx_crc +
fp->fxp_stat.sc_rx_align +
fp->fxp_stat.sc_rx_resource +
fp->fxp_stat.sc_rx_overrun +
fp->fxp_stat.sc_rx_cd +
fp->fxp_stat.sc_rx_short;
stats.ets_sendErr=
fp->fxp_stat.sc_tx_maxcol +
fp->fxp_stat.sc_tx_latecol +
fp->fxp_stat.sc_tx_crs;
stats.ets_OVW= fp->fxp_stat.sc_rx_overrun;
stats.ets_CRCerr= fp->fxp_stat.sc_rx_crc;
stats.ets_frameAll= fp->fxp_stat.sc_rx_align;
stats.ets_missedP= fp->fxp_stat.sc_rx_resource;
stats.ets_packetR= fp->fxp_stat.sc_rx_good;
stats.ets_packetT= fp->fxp_stat.sc_tx_good;
stats.ets_transDef= fp->fxp_stat.sc_tx_defered;
stats.ets_collision= fp->fxp_stat.sc_tx_totcol;
stats.ets_transAb= fp->fxp_stat.sc_tx_maxcol;
stats.ets_carrSense= fp->fxp_stat.sc_tx_crs;
stats.ets_fifoUnder= fp->fxp_stat.sc_tx_underrun;
stats.ets_fifoOver= fp->fxp_stat.sc_rx_overrun;
stats.ets_CDheartbeat= 0;
stats.ets_OWC= fp->fxp_stat.sc_tx_latecol;
r= sys_safecopyto(mp->DL_PROC, mp->DL_GRANT, 0, (vir_bytes)&stats,
sizeof(stats), D);
if (r != OK)
panic(__FILE__,"fxp_getstat_s: sys_safecopyto failed", r);
reply(fp, OK, FALSE);
}
@ -1697,6 +2105,11 @@ fxp_t *fp;
fxp_readv(&fp->fxp_rx_mess, TRUE /* from int */,
TRUE /* vectored */);
}
else if (fp->fxp_rx_mess.m_type == DL_READV_S)
{
fxp_readv_s(&fp->fxp_rx_mess, TRUE /* from int */);
}
else
{
assert(fp->fxp_rx_mess.m_type == DL_READ);
@ -1803,6 +2216,11 @@ fxp_t *fp;
TRUE /* from int */,
TRUE /* vectored */);
}
else if (fp->fxp_tx_mess.m_type == DL_WRITEV_S)
{
fxp_writev_s(&fp->fxp_tx_mess,
TRUE /* from int */);
}
else
{
assert(fp->fxp_tx_mess.m_type ==
@ -2212,23 +2630,6 @@ message *reply_mess;
panic("FXP","fxp: unable to mess_reply", NO_NUM);
}
/*===========================================================================*
* put_userdata *
*===========================================================================*/
static void put_userdata(user_proc, user_addr, count, loc_addr)
int user_proc;
vir_bytes user_addr;
vir_bytes count;
void *loc_addr;
{
int r;
r= sys_vircopy(SELF, D, (vir_bytes)loc_addr,
user_proc, D, user_addr, count);
if (r != OK)
panic("FXP","put_userdata: sys_vircopy failed", r);
}
/*===========================================================================*
* eeprom_read *
*===========================================================================*/

View file

@ -6,24 +6,30 @@
*
* The valid messages and their parameters are:
*
* m_type DL_PORT DL_PROC DL_COUNT DL_MODE DL_ADDR
* |------------+----------+---------+----------+---------+---------|
* | HARDINT | | | | | |
* |------------|----------|---------|----------|---------|---------|
* | DL_WRITE | port nr | proc nr | count | mode | address |
* |------------|----------|---------|----------|---------|---------|
* | DL_WRITEV | port nr | proc nr | count | mode | address |
* |------------|----------|---------|----------|---------|---------|
* | DL_READ | port nr | proc nr | count | | address |
* |------------|----------|---------|----------|---------|---------|
* | DL_READV | port nr | proc nr | count | | address |
* |------------|----------|---------|----------|---------|---------|
* | DL_INIT | port nr | proc nr | mode | | address |
* |------------|----------|---------|----------|---------|---------|
* | DL_GETSTAT | port nr | proc nr | | | address |
* |------------|----------|---------|----------|---------|---------|
* | DL_STOP | port_nr | | | | |
* |------------|----------|---------|----------|---------|---------|
* m_type DL_PORT DL_PROC DL_COUNT DL_MODE DL_ADDR DL_GRANT
* |------------+----------+---------+----------+---------+---------+---------|
* | HARDINT | | | | | | |
* |------------|----------|---------|----------|---------|---------|---------|
* | DL_WRITE | port nr | proc nr | count | mode | address | |
* |------------|----------|---------|----------|---------|---------|---------|
* | DL_WRITEV | port nr | proc nr | count | mode | address | |
* |------------|----------|---------|----------|---------|---------|---------|
* | DL_WRITEV_S| port nr | proc nr | count | mode | | grant |
* |------------|----------|---------|----------|---------|---------|---------|
* | DL_READ | port nr | proc nr | count | | address | |
* |------------|----------|---------|----------|---------|---------|---------|
* | DL_READV | port nr | proc nr | count | | address | |
* |------------|----------|---------|----------|---------|---------|---------|
* | DL_READV_S | port nr | proc nr | count | | | grant |
* |------------|----------|---------|----------|---------|---------|---------|
* | DL_CONF | port nr | proc nr | | mode | address | |
* |------------|----------|---------|----------|---------|---------|---------|
* | DL_GETSTAT | port nr | proc nr | | | address | |
* |------------|----------|---------|----------|---------|---------|---------|
* |DL_GETSTAT_S| port nr | proc nr | | | | grant |
* |------------|----------|---------|----------|---------|---------|---------|
* | DL_STOP | port_nr | | | | | |
* |------------|----------|---------|----------|---------|---------|---------|
*
* The messages sent are:
*
@ -34,7 +40,7 @@
*
* m_type m3_i1 m3_i2 m3_ca1
* |------------+---------+-----------+---------------|
* |DL_INIT_REPL| port nr | last port | ethernet addr |
* |DL_CONF_REPL| port nr | last port | ethernet addr |
* |------------|---------|-----------|---------------|
*
* Created: Jul 27, 2002 by Kazuya Kodama <kazuya@nii.ac.jp>
@ -144,11 +150,11 @@ _PROTOTYPE( static void reply,
_PROTOTYPE( static void ec_reset, (ether_card_t *ec) );
_PROTOTYPE( static void ec_send, (ether_card_t *ec) );
_PROTOTYPE( static void ec_recv, (ether_card_t *ec) );
_PROTOTYPE( static void do_vwrite,
(message *mp, int from_int, int vectored) );
_PROTOTYPE( static void do_vread, (message *mp, int vectored) );
_PROTOTYPE( static void get_userdata,
(int user_proc, vir_bytes user_addr,
_PROTOTYPE( static void do_vwrite_s,
(message *mp, int from_int) );
_PROTOTYPE( static void do_vread_s, (message *mp) );
_PROTOTYPE( static void get_userdata_s,
(int user_proc, cp_grant_id_t grant, vir_bytes offset,
vir_bytes count, void *loc_addr) );
_PROTOTYPE( static void ec_user2nic,
(ether_card_t *dep, iovec_dat_t *iovp,
@ -160,11 +166,10 @@ _PROTOTYPE( static void ec_nic2user,
vir_bytes count) );
_PROTOTYPE( static int calc_iovec_size, (iovec_dat_t *iovp) );
_PROTOTYPE( static void ec_next_iovec, (iovec_dat_t *iovp) );
_PROTOTYPE( static void do_getstat, (message *mp) );
_PROTOTYPE( static void put_userdata,
(int user_proc,
vir_bytes user_addr, vir_bytes count,
void *loc_addr) );
_PROTOTYPE( static void do_getstat_s, (message *mp) );
_PROTOTYPE( static void put_userdata_s,
(int user_proc, cp_grant_id_t grant,
void *loc_addr, vir_bytes count) );
_PROTOTYPE( static void do_stop, (message *mp) );
_PROTOTYPE( static void do_getname, (message *mp) );
@ -356,14 +361,12 @@ void main( int argc, char **argv )
switch (m.m_type){
case DEV_PING: notify(m.m_source); continue;
case DL_WRITE: do_vwrite(&m, FALSE, FALSE); break;
case DL_WRITEV: do_vwrite(&m, FALSE, TRUE); break;
case DL_READ: do_vread(&m, FALSE); break;
case DL_READV: do_vread(&m, TRUE); break;
case DL_INIT: do_init(&m); break;
case DL_GETSTAT: do_getstat(&m); break;
case DL_WRITEV_S: do_vwrite_s(&m, FALSE); break;
case DL_READV_S: do_vread_s(&m); break;
case DL_CONF: do_init(&m); break;
case DL_GETSTAT_S: do_getstat_s(&m); break;
case DL_STOP: do_stop(&m); break;
case DL_GETNAME: do_getname(&m); break;
case DL_GETNAME: do_getname(&m); break;
case FKEY_PRESSED: lance_dump(); break;
/*case HARD_STOP: lance_stop(); break;*/
case SYS_SIG:
@ -493,7 +496,7 @@ pci_init();
port = mp->DL_PORT;
if (port < 0 || port >= EC_PORT_NR_MAX)
{
reply_mess.m_type= DL_INIT_REPLY;
reply_mess.m_type= DL_CONF_REPLY;
reply_mess.m3_i1= ENXIO;
mess_reply(mp, &reply_mess);
return;
@ -517,7 +520,7 @@ pci_init();
if (ec->mode == EC_DISABLED)
{
/* Probe failed, or the device is configured off. */
reply_mess.m_type= DL_INIT_REPLY;
reply_mess.m_type= DL_CONF_REPLY;
reply_mess.m3_i1= ENXIO;
mess_reply(mp, &reply_mess);
return;
@ -535,7 +538,7 @@ pci_init();
ec->mac_address.ea_addr[4] =
ec->mac_address.ea_addr[5] = 0;
ec_confaddr(ec);
reply_mess.m_type = DL_INIT_REPLY;
reply_mess.m_type = DL_CONF_REPLY;
reply_mess.m3_i1 = mp->DL_PORT;
reply_mess.m3_i2 = EC_PORT_NR_MAX;
*(ether_addr_t *) reply_mess.m3_ca1 = ec->mac_address;
@ -557,7 +560,7 @@ pci_init();
ec->client = mp->m_source;
ec_reinit(ec);
reply_mess.m_type = DL_INIT_REPLY;
reply_mess.m_type = DL_CONF_REPLY;
reply_mess.m3_i1 = mp->DL_PORT;
reply_mess.m3_i2 = EC_PORT_NR_MAX;
*(ether_addr_t *) reply_mess.m3_ca1 = ec->mac_address;
@ -1071,8 +1074,7 @@ ether_card_t *ec;
ec->flags &= ~ECF_SEND_AVAIL;
switch(ec->sendmsg.m_type)
{
case DL_WRITE: do_vwrite(&ec->sendmsg, TRUE, FALSE); break;
case DL_WRITEV: do_vwrite(&ec->sendmsg, TRUE, TRUE); break;
case DL_WRITEV_S: do_vwrite_s(&ec->sendmsg, TRUE); break;
default:
panic( "lance", "wrong type:", ec->sendmsg.m_type);
break;
@ -1080,11 +1082,10 @@ ether_card_t *ec;
}
/*===========================================================================*
* do_vread *
* do_vread_s *
*===========================================================================*/
static void do_vread(mp, vectored)
static void do_vread_s(mp)
message *mp;
int vectored;
{
int port, count, size;
ether_card_t *ec;
@ -1094,28 +1095,17 @@ int vectored;
ec= &ec_table[port];
ec->client= mp->DL_PROC;
if (vectored)
{
get_userdata(mp->DL_PROC, (vir_bytes) mp->DL_ADDR,
(count > IOVEC_NR ? IOVEC_NR : count) *
sizeof(iovec_t), ec->read_iovec.iod_iovec);
ec->read_iovec.iod_iovec_s = count;
ec->read_iovec.iod_proc_nr = mp->DL_PROC;
ec->read_iovec.iod_iovec_addr = (vir_bytes) mp->DL_ADDR;
ec->tmp_iovec = ec->read_iovec;
size= calc_iovec_size(&ec->tmp_iovec);
}
else
{
ec->read_iovec.iod_iovec[0].iov_addr = (vir_bytes) mp->DL_ADDR;
ec->read_iovec.iod_iovec[0].iov_size = mp->DL_COUNT;
ec->read_iovec.iod_iovec_s = 1;
ec->read_iovec.iod_proc_nr = mp->DL_PROC;
ec->read_iovec.iod_iovec_addr = 0;
get_userdata_s(mp->DL_PROC, (vir_bytes) mp->DL_GRANT, 0,
(count > IOVEC_NR ? IOVEC_NR : count) *
sizeof(iovec_s_t), ec->read_iovec.iod_iovec);
ec->read_iovec.iod_iovec_s = count;
ec->read_iovec.iod_proc_nr = mp->DL_PROC;
ec->read_iovec.iod_grant = (vir_bytes) mp->DL_GRANT;
ec->read_iovec.iod_iovec_offset = 0;
ec->tmp_iovec = ec->read_iovec;
size= calc_iovec_size(&ec->tmp_iovec);
size= count;
}
ec->flags |= ECF_READING;
ec_recv(ec);
@ -1195,12 +1185,11 @@ ether_card_t *ec;
}
/*===========================================================================*
* do_vwrite *
* do_vwrite_s *
*===========================================================================*/
static void do_vwrite(mp, from_int, vectored)
static void do_vwrite_s(mp, from_int)
message *mp;
int from_int;
int vectored;
{
int port, count, check;
ether_card_t *ec;
@ -1221,30 +1210,17 @@ int vectored;
}
/* convert the message to write_iovec */
if (vectored)
{
get_userdata(mp->DL_PROC, (vir_bytes) mp->DL_ADDR,
(count > IOVEC_NR ? IOVEC_NR : count) *
sizeof(iovec_t), ec->write_iovec.iod_iovec);
get_userdata_s(mp->DL_PROC, mp->DL_GRANT, 0,
(count > IOVEC_NR ? IOVEC_NR : count) *
sizeof(iovec_s_t), ec->write_iovec.iod_iovec);
ec->write_iovec.iod_iovec_s = count;
ec->write_iovec.iod_proc_nr = mp->DL_PROC;
ec->write_iovec.iod_iovec_addr = (vir_bytes) mp->DL_ADDR;
ec->write_iovec.iod_iovec_s = count;
ec->write_iovec.iod_proc_nr = mp->DL_PROC;
ec->write_iovec.iod_grant = mp->DL_GRANT;
ec->write_iovec.iod_iovec_offset = 0;
ec->tmp_iovec = ec->write_iovec;
ec->write_s = calc_iovec_size(&ec->tmp_iovec);
}
else
{
ec->write_iovec.iod_iovec[0].iov_addr = (vir_bytes) mp->DL_ADDR;
ec->write_iovec.iod_iovec[0].iov_size = mp->DL_COUNT;
ec->write_iovec.iod_iovec_s = 1;
ec->write_iovec.iod_proc_nr = mp->DL_PROC;
ec->write_iovec.iod_iovec_addr = 0;
ec->write_s = mp->DL_COUNT;
}
ec->tmp_iovec = ec->write_iovec;
ec->write_s = calc_iovec_size(&ec->tmp_iovec);
/* copy write_iovec to the slot on DMA address */
ec_user2nic(ec, &ec->write_iovec, 0,
@ -1279,26 +1255,21 @@ int vectored;
/*===========================================================================*
* get_userdata *
* get_userdata_s *
*===========================================================================*/
static void get_userdata(user_proc, user_addr, count, loc_addr)
static void get_userdata_s(user_proc, grant, offset, count, loc_addr)
int user_proc;
vir_bytes user_addr;
cp_grant_id_t grant;
vir_bytes offset;
vir_bytes count;
void *loc_addr;
{
/*
phys_bytes src;
src = numap_local(user_proc, user_addr, count);
if (!src)
panic( "lance", "umap failed", NO_NUM);
phys_copy(src, vir2phys(loc_addr), (phys_bytes) count);
*/
int cps;
cps = sys_datacopy(user_proc, user_addr, SELF, (vir_bytes) loc_addr, count);
if (cps != OK) printf("lance: warning, scopy failed: %d\n", cps);
cps = sys_safecopyfrom(user_proc, grant, offset,
(vir_bytes)loc_addr, count, D);
if (cps != OK)
panic(__FILE__,
"get_userdata_s: sys_safecopyfrom failed: %d\n", cps);
}
/*===========================================================================*
@ -1311,12 +1282,8 @@ vir_bytes offset;
int nic_addr;
vir_bytes count;
{
/*phys_bytes phys_hw, phys_user;*/
int bytes, i, r;
/*
phys_hw = vir2phys(nic_addr);
*/
i= 0;
while (count > 0)
{
@ -1336,15 +1303,10 @@ vir_bytes count;
if (bytes > count)
bytes = count;
/*
phys_user = numap_local(iovp->iod_proc_nr,
iovp->iod_iovec[i].iov_addr + offset, bytes);
phys_copy(phys_user, phys_hw, (phys_bytes) bytes);
*/
if ( (r=sys_datacopy(iovp->iod_proc_nr, iovp->iod_iovec[i].iov_addr + offset,
SELF, nic_addr, count )) != OK )
panic( "lance", "sys_datacopy failed", r );
if ( (r=sys_safecopyfrom(iovp->iod_proc_nr,
iovp->iod_iovec[i].iov_grant, offset,
nic_addr, bytes, D )) != OK )
panic( __FILE__, "ec_user2nic: sys_safecopyfrom failed", r );
count -= bytes;
nic_addr += bytes;
@ -1362,11 +1324,8 @@ iovec_dat_t *iovp;
vir_bytes offset;
vir_bytes count;
{
/*phys_bytes phys_hw, phys_user;*/
int bytes, i, r;
/*phys_hw = vir2phys(nic_addr);*/
i= 0;
while (count > 0)
{
@ -1385,14 +1344,9 @@ vir_bytes count;
bytes = iovp->iod_iovec[i].iov_size - offset;
if (bytes > count)
bytes = count;
/*
phys_user = numap_local(iovp->iod_proc_nr,
iovp->iod_iovec[i].iov_addr + offset, bytes);
phys_copy(phys_hw, phys_user, (phys_bytes) bytes);
*/
if ( (r=sys_datacopy( SELF, nic_addr, iovp->iod_proc_nr, iovp->iod_iovec[i].iov_addr + offset, bytes )) != OK )
panic( "lance", "sys_datacopy failed: ", r );
if ( (r=sys_safecopyto( iovp->iod_proc_nr, iovp->iod_iovec[i].iov_grant,
offset, nic_addr, bytes, D )) != OK )
panic( __FILE__, "ec_nic2user: sys_safecopyto failed: ", r );
count -= bytes;
nic_addr += bytes;
@ -1433,19 +1387,20 @@ static void ec_next_iovec(iovp)
iovec_dat_t *iovp;
{
iovp->iod_iovec_s -= IOVEC_NR;
iovp->iod_iovec_addr += IOVEC_NR * sizeof(iovec_t);
iovp->iod_iovec_offset += IOVEC_NR * sizeof(iovec_s_t);
get_userdata(iovp->iod_proc_nr, iovp->iod_iovec_addr,
get_userdata_s(iovp->iod_proc_nr, iovp->iod_grant,
iovp->iod_iovec_offset,
(iovp->iod_iovec_s > IOVEC_NR ?
IOVEC_NR : iovp->iod_iovec_s) * sizeof(iovec_t),
IOVEC_NR : iovp->iod_iovec_s) * sizeof(iovec_s_t),
iovp->iod_iovec);
}
/*===========================================================================*
* do_getstat *
* do_getstat_s *
*===========================================================================*/
static void do_getstat(mp)
static void do_getstat_s(mp)
message *mp;
{
int port;
@ -1458,31 +1413,26 @@ message *mp;
ec= &ec_table[port];
ec->client= mp->DL_PROC;
put_userdata(mp->DL_PROC, (vir_bytes) mp->DL_ADDR,
(vir_bytes) sizeof(ec->eth_stat), &ec->eth_stat);
put_userdata_s(mp->DL_PROC, mp->DL_GRANT,
&ec->eth_stat, sizeof(ec->eth_stat));
reply(ec, OK, FALSE);
}
/*===========================================================================*
* put_userdata *
* put_userdata_s *
*===========================================================================*/
static void put_userdata(user_proc, user_addr, count, loc_addr)
static void put_userdata_s(user_proc, grant, loc_addr, count)
int user_proc;
vir_bytes user_addr;
vir_bytes count;
cp_grant_id_t grant;
void *loc_addr;
vir_bytes count;
{
/*phys_bytes dst;
dst = numap_local(user_proc, user_addr, count);
if (!dst)
panic( "lance", "umap failed", NO_NUM);
phys_copy(vir2phys(loc_addr), dst, (phys_bytes) count);
*/
int cps;
cps = sys_datacopy(SELF, (vir_bytes) loc_addr, user_proc, user_addr, count);
if (cps != OK) printf("lance: warning, scopy failed: %d\n", cps);
cps = sys_safecopyto(user_proc, grant, 0,
(vir_bytes) loc_addr, count, D);
if (cps != OK)
panic(__FILE__,
"put_userdata_s: sys_safecopyto failed: %d\n", cps);
}
/*===========================================================================*

View file

@ -53,10 +53,11 @@
#define IOVEC_NR 16
typedef struct iovec_dat
{
iovec_t iod_iovec[IOVEC_NR];
iovec_s_t iod_iovec[IOVEC_NR];
int iod_iovec_s;
int iod_proc_nr;
vir_bytes iod_iovec_addr;
cp_grant_id_t iod_grant;
vir_bytes iod_iovec_offset;
} iovec_dat_t;
#define ETH0_SELECTOR 0x61

View file

@ -6,26 +6,30 @@
*
* The valid messages and their parameters are:
*
* m_type DL_PORT DL_PROC DL_COUNT DL_MODE DL_ADDR
* |------------+----------+---------+----------+---------+---------|
* | HARD_INT | | | | | |
* |------------|----------|---------|----------|---------|---------|
* | DL_WRITE | port nr | proc nr | count | mode | address |
* |------------|----------|---------|----------|---------|---------|
* | DL_WRITEV | port nr | proc nr | count | mode | address |
* |------------|----------|---------|----------|---------|---------|
* | DL_READ | port nr | proc nr | count | | address |
* |------------|----------|---------|----------|---------|---------|
* | DL_READV | port nr | proc nr | count | | address |
* |------------|----------|---------|----------|---------|---------|
* | DL_INIT | port nr | proc nr | mode | | address |
* |------------|----------|---------|----------|---------|---------|
* | DL_GETSTAT | port nr | proc nr | | | address |
* |------------|----------|---------|----------|---------|---------|
* | DL_GETNAME | | | | | |
* |------------|----------|---------|----------|---------|---------|
* | DL_STOP | port_nr | | | | |
* |------------|----------|---------|----------|---------|---------|
* m_type DL_PORT DL_PROC DL_COUNT DL_MODE DL_ADDR DL_GRANT
* |------------+----------+---------+----------+---------+---------+---------|
* | HARDINT | | | | | | |
* |------------|----------|---------|----------|---------|---------|---------|
* | DL_WRITE | port nr | proc nr | count | mode | address | |
* |------------|----------|---------|----------|---------|---------|---------|
* | DL_WRITEV | port nr | proc nr | count | mode | address | |
* |------------|----------|---------|----------|---------|---------|---------|
* | DL_WRITEV_S| port nr | proc nr | count | mode | | grant |
* |------------|----------|---------|----------|---------|---------|---------|
* | DL_READ | port nr | proc nr | count | | address | |
* |------------|----------|---------|----------|---------|---------|---------|
* | DL_READV | port nr | proc nr | count | | address | |
* |------------|----------|---------|----------|---------|---------|---------|
* | DL_READV_S | port nr | proc nr | count | | | grant |
* |------------|----------|---------|----------|---------|---------|---------|
* | DL_CONF | port nr | proc nr | | mode | address | |
* |------------|----------|---------|----------|---------|---------|---------|
* | DL_GETSTAT | port nr | proc nr | | | address | |
* |------------|----------|---------|----------|---------|---------|---------|
* |DL_GETSTAT_S| port nr | proc nr | | | | grant |
* |------------|----------|---------|----------|---------|---------|---------|
* | DL_STOP | port_nr | | | | | |
* |------------|----------|---------|----------|---------|---------|---------|
*
* The messages sent are:
*
@ -36,7 +40,7 @@
*
* m_type m3_i1 m3_i2 m3_ca1
* |------------+---------+-----------+---------------|
* |DL_INIT_REPL| port nr | last port | ethernet addr |
* |DL_CONF_REPL| port nr | last port | ethernet addr |
* |------------|---------|-----------|---------------|
*
* Created: Aug 2003 by Philip Homburg <philip@cs.vu.nl>
@ -155,6 +159,7 @@ typedef struct re
message re_tx_mess;
char re_name[sizeof("rtl8139#n")];
iovec_t re_iovec[IOVEC_NR];
iovec_s_t re_iovec_s[IOVEC_NR];
}
re_t;
@ -238,8 +243,10 @@ _PROTOTYPE( static void rl_confaddr, (re_t *rep) );
_PROTOTYPE( static void rl_rec_mode, (re_t *rep) );
_PROTOTYPE( static void rl_readv, (message *mp, int from_int,
int vectored) );
_PROTOTYPE( static void rl_readv_s, (message *mp, int from_int) );
_PROTOTYPE( static void rl_writev, (message *mp, int from_int,
int vectored) );
_PROTOTYPE( static void rl_writev_s, (message *mp, int from_int) );
_PROTOTYPE( static void rl_check_ints, (re_t *rep) );
_PROTOTYPE( static void rl_report_link, (re_t *rep) );
_PROTOTYPE( static void mii_print_techab, (U16_t techab) );
@ -248,11 +255,10 @@ _PROTOTYPE( static void mii_print_stat_speed, (U16_t stat,
_PROTOTYPE( static void rl_clear_rx, (re_t *rep) );
_PROTOTYPE( static void rl_do_reset, (re_t *rep) );
_PROTOTYPE( static void rl_getstat, (message *mp) );
_PROTOTYPE( static void rl_getstat_s, (message *mp) );
_PROTOTYPE( static void rl_getname, (message *mp) );
_PROTOTYPE( static void reply, (re_t *rep, int err, int may_block) );
_PROTOTYPE( static void mess_reply, (message *req, message *reply) );
_PROTOTYPE( static void put_userdata, (int user_proc,
vir_bytes user_addr, vir_bytes count, void *loc_addr) );
_PROTOTYPE( static void rtl8139_stop, (void) );
_PROTOTYPE( static void check_int_events, (void) );
_PROTOTYPE( static int do_hard_int, (void) );
@ -314,15 +320,16 @@ int main(int argc, char *argv[])
switch (m.m_type)
{
case DEV_PING: notify(m.m_source); continue;
case DL_WRITEV: rl_writev(&m, FALSE, TRUE); break;
case DEV_PING: notify(m.m_source); break;
case DL_WRITE: rl_writev(&m, FALSE, FALSE); break;
#if 0
case DL_READ: do_vread(&m, FALSE); break;
#endif
case DL_WRITEV: rl_writev(&m, FALSE, TRUE); break;
case DL_WRITEV_S: rl_writev_s(&m, FALSE); break;
case DL_READ: rl_readv(&m, FALSE, FALSE); break;
case DL_READV: rl_readv(&m, FALSE, TRUE); break;
case DL_INIT: rl_init(&m); break;
case DL_READV_S: rl_readv_s(&m, FALSE); break;
case DL_CONF: rl_init(&m); break;
case DL_GETSTAT: rl_getstat(&m); break;
case DL_GETSTAT_S: rl_getstat_s(&m); break;
case DL_GETNAME: rl_getname(&m); break;
#if 0
case DL_STOP: do_stop(&m); break;
@ -490,7 +497,7 @@ message *mp;
port = mp->DL_PORT;
if (port < 0 || port >= RE_PORT_NR)
{
reply_mess.m_type= DL_INIT_REPLY;
reply_mess.m_type= DL_CONF_REPLY;
reply_mess.m3_i1= ENXIO;
mess_reply(mp, &reply_mess);
return;
@ -503,7 +510,7 @@ message *mp;
if (rep->re_mode == REM_DISABLED)
{
/* Probe failed, or the device is configured off. */
reply_mess.m_type= DL_INIT_REPLY;
reply_mess.m_type= DL_CONF_REPLY;
reply_mess.m3_i1= ENXIO;
mess_reply(mp, &reply_mess);
return;
@ -530,7 +537,7 @@ message *mp;
rep->re_client = mp->m_source;
rl_rec_mode(rep);
reply_mess.m_type = DL_INIT_REPLY;
reply_mess.m_type = DL_CONF_REPLY;
reply_mess.m3_i1 = mp->DL_PORT;
reply_mess.m3_i2 = RE_PORT_NR;
*(ether_addr_t *) reply_mess.m3_ca1 = rep->re_address;
@ -1058,14 +1065,6 @@ int vectored;
rxstat = *(u32_t *) (rep->v_re_rx_buf + d_start);
#if DEAD_CODE
src_phys= rep->re_rx_buf + d_start;
cps = sys_physcopy(
NONE, PHYS_SEG, src_phys,
SELF, D, (vir_bytes) &rxstat, sizeof(rxstat));
if (cps != OK) printf("RTL8139: warning, sys_abscopy failed: %d\n", cps);
#endif
if (rep->re_clear_rx)
{
#if 0
@ -1113,11 +1112,6 @@ int vectored;
if (vectored)
{
int iov_offset = 0;
#if 0
if ((cps = sys_umap(re_client, D, (vir_bytes) mp->DL_ADDR,
count * sizeof(rep->re_iovec[0]), &iov_src)) != OK)
printf("sys_umap failed: %d\n", cps);
#endif
size= 0;
o= d_start+4;
@ -1129,15 +1123,15 @@ int vectored;
n= IOVEC_NR;
if (i+n > count)
n= count-i;
#if 0
cps = sys_physcopy(NONE, PHYS_SEG, iov_src, SELF, D, (vir_bytes) rep->re_iovec,
cps = sys_vircopy(re_client, D,
(vir_bytes) mp->DL_ADDR + iov_offset,
SELF, D, (vir_bytes) rep->re_iovec,
n * sizeof(rep->re_iovec[0]));
if (cps != OK) printf("RTL8139: warning, sys_abscopy failed: %d\n", cps);
#else
cps = sys_vircopy(re_client, D, (vir_bytes) mp->DL_ADDR + iov_offset,
SELF, D, (vir_bytes) rep->re_iovec, n * sizeof(rep->re_iovec[0]));
if (cps != OK) printf("RTL8139: warning, sys_vircopy failed: %d (%d)\n", cps, __LINE__);
#endif
if (cps != OK)
printf(
"RTL8139: warning, sys_vircopy failed: %d (%d)\n",
cps, __LINE__);
for (j= 0, iovp= rep->re_iovec; j<n; j++, iovp++)
{
@ -1148,11 +1142,6 @@ int vectored;
s= packlen-size;
}
#if 0
if (sys_umap(re_client, D, iovp->iov_addr, s, &dst_phys) != OK)
panic("rtl8139","umap_local failed\n", NO_NUM);
#endif
if (o >= RX_BUFSIZE)
{
o -= RX_BUFSIZE;
@ -1164,30 +1153,33 @@ int vectored;
assert(o<RX_BUFSIZE);
s1= RX_BUFSIZE-o;
#if 0
cps = sys_abscopy(src_phys+o, dst_phys, s1);
if (cps != OK) printf("RTL8139: warning, sys_abscopy failed: %d\n", cps);
cps = sys_abscopy(src_phys, dst_phys+s1, s-s1);
if (cps != OK) printf("RTL8139: warning, sys_abscopy failed: %d\n", cps);
#else
cps = sys_vircopy(SELF, D, (vir_bytes) rep->v_re_rx_buf+o,
re_client, D, iovp->iov_addr, s1);
if (cps != OK) printf("RTL8139: warning, sys_vircopy failed: %d (%d)\n", cps, __LINE__);
cps = sys_vircopy(SELF, D, (vir_bytes) rep->v_re_rx_buf,
re_client, D, iovp->iov_addr+s1, s-s1);
if (cps != OK) printf("RTL8139: warning, sys_vircopy failed: %d (%d)\n", cps, __LINE__);
#endif
cps = sys_vircopy(SELF, D,
(vir_bytes) rep->v_re_rx_buf+o,
re_client, D, iovp->iov_addr,
s1);
if (cps != OK)
printf(
"RTL8139: warning, sys_vircopy failed: %d (%d)\n",
cps, __LINE__);
cps = sys_vircopy(SELF, D,
(vir_bytes) rep->v_re_rx_buf,
re_client, D,
iovp->iov_addr+s1, s-s1);
if (cps != OK)
printf(
"RTL8139: warning, sys_vircopy failed: %d (%d)\n",
cps, __LINE__);
}
else
{
#if 0
cps = sys_abscopy(src_phys+o, dst_phys, s);
if (cps != OK) printf("RTL8139: warning, sys_abscopy failed: %d\n", cps);
#else
cps = sys_vircopy(SELF, D, (vir_bytes) rep->v_re_rx_buf+o,
re_client, D, iovp->iov_addr, s);
if (cps != OK) printf("RTL8139: warning, sys_vircopy failed: %d (%d)\n", cps, __LINE__);
#endif
cps = sys_vircopy(SELF, D,
(vir_bytes) rep->v_re_rx_buf+o,
re_client, D, iovp->iov_addr,
s);
if (cps != OK)
printf(
"RTL8139: warning, sys_vircopy failed: %d (%d)\n",
cps, __LINE__);
}
size += s;
@ -1217,146 +1209,368 @@ int vectored;
cps = sys_abscopy(phys_user, p, size);
if (cps != OK) printf("RTL8139: warning, sys_abscopy failed: %d\n", cps);
#endif
}
if (rep->re_clear_rx)
{
/* For some reason the receiver FIFO is not stopped when
* the buffer is full.
*/
#if 0
printf("rl_readv: later buffer overflow\n");
#endif
goto suspend; /* Buffer overflow */
}
rep->re_stat.ets_packetR++;
rep->re_read_s= packlen;
rep->re_flags= (rep->re_flags & ~REF_READING) | REF_PACK_RECV;
/* Avoid overflow in 16-bit computations */
l= d_start;
l += totlen+4;
l= (l+3) & ~3; /* align */
if (l >= RX_BUFSIZE)
{
l -= RX_BUFSIZE;
assert(l < RX_BUFSIZE);
}
rl_outw(port, RL_CAPR, l-RL_CAPR_DATA_OFF);
if (!from_int)
reply(rep, OK, FALSE);
return;
suspend:
if (from_int)
{
assert(rep->re_flags & REF_READING);
/* No need to store any state */
return;
}
rep->re_rx_mess= *mp;
assert(!(rep->re_flags & REF_READING));
rep->re_flags |= REF_READING;
reply(rep, OK, FALSE);
}
/*===========================================================================*
* rl_writev *
*===========================================================================*/
static void rl_writev(mp, from_int, vectored)
message *mp;
int from_int;
int vectored;
if (rep->re_clear_rx)
{
phys_bytes p, iov_src, phys_user;
int i, j, n, s, port, count, size;
int tx_head, re_client;
re_t *rep;
iovec_t *iovp;
char *ret;
int cps;
/* For some reason the receiver FIFO is not stopped when
* the buffer is full.
*/
#if 0
printf("rl_readv: later buffer overflow\n");
#endif
goto suspend; /* Buffer overflow */
}
port = mp->DL_PORT;
count = mp->DL_COUNT;
if (port < 0 || port >= RE_PORT_NR)
panic("rtl8139","illegal port", port);
rep= &re_table[port];
re_client= mp->DL_PROC;
rep->re_client= re_client;
rep->re_stat.ets_packetR++;
rep->re_read_s= packlen;
rep->re_flags= (rep->re_flags & ~REF_READING) | REF_PACK_RECV;
assert(rep->re_mode == REM_ENABLED);
assert(rep->re_flags & REF_ENABLED);
/* Avoid overflow in 16-bit computations */
l= d_start;
l += totlen+4;
l= (l+3) & ~3; /* align */
if (l >= RX_BUFSIZE)
{
l -= RX_BUFSIZE;
assert(l < RX_BUFSIZE);
}
rl_outw(port, RL_CAPR, l-RL_CAPR_DATA_OFF);
if (from_int)
{
assert(rep->re_flags & REF_SEND_AVAIL);
rep->re_flags &= ~REF_SEND_AVAIL;
rep->re_send_int= FALSE;
rep->re_tx_alive= TRUE;
}
if (!from_int)
reply(rep, OK, FALSE);
tx_head= rep->re_tx_head;
if (rep->re_tx[tx_head].ret_busy)
{
assert(!(rep->re_flags & REF_SEND_AVAIL));
rep->re_flags |= REF_SEND_AVAIL;
if (rep->re_tx[tx_head].ret_busy)
goto suspend;
return;
/* Race condition, the interrupt handler may clear re_busy
* before we got a chance to set REF_SEND_AVAIL. Checking
* ret_busy twice should be sufficient.
*/
#if 0
printf("rl_writev: race detected\n");
#endif
rep->re_flags &= ~REF_SEND_AVAIL;
rep->re_send_int= FALSE;
}
suspend:
if (from_int)
{
assert(rep->re_flags & REF_READING);
assert(!(rep->re_flags & REF_SEND_AVAIL));
assert(!(rep->re_flags & REF_PACK_SENT));
/* No need to store any state */
return;
}
if (vectored)
{
int iov_offset = 0;
rep->re_rx_mess= *mp;
assert(!(rep->re_flags & REF_READING));
rep->re_flags |= REF_READING;
reply(rep, OK, FALSE);
}
/*===========================================================================*
* rl_readv_s *
*===========================================================================*/
static void rl_readv_s(mp, from_int)
message *mp;
int from_int;
{
int i, j, n, o, s, s1, dl_port, re_client, count, size;
port_t port;
unsigned amount, totlen, packlen;
phys_bytes src_phys, dst_phys, iov_src;
u16_t d_start, d_end;
u32_t l, rxstat = 0x12345678;
re_t *rep;
iovec_s_t *iovp;
int cps;
int iov_offset = 0;
dl_port = mp->DL_PORT;
count = mp->DL_COUNT;
if (dl_port < 0 || dl_port >= RE_PORT_NR)
panic("rtl8139"," illegal port", dl_port);
rep= &re_table[dl_port];
re_client= mp->DL_PROC;
rep->re_client= re_client;
if (rep->re_clear_rx)
goto suspend; /* Buffer overflow */
assert(rep->re_mode == REM_ENABLED);
assert(rep->re_flags & REF_ENABLED);
port= rep->re_base_port;
/* Assume that the RL_CR_BUFE check was been done by rl_checks_ints
*/
if (!from_int && (rl_inb(port, RL_CR) & RL_CR_BUFE))
{
/* Receive buffer is empty, suspend */
goto suspend;
}
d_start= rl_inw(port, RL_CAPR) + RL_CAPR_DATA_OFF;
d_end= rl_inw(port, RL_CBR) % RX_BUFSIZE;
if (d_start >= RX_BUFSIZE)
{
printf("rl_readv: strange value in RL_CAPR: 0x%x\n",
rl_inw(port, RL_CAPR));
d_start %= RX_BUFSIZE;
}
if (d_end > d_start)
amount= d_end-d_start;
else
amount= d_end+RX_BUFSIZE - d_start;
rxstat = *(u32_t *) (rep->v_re_rx_buf + d_start);
if (rep->re_clear_rx)
{
#if 0
printf("rl_readv: late buffer overflow\n");
#endif
goto suspend; /* Buffer overflow */
}
/* Should convert from little endian to host byte order */
if (!(rxstat & RL_RXS_ROK))
{
printf("rxstat = 0x%08lx\n", rxstat);
printf("d_start: 0x%x, d_end: 0x%x, rxstat: 0x%lx\n",
d_start, d_end, rxstat);
panic("rtl8139","received packet not OK", NO_NUM);
}
totlen= (rxstat >> RL_RXS_LEN_S);
if (totlen < 8 || totlen > 2*ETH_MAX_PACK_SIZE)
{
/* Someting went wrong */
printf(
"rl_readv: bad length (%u) in status 0x%08lx at offset 0x%x\n",
totlen, rxstat, d_start);
printf(
"d_start: 0x%x, d_end: 0x%x, totlen: %d, rxstat: 0x%lx\n",
d_start, d_end, totlen, rxstat);
panic(NULL, NULL, NO_NUM);
}
#if 0
if (OK != sys_umap(re_client, D, (vir_bytes)mp->DL_ADDR,
count * sizeof(rep->re_iovec[0]), &iov_src))
panic("rtl8139","umap_local failed", NO_NUM);
printf("d_start: 0x%x, d_end: 0x%x, totlen: %d, rxstat: 0x%x\n",
d_start, d_end, totlen, rxstat);
#endif
size= 0;
#if 0
p= rep->re_tx[tx_head].ret_buf;
#else
ret = rep->re_tx[tx_head].v_ret_buf;
#endif
for (i= 0; i<count; i += IOVEC_NR,
iov_src += IOVEC_NR * sizeof(rep->re_iovec[0]),
iov_offset += IOVEC_NR * sizeof(rep->re_iovec[0]))
if (totlen+4 > amount)
{
printf("rl_readv: packet not yet ready\n");
goto suspend;
}
/* Should subtract the CRC */
packlen= totlen - ETH_CRC_SIZE;
size= 0;
o= d_start+4;
src_phys= rep->re_rx_buf;
for (i= 0; i<count; i += IOVEC_NR,
iov_src += IOVEC_NR * sizeof(rep->re_iovec_s[0]),
iov_offset += IOVEC_NR * sizeof(rep->re_iovec_s[0]))
{
n= IOVEC_NR;
if (i+n > count)
n= count-i;
cps = sys_safecopyfrom(re_client, mp->DL_GRANT, iov_offset,
(vir_bytes) rep->re_iovec_s,
n * sizeof(rep->re_iovec_s[0]), D);
if (cps != OK)
{
panic(__FILE__, "rl_readv_s: sys_safecopyfrom failed",
cps);
}
for (j= 0, iovp= rep->re_iovec_s; j<n; j++, iovp++)
{
s= iovp->iov_size;
if (size + s > packlen)
{
n= IOVEC_NR;
if (i+n > count)
n= count-i;
assert(packlen > size);
s= packlen-size;
}
#if 0
cps = sys_physcopy(NONE, PHYS_SEG, iov_src, SELF, D, (vir_bytes) rep->re_iovec,
n * sizeof(rep->re_iovec[0]));
if (cps != OK) printf("RTL8139: warning, sys_abscopy failed: %d\n", cps);
#else
cps = sys_vircopy(re_client, D, ((vir_bytes) mp->DL_ADDR) + iov_offset,
SELF, D, (vir_bytes) rep->re_iovec,
n * sizeof(rep->re_iovec[0]));
if (cps != OK) printf("RTL8139: warning, sys_vircopy failed: %d\n", cps);
if (sys_umap(re_client, D, iovp->iov_addr, s, &dst_phys) != OK)
panic("rtl8139","umap_local failed\n", NO_NUM);
#endif
if (o >= RX_BUFSIZE)
{
o -= RX_BUFSIZE;
assert(o < RX_BUFSIZE);
}
if (o+s > RX_BUFSIZE)
{
assert(o<RX_BUFSIZE);
s1= RX_BUFSIZE-o;
cps = sys_safecopyto(re_client,
iovp->iov_grant, 0,
(vir_bytes) rep->v_re_rx_buf+o, s1, D);
if (cps != OK)
{
panic(__FILE__,
"rl_readv_s: sys_safecopyto failed",
cps);
}
cps = sys_safecopyto(re_client,
iovp->iov_grant, s1,
(vir_bytes) rep->v_re_rx_buf, s-s1, S);
if (cps != OK)
{
panic(__FILE__,
"rl_readv_s: sys_safecopyto failed",
cps);
}
}
else
{
cps = sys_safecopyto(re_client,
iovp->iov_grant, 0,
(vir_bytes) rep->v_re_rx_buf+o, s, D);
if (cps != OK)
panic(__FILE__,
"rl_readv_s: sys_vircopy failed",
cps);
}
size += s;
if (size == packlen)
break;
o += s;
}
if (size == packlen)
break;
}
if (size < packlen)
{
assert(0);
}
if (rep->re_clear_rx)
{
/* For some reason the receiver FIFO is not stopped when
* the buffer is full.
*/
#if 0
printf("rl_readv: later buffer overflow\n");
#endif
goto suspend; /* Buffer overflow */
}
rep->re_stat.ets_packetR++;
rep->re_read_s= packlen;
rep->re_flags= (rep->re_flags & ~REF_READING) | REF_PACK_RECV;
/* Avoid overflow in 16-bit computations */
l= d_start;
l += totlen+4;
l= (l+3) & ~3; /* align */
if (l >= RX_BUFSIZE)
{
l -= RX_BUFSIZE;
assert(l < RX_BUFSIZE);
}
rl_outw(port, RL_CAPR, l-RL_CAPR_DATA_OFF);
if (!from_int)
reply(rep, OK, FALSE);
return;
suspend:
if (from_int)
{
assert(rep->re_flags & REF_READING);
/* No need to store any state */
return;
}
rep->re_rx_mess= *mp;
assert(!(rep->re_flags & REF_READING));
rep->re_flags |= REF_READING;
reply(rep, OK, FALSE);
}
/*===========================================================================*
* rl_writev *
*===========================================================================*/
static void rl_writev(mp, from_int, vectored)
message *mp;
int from_int;
int vectored;
{
phys_bytes iov_src, phys_user;
int i, j, n, s, port, count, size;
int tx_head, re_client;
re_t *rep;
iovec_t *iovp;
char *ret;
int cps;
port = mp->DL_PORT;
count = mp->DL_COUNT;
if (port < 0 || port >= RE_PORT_NR)
panic("rtl8139","illegal port", port);
rep= &re_table[port];
re_client= mp->DL_PROC;
rep->re_client= re_client;
assert(rep->re_mode == REM_ENABLED);
assert(rep->re_flags & REF_ENABLED);
if (from_int)
{
assert(rep->re_flags & REF_SEND_AVAIL);
rep->re_flags &= ~REF_SEND_AVAIL;
rep->re_send_int= FALSE;
rep->re_tx_alive= TRUE;
}
tx_head= rep->re_tx_head;
if (rep->re_tx[tx_head].ret_busy)
{
assert(!(rep->re_flags & REF_SEND_AVAIL));
rep->re_flags |= REF_SEND_AVAIL;
if (rep->re_tx[tx_head].ret_busy)
goto suspend;
/* Race condition, the interrupt handler may clear re_busy
* before we got a chance to set REF_SEND_AVAIL. Checking
* ret_busy twice should be sufficient.
*/
#if 0
printf("rl_writev: race detected\n");
#endif
rep->re_flags &= ~REF_SEND_AVAIL;
rep->re_send_int= FALSE;
}
assert(!(rep->re_flags & REF_SEND_AVAIL));
assert(!(rep->re_flags & REF_PACK_SENT));
if (vectored)
{
int iov_offset = 0;
size= 0;
ret = rep->re_tx[tx_head].v_ret_buf;
for (i= 0; i<count; i += IOVEC_NR,
iov_src += IOVEC_NR * sizeof(rep->re_iovec[0]),
iov_offset += IOVEC_NR * sizeof(rep->re_iovec[0]))
{
n= IOVEC_NR;
if (i+n > count)
n= count-i;
cps = sys_vircopy(re_client, D, ((vir_bytes) mp->DL_ADDR) + iov_offset,
SELF, D, (vir_bytes) rep->re_iovec,
n * sizeof(rep->re_iovec[0]));
if (cps != OK) printf("RTL8139: warning, sys_vircopy failed: %d\n", cps);
for (j= 0, iovp= rep->re_iovec; j<n; j++, iovp++)
{
s= iovp->iov_size;
@ -1369,18 +1583,10 @@ int vectored;
if (OK != sys_umap(re_client, D, iovp->iov_addr, s, &phys_user))
panic("rtl8139","umap_local failed\n", NO_NUM);
#if 0
cps = sys_abscopy(phys_user, p, s);
if (cps != OK) printf("RTL8139: warning, sys_abscopy failed: %d\n", cps);
#else
cps = sys_vircopy(re_client, D, iovp->iov_addr,
SELF, D, (vir_bytes) ret, s);
if (cps != OK) printf("RTL8139: warning, sys_vircopy failed: %d\n", cps);
#endif
size += s;
#if 0
p += s;
#endif
ret += s;
}
}
@ -1392,19 +1598,10 @@ int vectored;
size= mp->DL_COUNT;
if (size < ETH_MIN_PACK_SIZE || size > ETH_MAX_PACK_SIZE_TAGGED)
panic("rtl8139","invalid packet size", size);
#if 0
if (OK != sys_umap(re_client, D, (vir_bytes)mp->DL_ADDR, size, &phys_user))
panic("rtl8139","umap_local failed\n", NO_NUM);
p= rep->re_tx[tx_head].ret_buf;
cps = sys_abscopy(phys_user, p, size);
if (cps != OK) printf("RTL8139: warning, sys_abscopy failed: %d\n", cps);
#else
ret = rep->re_tx[tx_head].v_ret_buf;
cps = sys_vircopy(re_client, D, (vir_bytes)mp->DL_ADDR,
SELF, D, (vir_bytes) ret, size);
if (cps != OK) printf("RTL8139: warning, sys_abscopy failed: %d\n", cps);
#endif
}
rl_outl(rep->re_base_port, RL_TSD0+tx_head*4,
@ -1446,6 +1643,143 @@ suspend:
reply(rep, OK, FALSE);
}
/*===========================================================================*
* rl_writev_s *
*===========================================================================*/
static void rl_writev_s(mp, from_int)
message *mp;
int from_int;
{
phys_bytes iov_src;
int i, j, n, s, port, count, size;
int tx_head, re_client;
re_t *rep;
iovec_s_t *iovp;
char *ret;
int cps;
int iov_offset = 0;
port = mp->DL_PORT;
count = mp->DL_COUNT;
if (port < 0 || port >= RE_PORT_NR)
panic("rtl8139","illegal port", port);
rep= &re_table[port];
re_client= mp->DL_PROC;
rep->re_client= re_client;
assert(rep->re_mode == REM_ENABLED);
assert(rep->re_flags & REF_ENABLED);
if (from_int)
{
assert(rep->re_flags & REF_SEND_AVAIL);
rep->re_flags &= ~REF_SEND_AVAIL;
rep->re_send_int= FALSE;
rep->re_tx_alive= TRUE;
}
tx_head= rep->re_tx_head;
if (rep->re_tx[tx_head].ret_busy)
{
assert(!(rep->re_flags & REF_SEND_AVAIL));
rep->re_flags |= REF_SEND_AVAIL;
if (rep->re_tx[tx_head].ret_busy)
goto suspend;
/* Race condition, the interrupt handler may clear re_busy
* before we got a chance to set REF_SEND_AVAIL. Checking
* ret_busy twice should be sufficient.
*/
#if 0
printf("rl_writev: race detected\n");
#endif
rep->re_flags &= ~REF_SEND_AVAIL;
rep->re_send_int= FALSE;
}
assert(!(rep->re_flags & REF_SEND_AVAIL));
assert(!(rep->re_flags & REF_PACK_SENT));
size= 0;
ret = rep->re_tx[tx_head].v_ret_buf;
for (i= 0; i<count; i += IOVEC_NR,
iov_src += IOVEC_NR * sizeof(rep->re_iovec_s[0]),
iov_offset += IOVEC_NR * sizeof(rep->re_iovec_s[0]))
{
n= IOVEC_NR;
if (i+n > count)
n= count-i;
cps = sys_safecopyfrom(re_client, mp->DL_GRANT, iov_offset,
(vir_bytes) rep->re_iovec_s,
n * sizeof(rep->re_iovec_s[0]), D);
if (cps != OK)
{
panic(__FILE__, "rl_writev_s: sys_safecopyfrom failed",
cps);
}
for (j= 0, iovp= rep->re_iovec_s; j<n; j++, iovp++)
{
s= iovp->iov_size;
if (size + s > ETH_MAX_PACK_SIZE_TAGGED)
{
panic("rtl8139","invalid packet size",
NO_NUM);
}
cps = sys_safecopyfrom(re_client, iovp->iov_grant, 0,
(vir_bytes) ret, s, D);
if (cps != OK)
{
panic(__FILE__,
"rl_writev_s: sys_safecopyfrom failed",
cps);
}
size += s;
ret += s;
}
}
if (size < ETH_MIN_PACK_SIZE)
panic("rtl8139","invalid packet size", size);
rl_outl(rep->re_base_port, RL_TSD0+tx_head*4,
rep->re_ertxth | size);
rep->re_tx[tx_head].ret_busy= TRUE;
if (++tx_head == N_TX_BUF)
tx_head= 0;
assert(tx_head < RL_N_TX);
rep->re_tx_head= tx_head;
rep->re_flags |= REF_PACK_SENT;
/* If the interrupt handler called, don't send a reply. The reply
* will be sent after all interrupts are handled.
*/
if (from_int)
return;
reply(rep, OK, FALSE);
return;
suspend:
#if 0
printf("rl_writev: head %d, tail %d, busy: %d %d %d %d\n",
tx_head, rep->re_tx_tail,
rep->re_tx[0].ret_busy, rep->re_tx[1].ret_busy,
rep->re_tx[2].ret_busy, rep->re_tx[3].ret_busy);
printf("rl_writev: TSD: 0x%x, 0x%x, 0x%x, 0x%x\n",
rl_inl(rep->re_base_port, RL_TSD0+0*4),
rl_inl(rep->re_base_port, RL_TSD0+1*4),
rl_inl(rep->re_base_port, RL_TSD0+2*4),
rl_inl(rep->re_base_port, RL_TSD0+3*4));
#endif
if (from_int)
panic("rtl8139","should not be sending\n", NO_NUM);
rep->re_tx_mess= *mp;
reply(rep, OK, FALSE);
}
/*===========================================================================*
* rl_check_ints *
*===========================================================================*/
@ -1503,6 +1837,10 @@ re_t *rep;
rl_readv(&rep->re_rx_mess, TRUE /* from int */,
TRUE /* vectored */);
}
else if (rep->re_rx_mess.m_type == DL_READV_S)
{
rl_readv_s(&rep->re_rx_mess, TRUE /* from int */);
}
else
{
assert(rep->re_rx_mess.m_type == DL_READ);
@ -1898,7 +2236,7 @@ re_t *rep;
static void rl_getstat(mp)
message *mp;
{
int port;
int r, port;
eth_stat_t stats;
re_t *rep;
@ -1913,8 +2251,38 @@ message *mp;
stats= rep->re_stat;
put_userdata(mp->DL_PROC, (vir_bytes) mp->DL_ADDR,
(vir_bytes) sizeof(stats), &stats);
r = sys_datacopy(SELF, (vir_bytes) &stats, mp->DL_PROC,
(vir_bytes) mp->DL_ADDR, sizeof(stats));
if (r != OK)
panic(__FILE__, "rl_getstat: sys_datacopy failed", r);
reply(rep, OK, FALSE);
}
/*===========================================================================*
* rl_getstat_s *
*===========================================================================*/
static void rl_getstat_s(mp)
message *mp;
{
int r, port;
eth_stat_t stats;
re_t *rep;
port = mp->DL_PORT;
if (port < 0 || port >= RE_PORT_NR)
panic("rtl8139","illegal port", port);
rep= &re_table[port];
rep->re_client= mp->DL_PROC;
assert(rep->re_mode == REM_ENABLED);
assert(rep->re_flags & REF_ENABLED);
stats= rep->re_stat;
r = sys_safecopyto(mp->DL_PROC, mp->DL_GRANT, 0,
(vir_bytes) &stats, sizeof(stats), D);
if (r != OK)
panic(__FILE__, "rl_getstat_s: sys_safecopyto failed", r);
reply(rep, OK, FALSE);
}
@ -1994,20 +2362,6 @@ message *reply_mess;
panic("rtl8139","unable to mess_reply", NO_NUM);
}
/*===========================================================================*
* put_userdata *
*===========================================================================*/
static void put_userdata(user_proc, user_addr, count, loc_addr)
int user_proc;
vir_bytes user_addr;
vir_bytes count;
void *loc_addr;
{
int cps;
cps = sys_datacopy(SELF, (vir_bytes) loc_addr, user_proc, user_addr, count);
if (cps != OK) printf("RTL8139: warning, scopy failed: %d\n", cps);
}
#if 0
static void dump_phy(rep)
re_t *rep;