dec21140A: use new libnetdriver

Change-Id: I54be3b770e4d1fd320200c30e9e9073a7c1b405b
This commit is contained in:
David van Moolenbroek 2014-12-02 14:01:20 +00:00
parent b80fc5be89
commit 29018b4ecd
2 changed files with 202 additions and 637 deletions

View File

@ -12,288 +12,105 @@
#include <minix/drivers.h>
#include <minix/netdriver.h>
#include <assert.h>
#include <machine/pci.h>
#include <minix/syslib.h>
#include <minix/endpoint.h>
#include <minix/com.h>
#include <minix/sef.h>
#include <minix/ds.h>
#include <net/gen/ether.h>
#include <net/gen/eth_io.h>
#include <stdlib.h>
#include <assert.h>
#include "dec21140A.h"
static u32_t io_inl(u16_t);
static void io_outl(u16_t, u32_t);
static void do_conf(const message *);
static void do_get_stat_s(message *);
static void do_interrupt(const dpeth_t *);
static void do_reply(dpeth_t *);
static void do_vread_s(const message *, int);
static void do_watchdog(void *);
static void de_update_conf(dpeth_t *);
static int de_probe(dpeth_t *, int skip);
static void de_conf_addr(dpeth_t *);
static void de_first_init(dpeth_t *);
static int do_init(unsigned int, ether_addr_t *);
static void do_stop(void);
static int do_send(struct netdriver_data *, size_t);
static ssize_t do_recv(struct netdriver_data *, size_t);
static void do_stat(eth_stat_t *);
static void do_intr(unsigned int);
static int de_probe(dpeth_t *, unsigned int skip);
static void de_conf_addr(dpeth_t *, ether_addr_t *);
static void de_init_buf(dpeth_t *);
static void de_reset(const dpeth_t *);
static void de_hw_conf(const dpeth_t *);
static void de_start(const dpeth_t *);
static void de_setup_frame(const dpeth_t *);
static void de_setup_frame(const dpeth_t *, const ether_addr_t *);
static u16_t de_read_rom(const dpeth_t *, u8_t, u8_t);
static int de_calc_iov_size(iovec_dat_s_t *);
static void de_next_iov(iovec_dat_s_t *);
static void do_vwrite_s(const message *, int);
static void de_get_userdata_s(int, cp_grant_id_t, vir_bytes, int, void
*);
/* Error messages */
static char str_CopyErrMsg[] = "unable to read/write user data";
static char str_SendErrMsg[] = "send failed";
static char str_SizeErrMsg[] = "illegal packet size";
static char str_UmapErrMsg[] = "Unable to sys_umap";
static char str_BusyErrMsg[] = "Send/Recv failed: busy";
static char str_StatErrMsg[] = "Unable to send stats";
static char str_AlignErrMsg[] = "Bad align of buffer/descriptor";
static char str_DevName[] = "dec21140A:eth#?";
static dpeth_t de_state;
static int de_instance;
/* SEF functions and variables. */
static void sef_local_startup(void);
static int sef_cb_init_fresh(int type, sef_init_info_t *info);
static const struct netdriver de_table = {
.ndr_init = do_init,
.ndr_stop = do_stop,
.ndr_recv = do_recv,
.ndr_send = do_send,
.ndr_stat = do_stat,
.ndr_intr = do_intr
};
/*===========================================================================*
* main *
*===========================================================================*/
int main(int argc, char *argv[])
{
dpeth_t *dep;
message m;
int ipc_status;
int r;
/* SEF local startup. */
env_setargs(argc, argv);
sef_local_startup();
while (TRUE)
{
if ((r= netdriver_receive(ANY, &m, &ipc_status)) != OK)
panic("netdriver_receive failed: %d", r);
netdriver_task(&de_table);
if(is_ipc_notify(ipc_status)) {
switch(_ENDPOINT_P(m.m_source)) {
case CLOCK:
do_watchdog(&m);
break;
case HARDWARE:
dep = &de_state;
if (dep->de_mode == DEM_ENABLED) {
do_interrupt(dep);
if (dep->de_flags & (DEF_ACK_SEND | DEF_ACK_RECV))
do_reply(dep);
sys_irqenable(&dep->de_hook);
}
break;
default:
printf("ignoring notify from %d\n", m.m_source);
break;
}
continue;
}
switch (m.m_type)
{
case DL_WRITEV_S: do_vwrite_s(&m, FALSE); break;
case DL_READV_S: do_vread_s(&m, FALSE); break;
case DL_CONF: do_conf(&m); break;
case DL_GETSTAT_S: do_get_stat_s(&m); break;
default:
printf("message 0x%x; %d from %d\n",
m.m_type, m.m_type-DL_RQ_BASE, m.m_source);
panic("illegal message: %d", m.m_type);
}
}
return 0;
}
/*===========================================================================*
* sef_local_startup *
*===========================================================================*/
static void sef_local_startup()
static void de_init_hw(dpeth_t *dep, ether_addr_t *addr)
{
/* Register init callbacks. */
sef_setcb_init_fresh(sef_cb_init_fresh);
sef_setcb_init_lu(sef_cb_init_fresh);
sef_setcb_init_restart(sef_cb_init_fresh);
de_reset(dep);
de_conf_addr(dep, addr);
de_init_buf(dep);
/* Register live update callbacks. */
sef_setcb_lu_prepare(sef_cb_lu_prepare_always_ready);
sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid_workfree);
/* Set the interrupt handler policy. Request interrupts not to be reenabled
* automatically. Return the IRQ line number when an interrupt occurs.
*/
dep->de_hook = dep->de_irq;
sys_irqsetpolicy(dep->de_irq, 0, &dep->de_hook);
sys_irqenable(&dep->de_hook);
/* Register signal callbacks. */
sef_setcb_signal_handler(sef_cb_signal_handler_term);
/* Let SEF perform startup. */
sef_startup();
de_reset(dep);
de_hw_conf(dep);
de_setup_frame(dep, addr);
de_start(dep);
}
/*===========================================================================*
* sef_cb_init_fresh *
*===========================================================================*/
static int sef_cb_init_fresh(int type, sef_init_info_t *UNUSED(info))
static int do_init(unsigned int instance, ether_addr_t *addr)
{
/* Initialize the DEC 21140A driver. */
int fkeys, sfkeys;
long v;
dpeth_t *dep;
v = 0;
(void) env_parse("instance", "d", 0, &v, 0, 255);
de_instance = (int) v;
dep = &de_state;
memset(dep, 0, sizeof(*dep));
/* Request function key for debug dumps */
fkeys = sfkeys = 0;
bit_set(sfkeys, DE_FKEY);
if ((fkey_map(&fkeys, &sfkeys)) != OK)
printf("%s: error using Shift+F%d key(%d)\n", str_DevName, DE_FKEY, errno);
strlcpy(dep->de_name, "dec21140A:?", sizeof(dep->de_name));
dep->de_name[strlen(dep->de_name)-1] = '0' + instance;
/* Announce we are up! */
netdriver_announce();
de_instance = instance;
if (!de_probe(dep, instance))
return ENXIO;
de_init_hw(dep, addr);
return OK;
}
static void do_get_stat_s(message * mp)
static void do_stat(eth_stat_t *stat)
{
int rc;
dpeth_t *dep;
dep = &de_state;
if ((rc = sys_safecopyto(mp->m_source, mp->m_net_netdrv_dl_getstat_s.grant,
0, (vir_bytes)&dep->de_stat, sizeof(dep->de_stat))) != OK)
panic("%s %d", str_CopyErrMsg, rc);
mp->m_type = DL_STAT_REPLY;
rc = ipc_send(mp->m_source, mp);
if( rc != OK )
panic("%s %d", str_StatErrMsg, rc);
return;
memcpy(stat, &de_state.de_stat, sizeof(*stat));
}
static void do_conf(const message * mp)
static int de_probe(dpeth_t *dep, unsigned int skip)
{
int r;
dpeth_t *dep;
message reply_mess;
dep = &de_state;
strncpy(dep->de_name, str_DevName, strlen(str_DevName));
dep->de_name[strlen(dep->de_name)-1] = '0' + de_instance;
if (dep->de_mode == DEM_DISABLED) {
de_update_conf(dep);
pci_init();
if (dep->de_mode == DEM_ENABLED && !de_probe(dep, de_instance)) {
printf("%s: warning no ethernet card found at 0x%04X\n",
dep->de_name, dep->de_base_port);
dep->de_mode = DEM_DISABLED;
}
}
r = OK;
/* 'de_mode' may change if probe routines fail, test again */
switch (dep->de_mode) {
case DEM_DISABLED:
r = ENXIO; /* Device is OFF or hardware probe failed */
break;
case DEM_ENABLED:
if (dep->de_flags == DEF_EMPTY) {
de_first_init(dep);
dep->de_flags |= DEF_ENABLED;
de_reset(dep);
de_hw_conf(dep);
de_setup_frame(dep);
de_start(dep);
}
/* TODO CHECK PROMISC AND MULTI */
dep->de_flags &= NOT(DEF_PROMISC | DEF_MULTI | DEF_BROAD);
if (mp->m_net_netdrv_dl_conf.mode & DL_PROMISC_REQ)
dep->de_flags |= DEF_PROMISC | DEF_MULTI | DEF_BROAD;
if (mp->m_net_netdrv_dl_conf.mode & DL_MULTI_REQ)
dep->de_flags |= DEF_MULTI;
if (mp->m_net_netdrv_dl_conf.mode & DL_BROAD_REQ)
dep->de_flags |= DEF_BROAD;
break;
case DEM_SINK:
DEBUG(printf("%s running in sink mode\n", str_DevName));
memset(dep->de_address.ea_addr, 0, sizeof(ether_addr_t));
de_conf_addr(dep);
break;
default: break;
}
reply_mess.m_type = DL_CONF_REPLY;
reply_mess.m_netdrv_net_dl_conf.stat = r;
if(r == OK){
memcpy(reply_mess.m_netdrv_net_dl_conf.hw_addr, dep->de_address.ea_addr,
sizeof(reply_mess.m_netdrv_net_dl_conf.hw_addr));
}
if (ipc_send(mp->m_source, &reply_mess) != OK)
panic("%s %d", str_SendErrMsg, mp->m_source);
return;
}
static void do_reply(dpeth_t * dep)
{
message reply;
int r, flags = DL_NOFLAGS;
if (dep->de_flags & DEF_ACK_SEND) flags |= DL_PACK_SEND;
if (dep->de_flags & DEF_ACK_RECV) flags |= DL_PACK_RECV;
reply.m_type = DL_TASK_REPLY;
reply.m_netdrv_net_dl_task.flags = flags;
reply.m_netdrv_net_dl_task.count = dep->de_read_s;
r = ipc_send(dep->de_client, &reply);
if(r < 0)
panic("%s %d", str_SendErrMsg, r);
dep->de_read_s = 0;
dep->de_flags &= NOT(DEF_ACK_SEND | DEF_ACK_RECV);
return;
}
static void do_watchdog(void *UNUSED(message))
{
/* nothing here yet */
return;
}
static int de_probe(dpeth_t *dep, int skip)
{
int i, r, devind;
u16_t vid, did, temp16;
int r, devind;
u16_t vid, did;
DEBUG(printf("PROBING..."));
pci_init();
r= pci_first_dev(&devind, &vid, &did);
if (r == 0)
return FALSE;
@ -321,33 +138,15 @@ static int de_probe(dpeth_t *dep, int skip)
/* device validation. We support only the DEC21140A */
if(dep->de_type != DEC_21140A){
dep->de_type = DE_TYPE_UNKNOWN;
printf("%s: unsupported device\n", str_DevName);
printf("%s: unsupported card type %x\n", dep->de_name, dep->de_type);
return FALSE;
}
de_reset(dep);
DEBUG(printf("Reading SROM...\n"));
for(i=0;i<(1<<SROM_BITWIDTH)-1;i++){
temp16 = de_read_rom(dep, i, SROM_BITWIDTH);
dep->srom[i*2] = temp16 & 0xFF;
dep->srom[i*2+1] = temp16 >> 8;
}
/* TODO: validate SROM content */
/* acquire MAC addr */
DEBUG(printf("Using MAC addr= "));
for(i=0;i<6;i++){
dep->de_address.ea_addr[i] = dep->srom[i+DE_SROM_EA_OFFSET];
DEBUG(printf("%02X%c",dep->de_address.ea_addr[i],i!=5?'-':'\n'));
}
DEBUG(printf("probe success\n"));
return TRUE;
}
static u16_t de_read_rom(const dpeth_t *dep, u8_t addr, u8_t nbAddrBits){
static u16_t de_read_rom(const dpeth_t *dep, u8_t addr, u8_t nbAddrBits)
{
u16_t retVal = 0;
int i;
u32_t csr = 0;
@ -356,7 +155,11 @@ static u16_t de_read_rom(const dpeth_t *dep, u8_t addr, u8_t nbAddrBits){
more readable, the following macro is also just
to clear up the code a little.*/
#define EMIT do { io_outl(CSR_ADDR(dep, CSR9), csr | csr2); io_outl(CSR_ADDR(dep, CSR1), 0);} while(0)
#define EMIT \
do { \
io_outl(CSR_ADDR(dep, CSR9), csr | csr2); \
io_outl(CSR_ADDR(dep, CSR1), 0); \
} while(0)
/* init */
csr = 0; EMIT;
@ -404,180 +207,87 @@ static u16_t de_read_rom(const dpeth_t *dep, u8_t addr, u8_t nbAddrBits){
return retVal;
}
static void de_update_conf(dpeth_t * dep)
static ssize_t do_recv(struct netdriver_data *data, size_t max)
{
static char dpc_fmt[] = "x:d:x";
char ec_key[16];
long val;
strlcpy(ec_key, "DEETH0", sizeof(ec_key));
ec_key[5] += de_instance;
dep->de_mode = DEM_ENABLED;
switch (env_parse(ec_key, dpc_fmt, 0, &val, 0x000L, 0x3FFL)) {
case EP_OFF: dep->de_mode = DEM_DISABLED; break;
case EP_ON: dep->de_mode = DEM_SINK; break;
}
dep->de_base_port = 0;
return;
}
static void do_vread_s(const message * mp, int from_int)
{
u8_t *buffer;
u32_t size;
int r, ix = 0;
vir_bytes bytes;
dpeth_t *dep = NULL;
de_loc_descr_t *descr = NULL;
iovec_dat_s_t *iovp = NULL;
dpeth_t *dep;
de_loc_descr_t *descr;
dep = &de_state;
dep->de_client = mp->m_source;
descr = &dep->descr[DESCR_RECV][dep->cur_descr[DESCR_RECV]];
if (dep->de_mode == DEM_ENABLED) {
/* check if packet is in the current descr and only there */
if ((descr->descr->des[DES0] & DES0_OWN) ||
!(descr->descr->des[DES0] & DES0_FS) ||
!(descr->descr->des[DES0] & DES0_LS))
return SUSPEND;
descr = &dep->descr[DESCR_RECV][dep->cur_descr[DESCR_RECV]];
/*TODO: multi-descr msgs...*/
/* We only support packets contained in a single descriptor.
Setting the descriptor buffer size to less then
ETH_MAX_PACK_SIZE will result in multi-descriptor
packets that we won't be able to handle
*/
/* check if packet is in the current descr and only there */
if( !( !(descr->descr->des[DES0] & DES0_OWN) &&
(descr->descr->des[DES0] & DES0_FS) &&
(descr->descr->des[DES0] & DES0_LS) ))
goto suspend;
/* Check for abnormal messages. We assert here
because this driver is for a virtualized
envrionment where we will not get bad packets
*/
assert(!(descr->descr->des[DES0]&DES0_ES));
assert(!(descr->descr->des[DES0]&DES0_RE));
/* Copy buffer to user area and clear ownage */
size = (descr->descr->des[DES0]&DES0_FL)>>DES0_FL_SHIFT;
/*TODO: multi-descr msgs...*/
/* We only support packets contained in a single descriptor.
Setting the descriptor buffer size to less then
ETH_MAX_PACK_SIZE will result in multi-descriptor
packets that we won't be able to handle
*/
assert(!(descr->descr->des[DES0]&DES0_OWN));
assert(descr->descr->des[DES0]&DES0_FS);
assert(descr->descr->des[DES0]&DES0_LS);
/* Check for abnormal messages. We assert here
because this driver is for a virtualized
envrionment where we will not get bad packets
*/
assert(!(descr->descr->des[DES0]&DES0_ES));
assert(!(descr->descr->des[DES0]&DES0_RE));
/* Setup the iovec entry to allow copying into
client layer
*/
dep->de_read_iovec.iod_proc_nr = mp->m_source;
de_get_userdata_s(mp->m_source, mp->m_net_netdrv_dl_readv_s.grant, 0,
mp->m_net_netdrv_dl_readv_s.count,
dep->de_read_iovec.iod_iovec);
dep->de_read_iovec.iod_iovec_s = mp->m_net_netdrv_dl_readv_s.count;
dep->de_read_iovec.iod_grant = mp->m_net_netdrv_dl_readv_s.grant;
dep->de_read_iovec.iod_iovec_offset = 0;
size = de_calc_iov_size(&dep->de_read_iovec);
if (size < ETH_MAX_PACK_SIZE)
panic("%s %d", str_SizeErrMsg, size);
/* Copy buffer to user area and clear ownage */
size = (descr->descr->des[DES0]&DES0_FL)>>DES0_FL_SHIFT;
/*TODO: Complain to MS */
/*HACK: VPC2007 returns packet of invalid size. Ethernet standard
specify 46 bytes as the minimum for valid payload. However, this is
artificial in so far as for certain packet types, notably ARP, less
then 46 bytes are needed to contain the full information. In a non
virtualized environment the 46 bytes rule is enforced in order to give
guarantee in the collison detection scheme. Of course, this being a
driver for a VPC2007, we won't have collisions and I can only suppose
MS decided to cut packet size to true minimum, regardless of the
46 bytes payload standard. Note that this seems to not happen in
bridged mode. Note also, that the card does not return runt or
incomplete frames to us, so this hack is safe
*/
if(size<60){
memset(&descr->buf1[size], 0, 60-size);
size=60;
}
/* End ugly hack */
iovp = &dep->de_read_iovec;
buffer = descr->buf1;
dep->bytes_rx += size;
dep->de_stat.ets_packetR++;
dep->de_read_s = size;
do {
bytes = iovp->iod_iovec[ix].iov_size; /* Size of buffer */
if (bytes >= size)
bytes = size;
r= sys_safecopyto(iovp->iod_proc_nr, iovp->iod_iovec[ix].iov_grant, 0,
(vir_bytes)buffer, bytes);
if (r != OK)
panic("%s %d", str_CopyErrMsg, r);
buffer += bytes;
if (++ix >= IOVEC_NR) { /* Next buffer of IO vector */
de_next_iov(iovp);
ix = 0;
}
} while ((size -= bytes) > 0);
descr->descr->des[DES0]=DES0_OWN;
dep->cur_descr[DESCR_RECV]++;
if(dep->cur_descr[DESCR_RECV] >= DE_NB_RECV_DESCR)
dep->cur_descr[DESCR_RECV] = 0;
DEBUG(printf("Read returned size = %d\n", size));
/* Reply information */
dep->de_flags |= DEF_ACK_RECV;
dep->de_flags &= NOT(DEF_READING);
/* HACK: VPC2007 sends short-sized packets, pad to minimum ethernet length */
if(size<60){
memset(&descr->buf1[size], 0, 60-size);
size=60;
}
if(!from_int){
do_reply(dep);
}
return;
/* Truncate large packets */
if (size > max)
size = max;
suspend:
if(from_int){
assert(dep->de_flags & DEF_READING);
return;
}
netdriver_copyout(data, 0, descr->buf1, size);
assert(!(dep->de_flags & DEF_READING));
dep->rx_return_msg = *mp;
dep->de_flags |= DEF_READING;
do_reply(dep);
return;
dep->de_stat.ets_packetR++;
descr->descr->des[DES0]=DES0_OWN;
dep->cur_descr[DESCR_RECV]++;
if(dep->cur_descr[DESCR_RECV] >= DE_NB_RECV_DESCR)
dep->cur_descr[DESCR_RECV] = 0;
DEBUG(printf("Read returned size = %d\n", size));
return size;
}
static void de_conf_addr(dpeth_t * dep)
static void de_conf_addr(dpeth_t *dep, ether_addr_t *addr)
{
static char ea_fmt[] = "x:x:x:x:x:x";
char ea_key[16];
int ix;
long val;
u16_t temp16;
int i;
strlcpy(ea_key, "DEETH0_EA", sizeof(ea_key));
ea_key[5] += de_instance;
DEBUG(printf("Reading SROM...\n"));
for (ix = 0; ix < SA_ADDR_LEN; ix++) {
val = dep->de_address.ea_addr[ix];
if (env_parse(ea_key, ea_fmt, ix, &val, 0x00L, 0xFFL) != EP_SET)
break;
dep->de_address.ea_addr[ix] = val;
for(i=0;i<(1<<SROM_BITWIDTH)-1;i++){
temp16 = de_read_rom(dep, i, SROM_BITWIDTH);
dep->srom[i*2] = temp16 & 0xFF;
dep->srom[i*2+1] = temp16 >> 8;
}
if (ix != 0 && ix != SA_ADDR_LEN)
env_parse(ea_key, "?", 0, &val, 0L, 0L);
return;
/* TODO: validate SROM content */
/* acquire MAC addr */
DEBUG(printf("Using MAC addr= "));
for(i=0;i<6;i++){
addr->ea_addr[i] = dep->srom[i+DE_SROM_EA_OFFSET];
DEBUG(printf("%02X%c", addr->ea_addr[i],i!=5?'-':'\n'));
}
DEBUG(printf("probe success\n"));
}
static void de_first_init(dpeth_t *dep)
static void de_init_buf(dpeth_t *dep)
{
int i,j,r;
vir_bytes descr_vir = (vir_bytes)dep->sendrecv_descr_buf;
@ -585,7 +295,6 @@ static void de_first_init(dpeth_t *dep)
de_loc_descr_t *loc_descr;
phys_bytes temp;
for(i=0;i<2;i++){
loc_descr = &dep->descr[i][0];
for(j=0; j < (i==DESCR_RECV ? DE_NB_RECV_DESCR : DE_NB_SEND_DESCR); j++){
@ -627,11 +336,11 @@ static void de_first_init(dpeth_t *dep)
/* record physical location of two first descriptor */
r = sys_umap(SELF, VM_D, (vir_bytes)dep->descr[DESCR_RECV][0].descr,
sizeof(de_descr_t), &dep->sendrecv_descr_phys_addr[DESCR_RECV]);
if(r != OK) panic("%s %d", str_UmapErrMsg, r);
if(r != OK) panic("sys_umap failed: %d", r);
r = sys_umap(SELF, VM_D, (vir_bytes)dep->descr[DESCR_TRAN][0].descr,
sizeof(de_descr_t), &dep->sendrecv_descr_phys_addr[DESCR_TRAN]);
if(r != OK) panic("%s %d", str_UmapErrMsg, r);
if(r != OK) panic("sys_umap failed: %d", r);
DEBUG(printf("Descr: head tran=[%08X] head recv=[%08X]\n",
dep->sendrecv_descr_phys_addr[DESCR_TRAN],
@ -643,13 +352,12 @@ static void de_first_init(dpeth_t *dep)
for(j=0;j< (i==DESCR_RECV?DE_NB_RECV_DESCR:DE_NB_SEND_DESCR);j++){
r = sys_umap(SELF, VM_D, (vir_bytes)&(loc_descr->descr),
sizeof(de_descr_t), &temp);
if(r != OK)
panic("%s %d", str_UmapErrMsg, r);
if(r != OK) panic("sys_umap failed: %d", r);
if( ((loc_descr->descr->des[DES_BUF1] & 0x3) != 0) ||
((loc_descr->descr->des[DES_BUF2] & 0x3) != 0) ||
((temp&0x3)!=0) )
panic("%s 0x%lx", str_AlignErrMsg, temp);
panic("alignment error: 0x%lx", temp);
loc_descr++;
}
@ -658,43 +366,45 @@ static void de_first_init(dpeth_t *dep)
/* Init default values */
dep->cur_descr[DESCR_TRAN]=1;
dep->cur_descr[DESCR_RECV]=0;
dep->bytes_rx = 0;
dep->bytes_tx = 0;
/* Set the interrupt handler policy. Request interrupts not to be reenabled
* automatically. Return the IRQ line number when an interrupt occurs.
*/
dep->de_hook = dep->de_irq;
sys_irqsetpolicy(dep->de_irq, 0, &dep->de_hook);
sys_irqenable(&dep->de_hook);
}
static void do_interrupt(const dpeth_t *dep){
static void do_intr(unsigned int __unused mask)
{
dpeth_t *dep;
u32_t val;
dep = &de_state;
val = io_inl(CSR_ADDR(dep, CSR5));
if(val & CSR5_AIS){
panic("Abnormal Int CSR5=: %d", val);
}
if( (dep->de_flags & DEF_READING) && (val & CSR5_RI) ){
do_vread_s(&dep->rx_return_msg, TRUE);
}
if (val & CSR5_RI)
netdriver_recv();
if( (dep->de_flags & DEF_SENDING) && (val & CSR5_TI) ){
do_vwrite_s(&dep->tx_return_msg, TRUE);
}
if (val & CSR5_TI)
netdriver_send();
/* ack and reset interrupts */
io_outl(CSR_ADDR(dep, CSR5), 0xFFFFFFFF);
return;
sys_irqenable(&dep->de_hook);
}
static void de_reset(const dpeth_t *dep){
static void de_reset(const dpeth_t *dep)
{
io_outl(CSR_ADDR(dep, CSR0), CSR0_SWR);
}
static void de_hw_conf(const dpeth_t *dep){
static void do_stop(void)
{
de_reset(&de_state);
}
static void de_hw_conf(const dpeth_t *dep)
{
u32_t val;
/* CSR0 - global host bus prop */
@ -719,13 +429,15 @@ static void de_hw_conf(const dpeth_t *dep){
io_outl(CSR_ADDR(dep, CSR6), val);
}
static void de_start(const dpeth_t *dep){
static void de_start(const dpeth_t *dep)
{
u32_t val;
val = io_inl(CSR_ADDR(dep, CSR6)) | CSR6_ST | CSR6_SR;
io_outl(CSR_ADDR(dep, CSR6), val);
}
static void de_setup_frame(const dpeth_t *dep){
static void de_setup_frame(const dpeth_t *dep, const ether_addr_t *addr)
{
int i;
u32_t val;
@ -739,12 +451,12 @@ static void de_setup_frame(const dpeth_t *dep){
dep->descr[DESCR_TRAN][0].buf1[9] = 0xFF;
for(i=1;i<16;i++){
memset(&(dep->descr[DESCR_TRAN][0].buf1[12*i]), 0, 12);
dep->descr[DESCR_TRAN][0].buf1[12*i+0] = dep->de_address.ea_addr[0];
dep->descr[DESCR_TRAN][0].buf1[12*i+1] = dep->de_address.ea_addr[1];
dep->descr[DESCR_TRAN][0].buf1[12*i+4] = dep->de_address.ea_addr[2];
dep->descr[DESCR_TRAN][0].buf1[12*i+5] = dep->de_address.ea_addr[3];
dep->descr[DESCR_TRAN][0].buf1[12*i+8] = dep->de_address.ea_addr[4];
dep->descr[DESCR_TRAN][0].buf1[12*i+9] = dep->de_address.ea_addr[5];
dep->descr[DESCR_TRAN][0].buf1[12*i+0] = addr->ea_addr[0];
dep->descr[DESCR_TRAN][0].buf1[12*i+1] = addr->ea_addr[1];
dep->descr[DESCR_TRAN][0].buf1[12*i+4] = addr->ea_addr[2];
dep->descr[DESCR_TRAN][0].buf1[12*i+5] = addr->ea_addr[3];
dep->descr[DESCR_TRAN][0].buf1[12*i+8] = addr->ea_addr[4];
dep->descr[DESCR_TRAN][0].buf1[12*i+9] = addr->ea_addr[5];
}
dep->descr[DESCR_TRAN][0].descr->des[DES0] = DES0_OWN;
@ -755,149 +467,55 @@ static void de_setup_frame(const dpeth_t *dep){
val = io_inl(CSR_ADDR(dep, CSR6)) | CSR6_ST;
io_outl(CSR_ADDR(dep, CSR6), val);
io_outl(CSR_ADDR(dep, CSR1), 0xFFFFFFFF);
return;
}
static int de_calc_iov_size(iovec_dat_s_t * iovp){
int size, ix;
size = ix = 0;
do{
size += iovp->iod_iovec[ix].iov_size;
if (++ix >= IOVEC_NR) {
de_next_iov(iovp);
ix = 0;
}
} while (ix < iovp->iod_iovec_s);
return size;
}
static void de_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);
rc = sys_safecopyfrom(user_proc, grant, 0, (vir_bytes)loc_addr, len);
if (rc != OK)
panic("%s %d", str_CopyErrMsg, rc);
return;
}
static void de_next_iov(iovec_dat_s_t * iovp){
iovp->iod_iovec_s -= IOVEC_NR;
iovp->iod_iovec_offset += IOVEC_NR * sizeof(iovec_t);
de_get_userdata_s(iovp->iod_proc_nr, iovp->iod_grant, iovp->iod_iovec_offset,
iovp->iod_iovec_s, iovp->iod_iovec);
return;
}
static void do_vwrite_s(const message * mp, int from_int){
static u8_t setupDone = 0;
int size, r, bytes, ix, totalsize;
static int do_send(struct netdriver_data *data, size_t size)
{
static int setup_done = 0;
dpeth_t *dep;
iovec_dat_s_t *iovp = NULL;
de_loc_descr_t *descr = NULL;
u8_t *buffer = NULL;
dep = &de_state;
dep->de_client = mp->m_source;
descr = &dep->descr[DESCR_TRAN][dep->cur_descr[DESCR_TRAN]];
if (dep->de_mode == DEM_ENABLED) {
if(( descr->descr->des[DES0] & DES0_OWN)!=0)
return SUSPEND;
if (!from_int && (dep->de_flags & DEF_SENDING))
panic("%s", str_BusyErrMsg);
descr = &dep->descr[DESCR_TRAN][dep->cur_descr[DESCR_TRAN]];
if(( descr->descr->des[DES0] & DES0_OWN)!=0)
goto suspend;
if(!setupDone && (dep->cur_descr[DESCR_TRAN] == 0) ){
dep->descr[DESCR_TRAN][0].descr->des[DES0] = 0;
setupDone=1;
}
buffer = descr->buf1;
iovp = &dep->de_write_iovec;
iovp->iod_proc_nr = mp->m_source;
de_get_userdata_s(mp->m_source, mp->m_net_netdrv_dl_writev_s.grant, 0,
mp->m_net_netdrv_dl_writev_s.count, iovp->iod_iovec);
iovp->iod_iovec_s = mp->m_net_netdrv_dl_writev_s.count;
iovp->iod_grant = mp->m_net_netdrv_dl_writev_s.grant;
iovp->iod_iovec_offset = 0;
totalsize = size = de_calc_iov_size(iovp);
if (size < ETH_MIN_PACK_SIZE || size > ETH_MAX_PACK_SIZE)
panic("%s %d", str_SizeErrMsg, size);
dep->bytes_tx += size;
dep->de_stat.ets_packetT++;
ix=0;
do {
bytes = iovp->iod_iovec[ix].iov_size;
if (bytes >= size)
bytes = size;
r= sys_safecopyfrom(iovp->iod_proc_nr, iovp->iod_iovec[ix].iov_grant,
0, (vir_bytes)buffer, bytes);
if (r != OK)
panic("%s %d", str_CopyErrMsg, r);
buffer += bytes;
if (++ix >= IOVEC_NR) {
de_next_iov(iovp);
ix = 0;
}
} while ((size -= bytes) > 0);
descr->descr->des[DES1] = (descr->descr->des[DES1]&DES1_ER) |
DES1_FS | DES1_LS | DES1_IC | totalsize;
descr->descr->des[DES0] = DES0_OWN;
dep->cur_descr[DESCR_TRAN]++;
if(dep->cur_descr[DESCR_TRAN] >= DE_NB_SEND_DESCR)
dep->cur_descr[DESCR_TRAN] = 0;
io_outl(CSR_ADDR(dep, CSR1), 0xFFFFFFFF);
if(!setup_done && (dep->cur_descr[DESCR_TRAN] == 0) ){
dep->descr[DESCR_TRAN][0].descr->des[DES0] = 0;
setup_done=1;
}
dep->de_flags |= DEF_ACK_SEND;
if(from_int){
dep->de_flags &= NOT(DEF_SENDING);
return;
}
do_reply(dep);
return;
netdriver_copyin(data, 0, descr->buf1, size);
suspend:
if(from_int)
panic("should not happen: %d", 0);
descr->descr->des[DES1] = (descr->descr->des[DES1]&DES1_ER) |
DES1_FS | DES1_LS | DES1_IC | size;
descr->descr->des[DES0] = DES0_OWN;
dep->de_stat.ets_transDef++;
dep->de_flags |= DEF_SENDING;
dep->de_stat.ets_transDef++;
dep->tx_return_msg = *mp;
do_reply(dep);
dep->cur_descr[DESCR_TRAN]++;
if(dep->cur_descr[DESCR_TRAN] >= DE_NB_SEND_DESCR)
dep->cur_descr[DESCR_TRAN] = 0;
io_outl(CSR_ADDR(dep, CSR1), 0xFFFFFFFF);
dep->de_stat.ets_packetT++;
return OK;
}
static void warning(const char *type, int err){
printf("Warning: %s sys_%s failed (%d)\n", str_DevName, type, err);
return;
}
static u32_t io_inl(u16_t port){
static u32_t io_inl(u16_t port)
{
u32_t value;
int rc;
if ((rc = sys_inl(port, &value)) != OK) warning("inl", rc);
if ((rc = sys_inl(port, &value)) != OK)
panic("sys_inl failed: %d", rc);
return value;
}
static void io_outl(u16_t port, u32_t value){
static void io_outl(u16_t port, u32_t value)
{
int rc;
if ((rc = sys_outl(port, value)) != OK) warning("outl", rc);
return;
if ((rc = sys_outl(port, value)) != OK)
panic("sys_outl failed: %d", rc);
}

View File

@ -11,37 +11,21 @@ Created: 09/01/2009 Nicolas Tittley (first.last @ gmail DOT com)
#include <sys/null.h>
#define DE_FKEY 7 /* Shift+ this value will dump info on console */
#define NOT(x) (~(x))
#if debug == 1
# define DEBUG(statm) statm
#else
# define DEBUG(statm)
#endif
#define SA_ADDR_LEN sizeof(ether_addr_t)
#define DE_NB_SEND_DESCR 32
#define DE_SEND_BUF_SIZE (ETH_MAX_PACK_SIZE+2)
#define DE_NB_RECV_DESCR 32
#define DE_RECV_BUF_SIZE (ETH_MAX_PACK_SIZE+2)
#define IOVEC_NR 16
#define DE_MIN_BASE_ADDR 0x0400
#define DE_SROM_EA_OFFSET 20
#define DE_SETUP_FRAME_SIZE 192
typedef struct iovec_dat_s {
iovec_s_t iod_iovec[IOVEC_NR];
int iod_iovec_s;
endpoint_t iod_proc_nr;
cp_grant_id_t iod_grant;
vir_bytes iod_iovec_offset;
} iovec_dat_s_t;
typedef struct de_descr {
u32_t des[4];
} de_descr_t;
@ -53,9 +37,6 @@ typedef struct de_local_descr {
} de_loc_descr_t;
typedef struct dpeth {
message rx_return_msg; /* Holds VREAD message until int */
message tx_return_msg; /* Holds VWRITE message until int */
char de_name[32]; /* Name of this interface */
port_t de_base_port; /* Base port, for multiple card instance */
int de_irq; /* IRQ line number */
@ -63,10 +44,7 @@ typedef struct dpeth {
int de_type; /* What kind of hardware */
ether_addr_t de_address; /* Ethernet Address */
eth_stat_t de_stat; /* Stats */
unsigned long bytes_tx; /* Number of bytes sent */
unsigned long bytes_rx; /* Number of bytes recv */
/* Space reservation. We will allocate all structures later in the code.
here we just make sure we have the space we need at compile time */
@ -81,42 +59,11 @@ typedef struct dpeth {
#define DESCR_RECV 0
#define DESCR_TRAN 1
int de_flags; /* Send/Receive mode (Configuration) */
#define DEF_EMPTY 0x0000
#define DEF_READING 0x0001
#define DEF_RECV_BUSY 0x0002
#define DEF_ACK_RECV 0x0004
#define DEF_SENDING 0x0010
#define DEF_XMIT_BUSY 0x0020
#define DEF_ACK_SEND 0x0040
#define DEF_PROMISC 0x0100
#define DEF_MULTI 0x0200
#define DEF_BROAD 0x0400
#define DEF_ENABLED 0x2000
#define DEF_STOPPED 0x4000
int de_mode; /* Status of the Interface */
#define DEM_DISABLED 0x0000
#define DEM_SINK 0x0001
#define DEM_ENABLED 0x0002
/* Serial ROM */
#define SROM_BITWIDTH 6
u8_t srom[((1<<SROM_BITWIDTH)-1)*2]; /* Space to read in
all the configuration ROM */
/* Temporary storage for RECV/SEND requests */
iovec_dat_s_t de_read_iovec;
iovec_dat_s_t de_write_iovec;
vir_bytes de_read_s;
vir_bytes de_send_s;
endpoint_t de_client;
} dpeth_t;