netdriver branch - JENKINS TESTING ONLY

Squashed commit of the following:

commit c1f8bd0351773f101b887beebf1bf8faea047d65
Author: David van Moolenbroek <david@minix3.org>
Date:   Tue Dec 2 14:08:24 2014 +0000

    virtio_net: use new libnetdriver

    Change-Id: Id06bdb67da12477984b42bbd46623bd8f25c0ab9

commit 70b92b94eb2ebd23fe4f0e39708f273fd23df6e9
Author: David van Moolenbroek <david@minix3.org>
Date:   Tue Dec 2 14:06:15 2014 +0000

    rtl8169: use new libnetdriver

    Change-Id: Ia26b6c440a1525f1d2bb9e7592e357dac0ba602c

commit 553a4151f85d4a51a368c1abbc7384f981c25a1d
Author: David van Moolenbroek <david@minix3.org>
Date:   Tue Dec 2 14:07:16 2014 +0000

    rtl8139: use new libnetdriver

    Change-Id: Iba941653b7c052375694bcec2561957c1979feb0

commit 0d5784cf27ba95190c09c885fda1c6c563e87f29
Author: David van Moolenbroek <david@minix3.org>
Date:   Tue Dec 2 14:05:26 2014 +0000

    orinoco: use new libnetdriver

    Change-Id: I003590539dd76f4be8e067f986bb1f17b151490d

commit 84a2c824ace788d3d014a3b4ee0f2d90321eeb8e
Author: David van Moolenbroek <david@minix3.org>
Date:   Tue Dec 2 14:05:09 2014 +0000

    lance: use new libnetdriver

    Change-Id: If3414088e66407c688c4960f99a165b0ee1ebc83

commit b3097036029c3d88a3964362a1fea0d76c4dfa00
Author: David van Moolenbroek <david@minix3.org>
Date:   Tue Dec 2 14:04:33 2014 +0000

    lan8710a: use new libnetdriver

    Change-Id: Iaee4d75a5dfafc72d94f0b02681f9aea1c9da535

commit bed92519b0c5015bac88400f2b13c7836539642d
Author: David van Moolenbroek <david@minix3.org>
Date:   Tue Dec 2 14:04:01 2014 +0000

    fxp: use new libnetdriver

    Change-Id: I03268655a5daff3d109ae52e64673911ef096a3f

commit ba868da1e91b1f8c64dbf918f0572000956f86e2
Author: David van Moolenbroek <david@minix3.org>
Date:   Tue Dec 2 14:03:14 2014 +0000

    e1000: use new libnetdriver

    Change-Id: I111750d2ca27f01039d0b427b1314aea861e2074

commit 668777f3f727722b73654253a66a0fd1ac3e1bbd
Author: David van Moolenbroek <david@minix3.org>
Date:   Tue Dec 2 14:02:46 2014 +0000

    dpeth: use new libnetdriver

    Change-Id: Ic389e54817c5b241dad851c89ef1cf16c015a79b

commit edf59ab3cb55219a93a060fceb8f59b713d75dcd
Author: David van Moolenbroek <david@minix3.org>
Date:   Tue Dec 2 14:02:02 2014 +0000

    dp8390: use new libnetdriver

    Change-Id: Ieaf6d605832d475f95fd9b06026b349dce7ee025

commit d8f11c1f66daaae7d50fe240d216e625472100b0
Author: David van Moolenbroek <david@minix3.org>
Date:   Tue Dec 2 14:01:20 2014 +0000

    dec21140A: use new libnetdriver

    Change-Id: I54be3b770e4d1fd320200c30e9e9073a7c1b405b

commit cc851f55f60ffcaa8cd61df269bd399c3159a78c
Author: David van Moolenbroek <david@minix3.org>
Date:   Tue Dec 2 14:00:04 2014 +0000

    atl2: use new libnetdriver

    Change-Id: I65de5d29a75d5f3101b2c5ab16a4b0d79bd77cc3

commit a50e5606a8cf503c024825ebe56d4b1a3dfd2670
Author: David van Moolenbroek <david@minix3.org>
Date:   Tue Dec 2 13:16:14 2014 +0000

    libnetdriver: turn into network driver framework

    The new implementation of this library provides abstractions for
    network drivers, and should be used for all network drivers from now
    on.  It provides the following functionality:

      - a function call table abstraction, hiding the details of the
        datalink protocol with simple parameters;
      - a state machine for sending and receiving packets, freeing the
        actual driver from keeping track of pending requests;
      - an abstraction for copying data from and to the network driver,
        freeing the actual driver from dealing with I/O vectors while at
        the same time providing a copy implementation which is more
        efficient than most current driver implementations;
      - a generalized implementation of zero-copy port-based I/O;
      - a clearer set of policies and defaults.

    While the concept is very similar to lib{block,char,fs,input}driver,
    one main difference is that libnetdriver now also takes care of SEF
    initialization, mainly so that aspects such as recovery policies and
    live-update aspects can be changed for all network drivers in a
    single place.  As always, for the case that the provided message loop
    is too restrictive, a set of more low-level message processing
    functions is provided.

    The netdriver API has been designed so as to allow alleviation of one
    current protocol bottleneck: the fact that at most one send request
    and one receive request may be pending at any time.  Changing this
    aspect will however require a significant rewrite of libnetdriver,
    and possibly debugging of drivers that are not able to cope with (in
    particular) queuing multiple packets for transmission at once.

    Beyond that, the design of the new API is based on the current
    protocol, and may be changed/extended later to allow for non-ethernet
    network drivers, exposure of link status, multicast address
    configuration, suspend and resume, and any other features that are in
    fact long overdue.

    Change-Id: I47ec47e05852c42f92af04549d41524f928efec2

commit 81cfac6291eaf0db0f66146ecdc2e6cf8c5e05ca
Author: David van Moolenbroek <david@minix3.org>
Date:   Mon Dec 1 17:00:04 2014 +0000

    e1000: convert to KNF

    Change-Id: Ibd156c2e0a58fed70895080d4b230b26c500fa11

commit 400925dd615afbf0ed720779085ee02db65abeab
Author: David van Moolenbroek <david@minix3.org>
Date:   Thu Nov 27 12:59:57 2014 +0000

    atl2: convert to KNF

    Change-Id: Ie4b979aab3127a91a12b8086326da0eb1f9a860b

commit 15e2247939858c826a6395cedac95632e3a8637f
Author: David van Moolenbroek <david@minix3.org>
Date:   Mon Dec 1 17:30:45 2014 +0000

    libvirtio: expose result size on packet dequeue

    Change-Id: I49304678895779849abc2528a9f78730f968e712

commit cf57d76601ac76ff0e4a1a7d5b4f2b1be15bd32d
Author: David van Moolenbroek <david@minix3.org>
Date:   Mon Dec 1 17:21:17 2014 +0000

    orinoco: restore register memory mapping

    Untested.

    Change-Id: I439f0e711e16ba478dadf57ffc8ad74ec19ea1b9

commit d388e231194b9334da2319175383aa9ee7c9e49d
Author: David van Moolenbroek <david@minix3.org>
Date:   Mon Dec 1 17:11:44 2014 +0000

    fxp: enable bus mastering if needed

    This is required for at least QEMU.  However, as of writing, QEMU also
    requires fixes in its epro100 emulator before this driver can use it.

    Change-Id: Ie5c5ffe4311b1a0e581bc687f1c15de3a85f4a30

commit 21e797836a991907f4139874bc740207cd893467
Author: David van Moolenbroek <david@minix3.org>
Date:   Mon Dec 1 17:04:49 2014 +0000

    e1000: fix unaligned register access

    This resolves a guru meditation in recent VirtualBox versions.

    Change-Id: I5034d8af1fe885adda3c027cb23563bffaccf97e

commit e9a2ab30f46660d5385eaf1e9212adcfc34448bc
Author: David van Moolenbroek <david@minix3.org>
Date:   Mon Dec 1 17:50:59 2014 +0000

    dp8390: update, allow default port and IRQ

    Bochs has switched from port base 0x240 to 0x300 for its default
    NE2000 ISA configuration, and QEMU is using the same settings.

    Change-Id: Ide6cdb14321eb4324d0bf6d6314c5970b3493e95

commit 651f2f48e07e532b26c6daaa617aed784006db8e
Author: David van Moolenbroek <david@minix3.org>
Date:   Mon Dec 1 17:35:21 2014 +0000

    etc/usr/rc: fix argument passing for net drivers

    The expected argument name would include the instance number, which
    is not only redundant in many cases (FOOETHn_n=arg.., "n" being the
    instance number) and conflicted with what netconf(8) does, but some
    drivers need to be able to see the arguments for all instances of its
    driver type--for example, dp8390 needs to know how many earlier
    instances have been configured to use PCI.

    Change-Id: I4830b823352722f554a032979464aba8b08fc166

commit 56ba3bb62d74c273e1d8230b9f3dddbb0cd5d4cf
Author: David van Moolenbroek <david@minix3.org>
Date:   Mon Dec 1 17:58:20 2014 +0000

    UDS: move from drivers/net/ to net/

    Change-Id: I53992b205e767a77c7b3c868a38c7f3d772a4ed3

Change-Id: I45f13cf627c0bce0d0d53b2e0e6aab51312106d9
This commit is contained in:
David van Moolenbroek 2014-12-03 10:27:47 +00:00
parent 7f59afadd5
commit 3570bf6aa8
60 changed files with 4394 additions and 9872 deletions

View File

@ -255,7 +255,10 @@ service dp8390
SDEVIO # 22 SDEVIO # 22
; ;
pci device 10ec:8029; pci device 10ec:8029;
uid 0; io
300:20
;
irq 9;
}; };
service dpeth service dpeth

View File

@ -184,7 +184,7 @@ start|autoboot)
for label in $(get_eth_labels); do for label in $(get_eth_labels); do
driver=$(echo $label | sed 's/\(.*\)_.*/\1/') driver=$(echo $label | sed 's/\(.*\)_.*/\1/')
instance=$(echo $label | sed 's/.*_//') instance=$(echo $label | sed 's/.*_//')
eval arg=\$${label}_arg eval arg=\$${driver}_arg
if [ ! -z "$arg" ]; then arg=" $arg"; fi if [ ! -z "$arg" ]; then arg=" $arg"; fi
arg="-args \"instance=$instance$arg\"" arg="-args \"instance=$instance$arg\""
eval up $driver -label $label $arg -period 5HZ eval up $driver -label $label $arg -period 5HZ

View File

@ -109,7 +109,7 @@ cards()
card 0 "No Ethernet card (no networking)" card 0 "No Ethernet card (no networking)"
card 1 "3Com 501 or 3Com 509 based card" card 1 "3Com 501 or 3Com 509 based card"
card 2 "Realtek 8029 based card (also emulated by Qemu)" "10EC:8029" card 2 "Realtek 8029 based card (also emulated by Qemu)" "10EC:8029"
card 3 "NE2000, 3com 503 or WD based card (also emulated by Bochs)" card 3 "NE2000, 3com 503 or WD based card (also emulated by Qemu, Bochs)"
card 4 "lan8710a (on BeagleBone, BeagleBone Black)" card 4 "lan8710a (on BeagleBone, BeagleBone Black)"
n=$first_pcicard n=$first_pcicard
for pcicard in $pci_list for pcicard in $pci_list
@ -197,10 +197,11 @@ drv_params()
test "$v" = 1 && echo "Note: After installing, edit $LOCALRC to the right configuration." test "$v" = 1 && echo "Note: After installing, edit $LOCALRC to the right configuration."
;; ;;
2) driver=dp8390; driverargs="dp8390_arg='DPETH0=pci'"; ;; 2) driver=dp8390; driverargs="dp8390_arg='DPETH0=pci'"; ;;
3) driver=dp8390; driverargs="dp8390_arg='DPETH0=240:9'"; 3) driver=dp8390; driverargs="dp8390_arg='DPETH0=300:9'";
test "$v" = 1 && echo "" test "$v" = 1 && echo ""
test "$v" = 1 && echo "Note: After installing, edit $LOCALRC to the right configuration." test "$v" = 1 && echo "Note: After installing, edit $LOCALRC to the right configuration."
test "$v" = 1 && echo " chose option 4, the defaults for emulation by Bochs have been set." test "$v" = 1 && echo "You may then also have to edit /etc/system.conf ."
test "$v" = 1 && echo "For now, the defaults for emulation by Bochs/Qemu have been set."
;; ;;
4) driver=lan8710a; ;; 4) driver=lan8710a; ;;
$first_after_pci) driver="psip0"; ;; $first_after_pci) driver="psip0"; ;;

View File

@ -18,6 +18,4 @@ SUBDIR+= virtio_net
SUBDIR+= lan8710a SUBDIR+= lan8710a
.endif # ${MACHINE_ARCH} == "earm" .endif # ${MACHINE_ARCH} == "earm"
SUBDIR+= uds
.include <bsd.subdir.mk> .include <bsd.subdir.mk>

File diff suppressed because it is too large Load Diff

View File

@ -179,5 +179,3 @@
#define ATL2_TXS_ABORTCOL 0x04000000 /* collision abort */ #define ATL2_TXS_ABORTCOL 0x04000000 /* collision abort */
#define ATL2_TXS_UNDERRUN 0x08000000 /* buffer underrun */ #define ATL2_TXS_UNDERRUN 0x08000000 /* buffer underrun */
#define ATL2_TXS_UPDATE 0x80000000 /* updated by device */ #define ATL2_TXS_UPDATE 0x80000000 /* updated by device */

View File

@ -12,288 +12,105 @@
#include <minix/drivers.h> #include <minix/drivers.h>
#include <minix/netdriver.h> #include <minix/netdriver.h>
#include <assert.h>
#include <machine/pci.h> #include <machine/pci.h>
#include <minix/syslib.h> #include <assert.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 "dec21140A.h" #include "dec21140A.h"
static u32_t io_inl(u16_t); static u32_t io_inl(u16_t);
static void io_outl(u16_t, u32_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 do_init(unsigned int, ether_addr_t *);
static int de_probe(dpeth_t *, int skip); static void do_stop(void);
static void de_conf_addr(dpeth_t *); static int do_send(struct netdriver_data *, size_t);
static void de_first_init(dpeth_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_reset(const dpeth_t *);
static void de_hw_conf(const dpeth_t *); static void de_hw_conf(const dpeth_t *);
static void de_start(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 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 dpeth_t de_state;
static int de_instance; static int de_instance;
/* SEF functions and variables. */ static const struct netdriver de_table = {
static void sef_local_startup(void); .ndr_init = do_init,
static int sef_cb_init_fresh(int type, sef_init_info_t *info); .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[]) int main(int argc, char *argv[])
{ {
dpeth_t *dep;
message m;
int ipc_status;
int r;
/* SEF local startup. */
env_setargs(argc, argv); env_setargs(argc, argv);
sef_local_startup();
while (TRUE) netdriver_task(&de_table);
{
if ((r= netdriver_receive(ANY, &m, &ipc_status)) != OK)
panic("netdriver_receive failed: %d", r);
if(is_ipc_notify(ipc_status)) { return 0;
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);
}
}
} }
/*===========================================================================* static void de_init_hw(dpeth_t *dep, ether_addr_t *addr)
* sef_local_startup *
*===========================================================================*/
static void sef_local_startup()
{ {
/* Register init callbacks. */ de_reset(dep);
sef_setcb_init_fresh(sef_cb_init_fresh); de_conf_addr(dep, addr);
sef_setcb_init_lu(sef_cb_init_fresh); de_init_buf(dep);
sef_setcb_init_restart(sef_cb_init_fresh);
/* Register live update callbacks. */ /* Set the interrupt handler policy. Request interrupts not to be reenabled
sef_setcb_lu_prepare(sef_cb_lu_prepare_always_ready); * automatically. Return the IRQ line number when an interrupt occurs.
sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid_workfree); */
dep->de_hook = dep->de_irq;
sys_irqsetpolicy(dep->de_irq, 0, &dep->de_hook);
sys_irqenable(&dep->de_hook);
/* Register signal callbacks. */ de_reset(dep);
sef_setcb_signal_handler(sef_cb_signal_handler_term); de_hw_conf(dep);
de_setup_frame(dep, addr);
/* Let SEF perform startup. */ de_start(dep);
sef_startup();
} }
/*===========================================================================* static int do_init(unsigned int instance, ether_addr_t *addr)
* sef_cb_init_fresh *
*===========================================================================*/
static int sef_cb_init_fresh(int type, sef_init_info_t *UNUSED(info))
{ {
/* Initialize the DEC 21140A driver. */ /* Initialize the DEC 21140A driver. */
int fkeys, sfkeys; dpeth_t *dep;
long v;
v = 0; dep = &de_state;
(void) env_parse("instance", "d", 0, &v, 0, 255); memset(dep, 0, sizeof(*dep));
de_instance = (int) v;
/* Request function key for debug dumps */ strlcpy(dep->de_name, "dec21140A:?", sizeof(dep->de_name));
fkeys = sfkeys = 0; dep->de_name[strlen(dep->de_name)-1] = '0' + instance;
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);
/* Announce we are up! */ de_instance = instance;
netdriver_announce();
if (!de_probe(dep, instance))
return ENXIO;
de_init_hw(dep, addr);
return OK; return OK;
} }
static void do_get_stat_s(message * mp) static void do_stat(eth_stat_t *stat)
{ {
int rc; memcpy(stat, &de_state.de_stat, sizeof(*stat));
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;
} }
static void do_conf(const message * mp) static int de_probe(dpeth_t *dep, unsigned int skip)
{ {
int r; int r, devind;
dpeth_t *dep; u16_t vid, did;
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;
DEBUG(printf("PROBING...")); DEBUG(printf("PROBING..."));
pci_init();
r= pci_first_dev(&devind, &vid, &did); r= pci_first_dev(&devind, &vid, &did);
if (r == 0) if (r == 0)
return FALSE; return FALSE;
@ -321,33 +138,15 @@ static int de_probe(dpeth_t *dep, int skip)
/* device validation. We support only the DEC21140A */ /* device validation. We support only the DEC21140A */
if(dep->de_type != DEC_21140A){ if(dep->de_type != DEC_21140A){
dep->de_type = DE_TYPE_UNKNOWN; printf("%s: unsupported card type %x\n", dep->de_name, dep->de_type);
printf("%s: unsupported device\n", str_DevName);
return FALSE; 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; 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; u16_t retVal = 0;
int i; int i;
u32_t csr = 0; 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 more readable, the following macro is also just
to clear up the code a little.*/ 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 */ /* init */
csr = 0; EMIT; 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; 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; u32_t size;
int r, ix = 0; dpeth_t *dep;
vir_bytes bytes; de_loc_descr_t *descr;
dpeth_t *dep = NULL;
de_loc_descr_t *descr = NULL;
iovec_dat_s_t *iovp = NULL;
dep = &de_state; 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 */ /* Check for abnormal messages. We assert here
if( !( !(descr->descr->des[DES0] & DES0_OWN) && because this driver is for a virtualized
(descr->descr->des[DES0] & DES0_FS) && envrionment where we will not get bad packets
(descr->descr->des[DES0] & DES0_LS) )) */
goto suspend; 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...*/ /* HACK: VPC2007 sends short-sized packets, pad to minimum ethernet length */
/* We only support packets contained in a single descriptor. if(size<60){
Setting the descriptor buffer size to less then memset(&descr->buf1[size], 0, 60-size);
ETH_MAX_PACK_SIZE will result in multi-descriptor size=60;
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);
} }
if(!from_int){ /* Truncate large packets */
do_reply(dep); if (size > max)
} size = max;
return;
suspend: netdriver_copyout(data, 0, descr->buf1, size);
if(from_int){
assert(dep->de_flags & DEF_READING);
return;
}
assert(!(dep->de_flags & DEF_READING)); dep->de_stat.ets_packetR++;
dep->rx_return_msg = *mp;
dep->de_flags |= DEF_READING; descr->descr->des[DES0]=DES0_OWN;
do_reply(dep); dep->cur_descr[DESCR_RECV]++;
return; 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"; u16_t temp16;
char ea_key[16]; int i;
int ix;
long val;
strlcpy(ea_key, "DEETH0_EA", sizeof(ea_key)); DEBUG(printf("Reading SROM...\n"));
ea_key[5] += de_instance;
for (ix = 0; ix < SA_ADDR_LEN; ix++) { for(i=0;i<(1<<SROM_BITWIDTH)-1;i++){
val = dep->de_address.ea_addr[ix]; temp16 = de_read_rom(dep, i, SROM_BITWIDTH);
if (env_parse(ea_key, ea_fmt, ix, &val, 0x00L, 0xFFL) != EP_SET) dep->srom[i*2] = temp16 & 0xFF;
break; dep->srom[i*2+1] = temp16 >> 8;
dep->de_address.ea_addr[ix] = val;
} }
if (ix != 0 && ix != SA_ADDR_LEN) /* TODO: validate SROM content */
env_parse(ea_key, "?", 0, &val, 0L, 0L); /* acquire MAC addr */
return; 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; int i,j,r;
vir_bytes descr_vir = (vir_bytes)dep->sendrecv_descr_buf; 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; de_loc_descr_t *loc_descr;
phys_bytes temp; phys_bytes temp;
for(i=0;i<2;i++){ for(i=0;i<2;i++){
loc_descr = &dep->descr[i][0]; loc_descr = &dep->descr[i][0];
for(j=0; j < (i==DESCR_RECV ? DE_NB_RECV_DESCR : DE_NB_SEND_DESCR); j++){ 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 */ /* record physical location of two first descriptor */
r = sys_umap(SELF, VM_D, (vir_bytes)dep->descr[DESCR_RECV][0].descr, 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]); 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, 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]); 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", DEBUG(printf("Descr: head tran=[%08X] head recv=[%08X]\n",
dep->sendrecv_descr_phys_addr[DESCR_TRAN], 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++){ 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), r = sys_umap(SELF, VM_D, (vir_bytes)&(loc_descr->descr),
sizeof(de_descr_t), &temp); sizeof(de_descr_t), &temp);
if(r != OK) if(r != OK) panic("sys_umap failed: %d", r);
panic("%s %d", str_UmapErrMsg, r);
if( ((loc_descr->descr->des[DES_BUF1] & 0x3) != 0) || if( ((loc_descr->descr->des[DES_BUF1] & 0x3) != 0) ||
((loc_descr->descr->des[DES_BUF2] & 0x3) != 0) || ((loc_descr->descr->des[DES_BUF2] & 0x3) != 0) ||
((temp&0x3)!=0) ) ((temp&0x3)!=0) )
panic("%s 0x%lx", str_AlignErrMsg, temp); panic("alignment error: 0x%lx", temp);
loc_descr++; loc_descr++;
} }
@ -658,43 +366,45 @@ static void de_first_init(dpeth_t *dep)
/* Init default values */ /* Init default values */
dep->cur_descr[DESCR_TRAN]=1; dep->cur_descr[DESCR_TRAN]=1;
dep->cur_descr[DESCR_RECV]=0; 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; u32_t val;
dep = &de_state;
val = io_inl(CSR_ADDR(dep, CSR5)); val = io_inl(CSR_ADDR(dep, CSR5));
if(val & CSR5_AIS){ if(val & CSR5_AIS){
panic("Abnormal Int CSR5=: %d", val); panic("Abnormal Int CSR5=: %d", val);
} }
if( (dep->de_flags & DEF_READING) && (val & CSR5_RI) ){ if (val & CSR5_RI)
do_vread_s(&dep->rx_return_msg, TRUE); netdriver_recv();
}
if( (dep->de_flags & DEF_SENDING) && (val & CSR5_TI) ){ if (val & CSR5_TI)
do_vwrite_s(&dep->tx_return_msg, TRUE); netdriver_send();
}
/* ack and reset interrupts */ /* ack and reset interrupts */
io_outl(CSR_ADDR(dep, CSR5), 0xFFFFFFFF); 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); 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; u32_t val;
/* CSR0 - global host bus prop */ /* 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); 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; u32_t val;
val = io_inl(CSR_ADDR(dep, CSR6)) | CSR6_ST | CSR6_SR; val = io_inl(CSR_ADDR(dep, CSR6)) | CSR6_ST | CSR6_SR;
io_outl(CSR_ADDR(dep, CSR6), val); 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; int i;
u32_t val; u32_t val;
@ -739,12 +451,12 @@ static void de_setup_frame(const dpeth_t *dep){
dep->descr[DESCR_TRAN][0].buf1[9] = 0xFF; dep->descr[DESCR_TRAN][0].buf1[9] = 0xFF;
for(i=1;i<16;i++){ for(i=1;i<16;i++){
memset(&(dep->descr[DESCR_TRAN][0].buf1[12*i]), 0, 12); 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+0] = addr->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+1] = addr->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+4] = addr->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+5] = addr->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+8] = addr->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+9] = addr->ea_addr[5];
} }
dep->descr[DESCR_TRAN][0].descr->des[DES0] = DES0_OWN; 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; val = io_inl(CSR_ADDR(dep, CSR6)) | CSR6_ST;
io_outl(CSR_ADDR(dep, CSR6), val); io_outl(CSR_ADDR(dep, CSR6), val);
io_outl(CSR_ADDR(dep, CSR1), 0xFFFFFFFF); io_outl(CSR_ADDR(dep, CSR1), 0xFFFFFFFF);
return;
} }
static int de_calc_iov_size(iovec_dat_s_t * iovp){ static int do_send(struct netdriver_data *data, size_t size)
int size, ix; {
size = ix = 0; static int setup_done = 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;
dpeth_t *dep; dpeth_t *dep;
iovec_dat_s_t *iovp = NULL;
de_loc_descr_t *descr = NULL; de_loc_descr_t *descr = NULL;
u8_t *buffer = NULL;
dep = &de_state; 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)) if(!setup_done && (dep->cur_descr[DESCR_TRAN] == 0) ){
panic("%s", str_BusyErrMsg); dep->descr[DESCR_TRAN][0].descr->des[DES0] = 0;
setup_done=1;
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);
} }
dep->de_flags |= DEF_ACK_SEND; netdriver_copyin(data, 0, descr->buf1, size);
if(from_int){
dep->de_flags &= NOT(DEF_SENDING);
return;
}
do_reply(dep);
return;
suspend: descr->descr->des[DES1] = (descr->descr->des[DES1]&DES1_ER) |
if(from_int) DES1_FS | DES1_LS | DES1_IC | size;
panic("should not happen: %d", 0); descr->descr->des[DES0] = DES0_OWN;
dep->de_stat.ets_transDef++; dep->cur_descr[DESCR_TRAN]++;
dep->de_flags |= DEF_SENDING; if(dep->cur_descr[DESCR_TRAN] >= DE_NB_SEND_DESCR)
dep->de_stat.ets_transDef++; dep->cur_descr[DESCR_TRAN] = 0;
dep->tx_return_msg = *mp;
do_reply(dep); io_outl(CSR_ADDR(dep, CSR1), 0xFFFFFFFF);
dep->de_stat.ets_packetT++;
return OK;
} }
static void warning(const char *type, int err){ static u32_t io_inl(u16_t port)
printf("Warning: %s sys_%s failed (%d)\n", str_DevName, type, err); {
return;
}
static u32_t io_inl(u16_t port){
u32_t value; u32_t value;
int rc; 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; return value;
} }
static void io_outl(u16_t port, u32_t value){ static void io_outl(u16_t port, u32_t value)
{
int rc; int rc;
if ((rc = sys_outl(port, value)) != OK) warning("outl", rc); if ((rc = sys_outl(port, value)) != OK)
return; 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> #include <sys/null.h>
#define DE_FKEY 7 /* Shift+ this value will dump info on console */
#define NOT(x) (~(x))
#if debug == 1 #if debug == 1
# define DEBUG(statm) statm # define DEBUG(statm) statm
#else #else
# define DEBUG(statm) # define DEBUG(statm)
#endif #endif
#define SA_ADDR_LEN sizeof(ether_addr_t)
#define DE_NB_SEND_DESCR 32 #define DE_NB_SEND_DESCR 32
#define DE_SEND_BUF_SIZE (ETH_MAX_PACK_SIZE+2) #define DE_SEND_BUF_SIZE (ETH_MAX_PACK_SIZE+2)
#define DE_NB_RECV_DESCR 32 #define DE_NB_RECV_DESCR 32
#define DE_RECV_BUF_SIZE (ETH_MAX_PACK_SIZE+2) #define DE_RECV_BUF_SIZE (ETH_MAX_PACK_SIZE+2)
#define IOVEC_NR 16
#define DE_MIN_BASE_ADDR 0x0400 #define DE_MIN_BASE_ADDR 0x0400
#define DE_SROM_EA_OFFSET 20 #define DE_SROM_EA_OFFSET 20
#define DE_SETUP_FRAME_SIZE 192 #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 { typedef struct de_descr {
u32_t des[4]; u32_t des[4];
} de_descr_t; } de_descr_t;
@ -53,9 +37,6 @@ typedef struct de_local_descr {
} de_loc_descr_t; } de_loc_descr_t;
typedef struct dpeth { 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 */ char de_name[32]; /* Name of this interface */
port_t de_base_port; /* Base port, for multiple card instance */ port_t de_base_port; /* Base port, for multiple card instance */
int de_irq; /* IRQ line number */ int de_irq; /* IRQ line number */
@ -63,10 +44,7 @@ typedef struct dpeth {
int de_type; /* What kind of hardware */ int de_type; /* What kind of hardware */
ether_addr_t de_address; /* Ethernet Address */
eth_stat_t de_stat; /* Stats */ 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. /* 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 */ 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_RECV 0
#define DESCR_TRAN 1 #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 */ /* Serial ROM */
#define SROM_BITWIDTH 6 #define SROM_BITWIDTH 6
u8_t srom[((1<<SROM_BITWIDTH)-1)*2]; /* Space to read in u8_t srom[((1<<SROM_BITWIDTH)-1)*2]; /* Space to read in
all the configuration ROM */ 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; } dpeth_t;

View File

@ -12,6 +12,7 @@
*/ */
#include <minix/drivers.h> #include <minix/drivers.h>
#include <minix/netdriver.h>
#include <net/gen/ether.h> #include <net/gen/ether.h>
#include <net/gen/eth_io.h> #include <net/gen/eth_io.h>

View File

@ -2,7 +2,7 @@
PROG= dp8390 PROG= dp8390
SRCS= 3c503.c dp8390.c ne2000.c rtl8029.c wdeth.c SRCS= 3c503.c dp8390.c ne2000.c rtl8029.c wdeth.c
DPADD+= ${LIBNETDRIVER} ${LIBSYS} ${LIBTIMERS} DPADD+= ${LIBNETDRIVER} ${LIBSYS}
LDADD+= -lnetdriver -lsys -ltimers LDADD+= -lnetdriver -lsys
.include <minix.service.mk> .include <minix.service.mk>

File diff suppressed because it is too large Load Diff

View File

@ -173,45 +173,19 @@ typedef struct dp_rcvhdr
struct dpeth; struct dpeth;
struct iovec_dat; struct iovec_dat;
struct iovec_dat_s; struct iovec_dat_s;
typedef void(*dp_initf_t) (struct dpeth *dep); typedef void (*dp_initf_t)(struct dpeth *dep);
typedef void(*dp_stopf_t) (struct dpeth *dep); typedef void (*dp_stopf_t)(struct dpeth *dep);
typedef void(*dp_user2nicf_t) (struct dpeth *dep, struct iovec_dat typedef void (*dp_user2nicf_s_t)(struct dpeth *dep,
*iovp, vir_bytes offset, int nic_addr, vir_bytes count); struct netdriver_data *data, int nic_addr, size_t offset,
typedef void(*dp_user2nicf_s_t) (struct dpeth *dep, struct iovec_dat_s size_t count);
*iovp, vir_bytes offset, int nic_addr, vir_bytes count); typedef void (*dp_nic2userf_s_t)(struct dpeth *dep,
typedef void(*dp_nic2userf_t) (struct dpeth *dep, int nic_addr, struct struct netdriver_data *data, int nic_addr, size_t offset,
iovec_dat *iovp, vir_bytes offset, vir_bytes count); size_t count);
typedef void(*dp_nic2userf_s_t) (struct dpeth *dep, int nic_addr, struct typedef void (*dp_getblock_t)(struct dpeth *dep, int page, size_t
iovec_dat_s *iovp, vir_bytes offset, vir_bytes count);
#if 0
typedef void(*dp_getheaderf_t) (struct dpeth *dep, int page, struct
dp_rcvhdr *h, u16_t *eth_type);
#endif
typedef void(*dp_getblock_t) (struct dpeth *dep, int page, size_t
offset, size_t size, void *dst); offset, size_t size, void *dst);
/* iovectors are handled IOVEC_NR entries at a time. */
#define IOVEC_NR 16
typedef int irq_hook_t; typedef int irq_hook_t;
typedef struct iovec_dat
{
iovec_t iod_iovec[IOVEC_NR];
int iod_iovec_s;
endpoint_t iod_proc_nr;
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_NR 2 /* Maximum size of the send queue */
#define SENDQ_PAGES 6 /* 6 * DP_PAGESIZE >= 1514 bytes */ #define SENDQ_PAGES 6 /* 6 * DP_PAGESIZE >= 1514 bytes */
@ -250,10 +224,8 @@ typedef struct dpeth
int de_startpage; int de_startpage;
int de_stoppage; int de_stoppage;
#if ENABLE_PCI
/* PCI config */ /* PCI config */
char de_pci; /* TRUE iff PCI device */ char de_pci; /* TRUE iff PCI device */
#endif
/* Do it yourself send queue */ /* Do it yourself send queue */
struct sendq struct sendq
@ -268,14 +240,7 @@ typedef struct dpeth
/* Fields for internal use by the dp8390 driver. */ /* Fields for internal use by the dp8390 driver. */
int de_flags; int de_flags;
int de_mode;
eth_stat_t de_stat; eth_stat_t de_stat;
iovec_dat_s_t de_read_iovec_s;
iovec_dat_s_t de_write_iovec_s;
iovec_dat_s_t de_tmp_iovec_s;
vir_bytes de_read_s;
endpoint_t de_client;
message de_sendmsg;
dp_user2nicf_s_t de_user2nicf_s; dp_user2nicf_s_t de_user2nicf_s;
dp_nic2userf_s_t de_nic2userf_s; dp_nic2userf_s_t de_nic2userf_s;
dp_getblock_t de_getblockf; dp_getblock_t de_getblockf;
@ -283,24 +248,10 @@ typedef struct dpeth
#define DEI_DEFAULT 0x8000 #define DEI_DEFAULT 0x8000
#define DEF_EMPTY 0x000 #define DEF_EMPTY 0x00
#define DEF_PACK_SEND 0x001 #define DEF_STOPPED 0x01
#define DEF_PACK_RECV 0x002
#define DEF_SEND_AVAIL 0x004
#define DEF_READING 0x010
#define DEF_PROMISC 0x040
#define DEF_MULTI 0x080
#define DEF_BROAD 0x100
#define DEF_ENABLED 0x200
#define DEF_STOPPED 0x400
#define DEM_DISABLED 0x0 #define debug 0
#define DEM_SINK 0x1
#define DEM_ENABLED 0x2
#if !__minix_vmd
#define debug 0 /* Standard Minix lacks debug variable */
#endif
/* /*
* $PchId: dp8390.h,v 1.10 2005/02/10 17:26:06 philip Exp $ * $PchId: dp8390.h,v 1.10 2005/02/10 17:26:06 philip Exp $

View File

@ -5,7 +5,6 @@ local.h
#define ENABLE_WDETH 1 #define ENABLE_WDETH 1
#define ENABLE_NE2000 1 #define ENABLE_NE2000 1
#define ENABLE_3C503 1 #define ENABLE_3C503 1
#define ENABLE_PCI 1
struct dpeth; struct dpeth;

View File

@ -8,12 +8,10 @@ Created: March 15, 1994 by Philip Homburg <philip@f-mnx.phicoh.com>
*/ */
#include <minix/drivers.h> #include <minix/drivers.h>
#include <minix/netdriver.h>
#include <net/gen/ether.h> #include <net/gen/ether.h>
#include <net/gen/eth_io.h> #include <net/gen/eth_io.h>
#if __minix_vmd
#include "config.h"
#endif
#include "local.h" #include "local.h"
#include "dp8390.h" #include "dp8390.h"

View File

@ -7,6 +7,7 @@ Created: April 2000 by Philip Homburg <philip@f-mnx.phicoh.com>
*/ */
#include <minix/drivers.h> #include <minix/drivers.h>
#include <minix/netdriver.h>
#include <stdlib.h> #include <stdlib.h>
#include <sys/types.h> #include <sys/types.h>
@ -20,8 +21,6 @@ Created: April 2000 by Philip Homburg <philip@f-mnx.phicoh.com>
#include "dp8390.h" #include "dp8390.h"
#include "rtl8029.h" #include "rtl8029.h"
#if ENABLE_PCI
static void rtl_init(struct dpeth *dep); static void rtl_init(struct dpeth *dep);
#if 0 #if 0
static u16_t get_ee_word(dpeth_t *dep, int a); static u16_t get_ee_word(dpeth_t *dep, int a);
@ -312,8 +311,6 @@ dpeth_t *dep;
} }
#endif #endif
#endif /* ENABLE_PCI */
/* /*
* $PchId: rtl8029.c,v 1.7 2004/08/03 12:16:58 philip Exp $ * $PchId: rtl8029.c,v 1.7 2004/08/03 12:16:58 philip Exp $
*/ */

View File

@ -5,6 +5,7 @@ Created: March 14, 1994 by Philip Homburg
*/ */
#include <minix/drivers.h> #include <minix/drivers.h>
#include <minix/netdriver.h>
#include <net/gen/ether.h> #include <net/gen/ether.h>
#include <net/gen/eth_io.h> #include <net/gen/eth_io.h>
@ -70,9 +71,6 @@ dpeth_t *dep;
int we_type; int we_type;
int sendq_nr; int sendq_nr;
assert(dep->de_mode == DEM_ENABLED);
assert(!(dep->de_flags & DEF_ENABLED));
dep->de_address.ea_addr[0] = inb_we(dep, EPL_EA0); dep->de_address.ea_addr[0] = inb_we(dep, EPL_EA0);
dep->de_address.ea_addr[1] = inb_we(dep, EPL_EA1); dep->de_address.ea_addr[1] = inb_we(dep, EPL_EA1);
dep->de_address.ea_addr[2] = inb_we(dep, EPL_EA2); dep->de_address.ea_addr[2] = inb_we(dep, EPL_EA2);

View File

@ -10,7 +10,7 @@
*/ */
#include <minix/drivers.h> #include <minix/drivers.h>
#include <minix/com.h> #include <minix/netdriver.h>
#include <net/gen/ether.h> #include <net/gen/ether.h>
#include <net/gen/eth_io.h> #include <net/gen/eth_io.h>
#include "dp.h" #include "dp.h"
@ -23,17 +23,17 @@ static unsigned char StationAddress[SA_ADDR_LEN] = {0, 0, 0, 0, 0, 0,};
static buff_t *TxBuff = NULL; static buff_t *TxBuff = NULL;
/* /*
** Name: void el1_getstats(dpeth_t *dep) ** Name: el1_getstats
** Function: Reads statistics counters from board. ** Function: Reads statistics counters from board.
**/ **/
static void el1_getstats(dpeth_t * dep) static void el1_getstats(dpeth_t * dep)
{ {
return; /* Nothing to do */ /* Nothing to do */
} }
/* /*
** Name: void el1_reset(dpeth_t *dep) ** Name: el1_reset
** Function: Reset function specific for Etherlink hardware. ** Function: Reset function specific for Etherlink hardware.
*/ */
static void el1_reset(dpeth_t * dep) static void el1_reset(dpeth_t * dep)
@ -49,7 +49,6 @@ static void el1_reset(dpeth_t * dep)
for (ix = EL1_ADDRESS; ix < SA_ADDR_LEN; ix += 1) for (ix = EL1_ADDRESS; ix < SA_ADDR_LEN; ix += 1)
outb_el1(dep, ix, StationAddress[ix]); outb_el1(dep, ix, StationAddress[ix]);
lock();
/* Enable DMA/Interrupt, gain control of Buffer */ /* Enable DMA/Interrupt, gain control of Buffer */
outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_SYS); outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_SYS);
/* Clear RX packet area */ /* Clear RX packet area */
@ -60,22 +59,19 @@ static void el1_reset(dpeth_t * dep)
inb_el1(dep, EL1_RECV); inb_el1(dep, EL1_RECV);
inb_el1(dep, EL1_XMIT); inb_el1(dep, EL1_XMIT);
dep->de_flags &= NOT(DEF_XMIT_BUSY); dep->de_flags &= NOT(DEF_XMIT_BUSY);
unlock();
return; /* Done */
} }
/* /*
** Name: void el1_dumpstats(dpeth_t *dep, int port, vir_bytes size) ** Name: el1_dumpstats
** Function: Dumps counter on screen (support for console display). ** Function: Dumps counter on screen (support for console display).
*/ */
static void el1_dumpstats(dpeth_t * UNUSED(dep)) static void el1_dumpstats(dpeth_t * UNUSED(dep))
{ {
return;
} }
/* /*
** Name: void el1_mode_init(dpeth_t *dep) ** Name: el1_mode_init
** Function: Initializes receicer mode ** Function: Initializes receicer mode
*/ */
static void el1_mode_init(dpeth_t * dep) static void el1_mode_init(dpeth_t * dep)
@ -95,125 +91,93 @@ static void el1_mode_init(dpeth_t * dep)
} }
outb_el1(dep, EL1_RECV, dep->de_recv_mode); outb_el1(dep, EL1_RECV, dep->de_recv_mode);
inb_el1(dep, EL1_RECV); inb_el1(dep, EL1_RECV);
return;
} }
/* /*
** Name: void el1_recv(dpeth_t *dep, int from, int size) ** Name: el1_recv
** Function: Receive function. Called from interrupt handler to ** Function: Receive function. Called from interrupt handler to
** unload recv. buffer or from main (packet to client) ** unload recv. buffer or from main (packet to client)
*/ */
static void el1_recv(dpeth_t * dep, int from, int size) static ssize_t el1_recv(dpeth_t *dep, struct netdriver_data *data, size_t max)
{ {
buff_t *rxptr; buff_t *rxptr;
size_t size;
while ((dep->de_flags & DEF_READING) && (rxptr = dep->de_recvq_head)) { if ((rxptr = dep->de_recvq_head) == NULL)
return SUSPEND;
/* Remove buffer from queue and free buffer */ /* Remove buffer from queue and free buffer */
lock(); if (dep->de_recvq_tail == dep->de_recvq_head)
if (dep->de_recvq_tail == dep->de_recvq_head) dep->de_recvq_head = dep->de_recvq_tail = NULL;
dep->de_recvq_head = dep->de_recvq_tail = NULL; else
else dep->de_recvq_head = rxptr->next;
dep->de_recvq_head = rxptr->next;
unlock();
/* Copy buffer to user area */ /* Copy buffer to user area */
mem2user(dep, rxptr); size = MIN(rxptr->size, max);
/* Reply information */ netdriver_copyout(data, 0, rxptr->buffer, size);
dep->de_read_s = rxptr->size;
dep->de_flags |= DEF_ACK_RECV;
dep->de_flags &= NOT(DEF_READING);
/* Return buffer to the idle pool */ /* Return buffer to the idle pool */
free_buff(dep, rxptr); free_buff(dep, rxptr);
}
return; return size;
} }
/* /*
** Name: void el1_send(dpeth_t *dep, int from_int, int pktsize) ** Name: el1_send
** Function: Send function. Called from main to transit a packet or ** Function: Send function.
** from interrupt handler when a new packet was queued.
*/ */
static void el1_send(dpeth_t * dep, int from_int, int pktsize) static int el1_send(dpeth_t *dep, struct netdriver_data *data, size_t size)
{ {
buff_t *txbuff; buff_t *txbuff;
clock_t now; clock_t now;
if (from_int == FALSE) { if (dep->de_flags & DEF_XMIT_BUSY) {
if ((txbuff = alloc_buff(dep, pktsize + sizeof(buff_t))) != NULL) {
/* Fill transmit buffer from user area */
txbuff->next = NULL;
txbuff->size = pktsize;
txbuff->client = dep->de_client;
user2mem(dep, txbuff);
} else
panic("out of memory for Tx");
} else if ((txbuff = dep->de_xmitq_head) != NULL) {
/* Get first packet in queue */
lock();
if (dep->de_xmitq_tail == dep->de_xmitq_head)
dep->de_xmitq_head = dep->de_xmitq_tail = NULL;
else
dep->de_xmitq_head = txbuff->next;
unlock();
pktsize = txbuff->size;
} else
panic("should not be sending ");
if ((dep->de_flags & DEF_XMIT_BUSY)) {
if (from_int) panic("should not be sending ");
getticks(&now); getticks(&now);
if ((now - dep->de_xmit_start) > 4) { if ((now - dep->de_xmit_start) > 4) {
/* Transmitter timed out */ /* Transmitter timed out */
DEBUG(printf("3c501: transmitter timed out ... \n")); DEBUG(printf("3c501: transmitter timed out ... \n"));
dep->de_stat.ets_sendErr += 1; dep->de_stat.ets_sendErr += 1;
dep->de_flags &= NOT(DEF_XMIT_BUSY); dep->de_flags &= NOT(DEF_XMIT_BUSY);
el1_reset(dep); /* Try sending anyway. */
} } else
return SUSPEND;
/* Queue packet */
lock(); /* Queue packet to receive queue */
if (dep->de_xmitq_head == NULL)
dep->de_xmitq_head = txbuff;
else
dep->de_xmitq_tail->next = txbuff;
dep->de_xmitq_tail = txbuff;
unlock();
} else {
/* Save for retransmission */
TxBuff = txbuff;
dep->de_flags |= (DEF_XMIT_BUSY | DEF_ACK_SEND);
/* Setup board for packet loading */
lock(); /* Buffer to processor */
outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_SYS);
inb_el1(dep, EL1_RECV); /* Clears any spurious interrupt */
inb_el1(dep, EL1_XMIT);
outw_el1(dep, EL1_RECVPTR, 0); /* Clears RX packet area */
/* Loads packet */
outw_el1(dep, EL1_XMITPTR, (EL1_BFRSIZ - pktsize));
outsb(dep->de_data_port, SELF, txbuff->buffer, pktsize);
/* Starts transmitter */
outw_el1(dep, EL1_XMITPTR, (EL1_BFRSIZ - pktsize));
outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_XMIT); /* There it goes... */
unlock();
getticks(&dep->de_xmit_start);
dep->de_flags &= NOT(DEF_SENDING);
} }
return;
/* Since we may have to retransmit, we need a local copy. */
if ((txbuff = alloc_buff(dep, size + sizeof(buff_t))) == NULL)
panic("out of memory");
/* Fill transmit buffer from user area */
txbuff->next = NULL;
txbuff->size = size;
netdriver_copyin(data, 0, txbuff->buffer, size);
/* Save for retransmission */
TxBuff = txbuff;
dep->de_flags |= DEF_XMIT_BUSY;
/* Setup board for packet loading */
outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_SYS);
inb_el1(dep, EL1_RECV); /* Clears any spurious interrupt */
inb_el1(dep, EL1_XMIT);
outw_el1(dep, EL1_RECVPTR, 0); /* Clears RX packet area */
/* Loads packet */
outw_el1(dep, EL1_XMITPTR, (EL1_BFRSIZ - size));
outsb(dep->de_data_port, txbuff->buffer, size);
/* Starts transmitter */
outw_el1(dep, EL1_XMITPTR, (EL1_BFRSIZ - size));
outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_XMIT); /* There it goes... */
getticks(&dep->de_xmit_start);
return OK;
} }
/* /*
** Name: void el1_stop(dpeth_t *dep) ** Name: el1_stop
** Function: Stops board and disable interrupts. ** Function: Stops board and disable interrupts.
*/ */
static void el1_stop(dpeth_t * dep) static void el1_stop(dpeth_t * dep)
@ -225,11 +189,10 @@ static void el1_stop(dpeth_t * dep)
outb_el1(dep, EL1_CSR, ECSR_RESET); outb_el1(dep, EL1_CSR, ECSR_RESET);
outb_el1(dep, EL1_CSR, ECSR_SYS); outb_el1(dep, EL1_CSR, ECSR_SYS);
sys_irqdisable(&dep->de_hook); /* Disable interrupt */ sys_irqdisable(&dep->de_hook); /* Disable interrupt */
return;
} }
/* /*
** Name: void el1_interrupt(dpeth_t *dep) ** Name: el1_interrupt
** Function: Interrupt handler. Acknwledges transmit interrupts ** Function: Interrupt handler. Acknwledges transmit interrupts
** or unloads receive buffer to memory queue. ** or unloads receive buffer to memory queue.
*/ */
@ -264,7 +227,6 @@ static void el1_interrupt(dpeth_t * dep)
} }
DEBUG(printf("3c501: got xmit interrupt (0x%02X)\n", isr)); DEBUG(printf("3c501: got xmit interrupt (0x%02X)\n", isr));
el1_reset(dep); el1_reset(dep);
} else { } else {
/** if (inw_el1(dep, EL1_XMITPTR) == EL1_BFRSIZ) **/ /** if (inw_el1(dep, EL1_XMITPTR) == EL1_BFRSIZ) **/
/* Packet transmitted successfully */ /* Packet transmitted successfully */
@ -272,12 +234,9 @@ static void el1_interrupt(dpeth_t * dep)
dep->bytes_Tx += (long) (TxBuff->size); dep->bytes_Tx += (long) (TxBuff->size);
free_buff(dep, TxBuff); free_buff(dep, TxBuff);
dep->de_flags &= NOT(DEF_XMIT_BUSY); dep->de_flags &= NOT(DEF_XMIT_BUSY);
if ((dep->de_flags & DEF_SENDING) && dep->de_xmitq_head) { netdriver_send();
/* Pending transmit request available in queue */ if (dep->de_flags & DEF_XMIT_BUSY)
el1_send(dep, TRUE, 0); return;
if (dep->de_flags & (DEF_XMIT_BUSY | DEF_ACK_SEND))
return;
}
} }
} else if ((csr & (ECSR_RECV | ECSR_XMTBSY)) == (ECSR_RECV | ECSR_XMTBSY)) { } else if ((csr & (ECSR_RECV | ECSR_XMTBSY)) == (ECSR_RECV | ECSR_XMTBSY)) {
@ -301,21 +260,20 @@ static void el1_interrupt(dpeth_t * dep)
/* Got a good packet. Read it from buffer */ /* Got a good packet. Read it from buffer */
outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_SYS); outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_SYS);
outw_el1(dep, EL1_XMITPTR, 0); outw_el1(dep, EL1_XMITPTR, 0);
insb(dep->de_data_port, SELF, rxptr->buffer, pktsize); insb(dep->de_data_port, rxptr->buffer, pktsize);
rxptr->next = NULL; rxptr->next = NULL;
rxptr->size = pktsize; rxptr->size = pktsize;
dep->de_stat.ets_packetR += 1; dep->de_stat.ets_packetR += 1;
dep->bytes_Rx += (long) pktsize; dep->bytes_Rx += (long) pktsize;
lock(); /* Queue packet to receive queue */ /* Queue packet to receive queue */
if (dep->de_recvq_head == NULL) if (dep->de_recvq_head == NULL)
dep->de_recvq_head = rxptr; dep->de_recvq_head = rxptr;
else else
dep->de_recvq_tail->next = rxptr; dep->de_recvq_tail->next = rxptr;
dep->de_recvq_tail = rxptr; dep->de_recvq_tail = rxptr;
unlock();
/* Reply to pending Receive requests, if any */ /* Reply to pending Receive requests, if any */
el1_recv(dep, TRUE, 0); netdriver_recv();
} }
} else { /* Nasty condition, should never happen */ } else { /* Nasty condition, should never happen */
DEBUG( DEBUG(
@ -337,11 +295,10 @@ static void el1_interrupt(dpeth_t * dep)
/* Be sure that interrupts are cleared */ /* Be sure that interrupts are cleared */
inb_el1(dep, EL1_RECV); inb_el1(dep, EL1_RECV);
inb_el1(dep, EL1_XMIT); inb_el1(dep, EL1_XMIT);
return;
} }
/* /*
** Name: void el1_init(dpeth_t *dep) ** Name: el1_init
** Function: Initalizes board hardware and driver data structures. ** Function: Initalizes board hardware and driver data structures.
*/ */
static void el1_init(dpeth_t * dep) static void el1_init(dpeth_t * dep)
@ -376,12 +333,10 @@ static void el1_init(dpeth_t * dep)
dep->de_getstatsf = el1_getstats; dep->de_getstatsf = el1_getstats;
dep->de_dumpstatsf = el1_dumpstats; dep->de_dumpstatsf = el1_dumpstats;
dep->de_interruptf = el1_interrupt; dep->de_interruptf = el1_interrupt;
return; /* Done */
} }
/* /*
** Name: int el1_probe(dpeth_t *dep) ** Name: el1_probe
** Function: Checks for presence of the board. ** Function: Checks for presence of the board.
*/ */
int el1_probe(dpeth_t * dep) int el1_probe(dpeth_t * dep)

View File

@ -10,6 +10,7 @@
*/ */
#include <minix/drivers.h> #include <minix/drivers.h>
#include <minix/netdriver.h>
#include <net/gen/ether.h> #include <net/gen/ether.h>
#include <net/gen/eth_io.h> #include <net/gen/eth_io.h>
#include "dp.h" #include "dp.h"
@ -20,7 +21,7 @@
#include "3c503.h" #include "3c503.h"
/* /*
** Name: void el2_init(dpeth_t *dep); ** Name: el2_init
** Function: Initalize hardware and data structures. ** Function: Initalize hardware and data structures.
*/ */
static void el2_init(dpeth_t * dep) static void el2_init(dpeth_t * dep)
@ -97,11 +98,10 @@ static void el2_init(dpeth_t * dep)
for (ix = 0; ix < SA_ADDR_LEN; ix += 1) for (ix = 0; ix < SA_ADDR_LEN; ix += 1)
printf("%02X%c", dep->de_address.ea_addr[ix], printf("%02X%c", dep->de_address.ea_addr[ix],
ix < SA_ADDR_LEN - 1 ? ':' : '\n'); ix < SA_ADDR_LEN - 1 ? ':' : '\n');
return;
} }
/* /*
** Name: void el2_stop(dpeth_t *dep); ** Name: el2_stop
** Function: Stops board by disabling interrupts. ** Function: Stops board by disabling interrupts.
*/ */
static void el2_stop(dpeth_t * dep) static void el2_stop(dpeth_t * dep)
@ -109,11 +109,10 @@ static void el2_stop(dpeth_t * dep)
outb_el2(dep, EL2_CFGR, ECFGR_IRQOFF); outb_el2(dep, EL2_CFGR, ECFGR_IRQOFF);
sys_irqdisable(&dep->de_hook); /* disable interrupts */ sys_irqdisable(&dep->de_hook); /* disable interrupts */
return;
} }
/* /*
** Name: void el2_probe(dpeth_t *dep); ** Name: el2_probe
** Function: Probe for the presence of an EtherLink II card. ** Function: Probe for the presence of an EtherLink II card.
** Initialize memory addressing if card detected. ** Initialize memory addressing if card detected.
*/ */
@ -132,9 +131,9 @@ int el2_probe(dpeth_t * dep)
/* Resets board */ /* Resets board */
outb_el2(dep, EL2_CNTR, ECNTR_RESET | thin); outb_el2(dep, EL2_CNTR, ECNTR_RESET | thin);
milli_delay(1); micro_delay(1000);
outb_el2(dep, EL2_CNTR, thin); outb_el2(dep, EL2_CNTR, thin);
milli_delay(5); micro_delay(5000);
/* Map the address PROM to lower I/O address range */ /* Map the address PROM to lower I/O address range */
outb_el2(dep, EL2_CNTR, ECNTR_SAPROM | thin); outb_el2(dep, EL2_CNTR, ECNTR_SAPROM | thin);

View File

@ -10,7 +10,7 @@
*/ */
#include <minix/drivers.h> #include <minix/drivers.h>
#include <minix/com.h> #include <minix/netdriver.h>
#include <net/gen/ether.h> #include <net/gen/ether.h>
#include <net/gen/eth_io.h> #include <net/gen/eth_io.h>
@ -25,7 +25,7 @@ static const char *const IfNamesMsg[] = {
}; };
/* /*
** Name: void el3_update_stats(dpeth_t *dep) ** Name: el3_update_stats
** Function: Reads statistic counters from board ** Function: Reads statistic counters from board
** and updates local counters. ** and updates local counters.
*/ */
@ -52,36 +52,30 @@ static void el3_update_stats(dpeth_t * dep)
/* Goes back to operating window and enables statistics */ /* Goes back to operating window and enables statistics */
SetWindow(WNO_Operating); SetWindow(WNO_Operating);
outw_el3(dep, REG_CmdStatus, CMD_StatsEnable); outw_el3(dep, REG_CmdStatus, CMD_StatsEnable);
return;
} }
/* /*
** Name: void el3_getstats(dpeth_t *dep) ** Name: el3_getstats
** Function: Reads statistics counters from board. ** Function: Reads statistics counters from board.
*/ */
static void el3_getstats(dpeth_t * dep) static void el3_getstats(dpeth_t * dep)
{ {
lock();
el3_update_stats(dep); el3_update_stats(dep);
unlock();
return;
} }
/* /*
** Name: void el3_dodump(dpeth_t *dep) ** Name: el3_dodump
** Function: Dumps counter on screen (support for console display). ** Function: Dumps counter on screen (support for console display).
*/ */
static void el3_dodump(dpeth_t * dep) static void el3_dodump(dpeth_t * dep)
{ {
el3_getstats(dep); el3_getstats(dep);
return;
} }
/* /*
** Name: void el3_rx_mode(dpeth_t *dep) ** Name: el3_rx_mode
** Function: Initializes receiver mode ** Function: Initializes receiver mode
*/ */
static void el3_rx_mode(dpeth_t * dep) static void el3_rx_mode(dpeth_t * dep)
@ -95,85 +89,49 @@ static void el3_rx_mode(dpeth_t * dep)
outw_el3(dep, REG_CmdStatus, CMD_RxReset); outw_el3(dep, REG_CmdStatus, CMD_RxReset);
outw_el3(dep, REG_CmdStatus, CMD_SetRxFilter | dep->de_recv_mode); outw_el3(dep, REG_CmdStatus, CMD_SetRxFilter | dep->de_recv_mode);
outw_el3(dep, REG_CmdStatus, CMD_RxEnable); outw_el3(dep, REG_CmdStatus, CMD_RxEnable);
return;
} }
/* /*
** Name: void el3_reset(dpeth_t *dep) ** Name: el3_reset
** Function: Reset function specific for Etherlink hardware. ** Function: Reset function specific for Etherlink hardware.
*/ */
static void el3_reset(dpeth_t * UNUSED(dep)) static void el3_reset(dpeth_t * UNUSED(dep))
{ {
return; /* Done */
} }
/* /*
** Name: void el3_write_fifo(dpeth_t * dep, int pktsize); ** Name: el3_recv
** Function: Writes a packet from user area to board.
** Remark: Writing a word/dword at a time may result faster
** but is a lot more complicated. Let's go simpler way.
*/
static void el3_write_fifo(dpeth_t * dep, int pktsize)
{
int bytes, ix = 0;
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 */
r= sys_safe_outsb(dep->de_data_port, iovp->iod_proc_nr,
iovp->iod_iovec[ix].iov_grant, 0, bytes);
if (r != OK)
panic("el3_write_fifo: sys_safe_outsb failed: %d", r);
if (++ix >= IOVEC_NR) { /* Next buffer of IO vector */
dp_next_iovec(iovp);
ix = 0;
}
/* Till packet done */
} while ((pktsize -= bytes) > 0);
while ((padding++ % sizeof(long)) != 0) outb(dep->de_data_port, 0x00);
return;
}
/*
** Name: void el3_recv(dpeth_t *dep, int fromint, int size)
** Function: Receive function. Called from interrupt handler or ** Function: Receive function. Called from interrupt handler or
** from main to unload recv. buffer (packet to client) ** from main to unload recv. buffer (packet to client)
*/ */
static void el3_recv(dpeth_t *dep, int fromint, int size) static ssize_t el3_recv(dpeth_t *dep, struct netdriver_data *data, size_t max)
{ {
buff_t *rxptr; buff_t *rxptr;
size_t size;
while ((dep->de_flags & DEF_READING) && (rxptr = dep->de_recvq_head)) { if ((rxptr = dep->de_recvq_head) == NULL)
return SUSPEND;
lock(); /* Remove buffer from queue */ /* Remove buffer from queue */
if (dep->de_recvq_tail == dep->de_recvq_head) if (dep->de_recvq_tail == dep->de_recvq_head)
dep->de_recvq_head = dep->de_recvq_tail = NULL; dep->de_recvq_head = dep->de_recvq_tail = NULL;
else else
dep->de_recvq_head = rxptr->next; dep->de_recvq_head = rxptr->next;
unlock();
/* Copy buffer to user area and free it */ /* Copy buffer to user area and free it */
mem2user(dep, rxptr); size = MIN(rxptr->size, max);
dep->de_read_s = rxptr->size; netdriver_copyout(data, 0, rxptr->buffer, size);
dep->de_flags |= DEF_ACK_RECV;
dep->de_flags &= NOT(DEF_READING);
/* Return buffer to the idle pool */ /* Return buffer to the idle pool */
free_buff(dep, rxptr); free_buff(dep, rxptr);
}
return; return size;
} }
/* /*
** Name: void el3_rx_complete(dpeth_t * dep); ** Name: el3_rx_complete
** Function: Upon receiving a packet, provides status checks ** Function: Upon receiving a packet, provides status checks
** and if packet is OK copies it to local buffer. ** and if packet is OK copies it to local buffer.
*/ */
@ -205,38 +163,36 @@ static void el3_rx_complete(dpeth_t * dep)
} else { } else {
/* Good packet. Read it from FIFO */ /* Good packet. Read it from FIFO */
insb(dep->de_data_port, SELF, rxptr->buffer, pktsize); insb(dep->de_data_port, rxptr->buffer, pktsize);
rxptr->next = NULL; rxptr->next = NULL;
rxptr->size = pktsize; rxptr->size = pktsize;
lock(); /* Queue packet to receive queue */ /* Queue packet to receive queue */
if (dep->de_recvq_head == NULL) if (dep->de_recvq_head == NULL)
dep->de_recvq_head = rxptr; dep->de_recvq_head = rxptr;
else else
dep->de_recvq_tail->next = rxptr; dep->de_recvq_tail->next = rxptr;
dep->de_recvq_tail = rxptr; dep->de_recvq_tail = rxptr;
unlock();
/* Reply to pending Receive requests, if any */ /* Reply to pending Receive requests, if any */
el3_recv(dep, TRUE, pktsize); netdriver_recv();
} }
/* Discard top packet from queue */ /* Discard top packet from queue */
outw_el3(dep, REG_CmdStatus, CMD_RxDiscard); outw_el3(dep, REG_CmdStatus, CMD_RxDiscard);
return;
} }
/* /*
** Name: void el3_send(dpeth_t *dep, int count) ** Name: el3_send
** Function: Send function. Called from main to transit a packet or ** Function: Send function. Called from main to transit a packet or
** from interrupt handler when Tx FIFO gets available. ** from interrupt handler when Tx FIFO gets available.
*/ */
static void el3_send(dpeth_t * dep, int from_int, int count) static int el3_send(dpeth_t *dep, struct netdriver_data *data, size_t size)
{ {
clock_t now; clock_t now;
int ix; int ix;
short int TxStatus; short int TxStatus;
size_t padding;
getticks(&now); getticks(&now);
if ((dep->de_flags & DEF_XMIT_BUSY) && if ((dep->de_flags & DEF_XMIT_BUSY) &&
@ -249,41 +205,43 @@ static void el3_send(dpeth_t * dep, int from_int, int count)
outw_el3(dep, REG_CmdStatus, CMD_TxEnable); outw_el3(dep, REG_CmdStatus, CMD_TxEnable);
dep->de_flags &= NOT(DEF_XMIT_BUSY); dep->de_flags &= NOT(DEF_XMIT_BUSY);
} }
if (!(dep->de_flags & DEF_XMIT_BUSY)) { if (dep->de_flags & DEF_XMIT_BUSY)
return SUSPEND;
/* Writes Transmitter preamble 1st Word (packet len, no ints) */ /* Writes Transmitter preamble 1st Word (packet len, no ints) */
outw_el3(dep, REG_TxFIFO, count); outw_el3(dep, REG_TxFIFO, size);
/* Writes Transmitter preamble 2nd Word (all zero) */ /* Writes Transmitter preamble 2nd Word (all zero) */
outw_el3(dep, REG_TxFIFO, 0); outw_el3(dep, REG_TxFIFO, 0);
/* Writes packet */ /* Writes packet */
el3_write_fifo(dep, count); netdriver_portoutb(data, 0, dep->de_data_port, size);
padding = size;
while ((padding++ % sizeof(long)) != 0) outb(dep->de_data_port, 0x00);
getticks(&dep->de_xmit_start); getticks(&dep->de_xmit_start);
dep->de_flags |= (DEF_XMIT_BUSY | DEF_ACK_SEND); dep->de_flags |= DEF_XMIT_BUSY;
if (inw_el3(dep, REG_TxFree) > ETH_MAX_PACK_SIZE) { if (inw_el3(dep, REG_TxFree) > ETH_MAX_PACK_SIZE) {
/* Tx has enough room for a packet of maximum size */ /* Tx has enough room for a packet of maximum size */
dep->de_flags &= NOT(DEF_XMIT_BUSY | DEF_SENDING); dep->de_flags &= NOT(DEF_XMIT_BUSY);
} else { } else {
/* Interrupt driver when enough room is available */ /* Interrupt driver when enough room is available */
outw_el3(dep, REG_CmdStatus, CMD_SetTxAvailable | ETH_MAX_PACK_SIZE); outw_el3(dep, REG_CmdStatus, CMD_SetTxAvailable | ETH_MAX_PACK_SIZE);
dep->de_flags &= NOT(DEF_SENDING);
}
/* Pops Tx status stack */
for (ix = 4; --ix && (TxStatus = inb_el3(dep, REG_TxStatus)) > 0;) {
if (TxStatus & 0x38) dep->de_stat.ets_sendErr += 1;
if (TxStatus & 0x30)
outw_el3(dep, REG_CmdStatus, CMD_TxReset);
if (TxStatus & 0x3C)
outw_el3(dep, REG_CmdStatus, CMD_TxEnable);
outb_el3(dep, REG_TxStatus, 0);
}
} }
return;
/* Pops Tx status stack */
for (ix = 4; --ix && (TxStatus = inb_el3(dep, REG_TxStatus)) > 0;) {
if (TxStatus & 0x38) dep->de_stat.ets_sendErr += 1;
if (TxStatus & 0x30)
outw_el3(dep, REG_CmdStatus, CMD_TxReset);
if (TxStatus & 0x3C)
outw_el3(dep, REG_CmdStatus, CMD_TxEnable);
outb_el3(dep, REG_TxStatus, 0);
}
return OK;
} }
/* /*
** Name: void el3_close(dpeth_t *dep) ** Name: el3_close
** Function: Stops board and makes it ready to shut down. ** Function: Stops board and makes it ready to shut down.
*/ */
static void el3_close(dpeth_t * dep) static void el3_close(dpeth_t * dep)
@ -296,24 +254,22 @@ static void el3_close(dpeth_t * dep)
if (dep->de_if_port == BNC_XCVR) { if (dep->de_if_port == BNC_XCVR) {
outw_el3(dep, REG_CmdStatus, CMD_StopIntXcvr); outw_el3(dep, REG_CmdStatus, CMD_StopIntXcvr);
/* milli_delay(5); */ /* micro_delay(5000); */
} else if (dep->de_if_port == TP_XCVR) { } else if (dep->de_if_port == TP_XCVR) {
SetWindow(WNO_Diagnostics); SetWindow(WNO_Diagnostics);
outw_el3(dep, REG_MediaStatus, inw_el3(dep, REG_MediaStatus) & outw_el3(dep, REG_MediaStatus, inw_el3(dep, REG_MediaStatus) &
NOT((MediaLBeatEnable | MediaJabberEnable))); NOT((MediaLBeatEnable | MediaJabberEnable)));
/* milli_delay(5); */ /* micro_delay(5000); */
} }
DEBUG(printf("%s: stopping Etherlink ... \n", dep->de_name)); DEBUG(printf("%s: stopping Etherlink ... \n", dep->de_name));
/* Issues a global reset /* Issues a global reset
outw_el3(dep, REG_CmdStatus, CMD_GlobalReset); */ outw_el3(dep, REG_CmdStatus, CMD_GlobalReset); */
sys_irqdisable(&dep->de_hook); /* Disable interrupt */ sys_irqdisable(&dep->de_hook); /* Disable interrupt */
return;
} }
/* /*
** Name: void el3_interrupt(dpeth_t *dep) ** Name: el3_interrupt
** Function: Interrupt handler. Acknwledges transmit interrupts ** Function: Interrupt handler. Acknwledges transmit interrupts
** or unloads receive buffer to memory queue. ** or unloads receive buffer to memory queue.
*/ */
@ -332,8 +288,7 @@ static void el3_interrupt(dpeth_t * dep)
DEBUG(printf("3c509: got Tx interrupt, Status=0x%04x\n", isr);) DEBUG(printf("3c509: got Tx interrupt, Status=0x%04x\n", isr);)
dep->de_flags &= NOT(DEF_XMIT_BUSY); dep->de_flags &= NOT(DEF_XMIT_BUSY);
outw_el3(dep, REG_CmdStatus, CMD_Acknowledge | INT_TxAvailable); outw_el3(dep, REG_CmdStatus, CMD_Acknowledge | INT_TxAvailable);
if (dep->de_flags & DEF_SENDING) /* Send pending */ netdriver_send();
el3_send(dep, TRUE, dep->de_send_s);
} }
if (isr & (INT_AdapterFail | INT_RxEarly | INT_UpdateStats)) { if (isr & (INT_AdapterFail | INT_RxEarly | INT_UpdateStats)) {
@ -354,11 +309,10 @@ static void el3_interrupt(dpeth_t * dep)
/* Acknowledge interrupt */ /* Acknowledge interrupt */
outw_el3(dep, REG_CmdStatus, CMD_Acknowledge | (INT_Latch | INT_Requested)); outw_el3(dep, REG_CmdStatus, CMD_Acknowledge | (INT_Latch | INT_Requested));
} }
return;
} }
/* /*
** Name: unsigned el3_read_eeprom(port_t port, unsigned address); ** Name: el3_read_eeprom
** Function: Reads the EEPROM at specified address ** Function: Reads the EEPROM at specified address
*/ */
static unsigned el3_read_eeprom(port_t port, unsigned address) static unsigned el3_read_eeprom(port_t port, unsigned address)
@ -368,7 +322,7 @@ static unsigned el3_read_eeprom(port_t port, unsigned address)
address |= EL3_READ_EEPROM; address |= EL3_READ_EEPROM;
outb(port, address); outb(port, address);
milli_delay(5); /* Allows EEPROM reads */ micro_delay(5000); /* Allows EEPROM reads */
for (result = 0, bit = 16; bit > 0; bit -= 1) { for (result = 0, bit = 16; bit > 0; bit -= 1) {
result = (result << 1) | (inb(port) & 0x0001); result = (result << 1) | (inb(port) & 0x0001);
} }
@ -376,7 +330,7 @@ static unsigned el3_read_eeprom(port_t port, unsigned address)
} }
/* /*
** Name: void el3_read_StationAddress(dpeth_t *dep) ** Name: el3_read_StationAddress
** Function: Reads station address from board ** Function: Reads station address from board
*/ */
static void el3_read_StationAddress(dpeth_t * dep) static void el3_read_StationAddress(dpeth_t * dep)
@ -390,11 +344,10 @@ static void el3_read_StationAddress(dpeth_t * dep)
dep->de_address.ea_addr[ix++] = (rc >> 8) & 0xFF; dep->de_address.ea_addr[ix++] = (rc >> 8) & 0xFF;
dep->de_address.ea_addr[ix++] = rc & 0xFF; dep->de_address.ea_addr[ix++] = rc & 0xFF;
} }
return;
} }
/* /*
** Name: void el3_open(dpeth_t *dep) ** Name: el3_open
** Function: Initalizes board hardware and driver data structures. ** Function: Initalizes board hardware and driver data structures.
*/ */
static void el3_open(dpeth_t * dep) static void el3_open(dpeth_t * dep)
@ -440,7 +393,7 @@ static void el3_open(dpeth_t * dep)
if (dep->de_if_port == BNC_XCVR) { if (dep->de_if_port == BNC_XCVR) {
/* Start internal transceiver for Coaxial cable */ /* Start internal transceiver for Coaxial cable */
outw_el3(dep, REG_CmdStatus, CMD_StartIntXcvr); outw_el3(dep, REG_CmdStatus, CMD_StartIntXcvr);
milli_delay(5); micro_delay(5000);
} else if (dep->de_if_port == TP_XCVR) { } else if (dep->de_if_port == TP_XCVR) {
/* Start internal transceiver for Twisted pair cable */ /* Start internal transceiver for Twisted pair cable */
@ -497,12 +450,10 @@ static void el3_open(dpeth_t * dep)
for (ix = 0; ix < SA_ADDR_LEN; ix += 1) for (ix = 0; ix < SA_ADDR_LEN; ix += 1)
printf("%02X%c", dep->de_address.ea_addr[ix], printf("%02X%c", dep->de_address.ea_addr[ix],
ix < SA_ADDR_LEN - 1 ? ':' : '\n'); ix < SA_ADDR_LEN - 1 ? ':' : '\n');
return; /* Done */
} }
/* /*
** Name: unsigned int el3_checksum(port_t port); ** Name: int el3_checksum
** Function: Reads EEPROM and computes checksum. ** Function: Reads EEPROM and computes checksum.
*/ */
static unsigned short el3_checksum(port_t port) static unsigned short el3_checksum(port_t port)
@ -534,7 +485,7 @@ static unsigned short el3_checksum(port_t port)
} }
/* /*
** Name: void el3_write_id(port_t port); ** Name: el3_write_id
** Function: Writes the ID sequence to the board. ** Function: Writes the ID sequence to the board.
*/ */
static void el3_write_id(port_t port) static void el3_write_id(port_t port)
@ -548,11 +499,10 @@ static void el3_write_id(port_t port)
pattern <<= 1; pattern <<= 1;
pattern = (pattern & 0x0100) ? pattern ^ 0xCF : pattern; pattern = (pattern & 0x0100) ? pattern ^ 0xCF : pattern;
} }
return;
} }
/* /*
** Name: int el3_probe(dpeth_t *dep) ** Name: el3_probe
** Function: Checks for presence of the board. ** Function: Checks for presence of the board.
*/ */
int el3_probe(dpeth_t * dep) int el3_probe(dpeth_t * dep)
@ -572,10 +522,10 @@ int el3_probe(dpeth_t * dep)
el3_write_id(id_port); el3_write_id(id_port);
outb(id_port, EL3_ID_GLOBAL_RESET); /* Reset the board */ outb(id_port, EL3_ID_GLOBAL_RESET); /* Reset the board */
milli_delay(5); /* Technical reference says 162 micro sec. */ micro_delay(5000); /* Technical reference says 162 micro sec. */
el3_write_id(id_port); el3_write_id(id_port);
outb(id_port, EL3_SET_TAG_REGISTER); outb(id_port, EL3_SET_TAG_REGISTER);
milli_delay(5); micro_delay(5000);
dep->de_id_port = id_port; /* Stores ID port No. */ dep->de_id_port = id_port; /* Stores ID port No. */
dep->de_ramsize = /* RAM size is meaningless */ dep->de_ramsize = /* RAM size is meaningless */

View File

@ -1,4 +1,3 @@
#include <assert.h>
/* /*
** File: 8390.c May 02, 2000 ** File: 8390.c May 02, 2000
** **
@ -12,32 +11,18 @@
*/ */
#include <minix/drivers.h> #include <minix/drivers.h>
#include <minix/com.h> #include <minix/netdriver.h>
#include <net/gen/ether.h> #include <net/gen/ether.h>
#include <net/gen/eth_io.h> #include <net/gen/eth_io.h>
#include <assert.h>
#include "dp.h" #include "dp.h"
#if (ENABLE_DP8390 == 1) #if (ENABLE_DP8390 == 1)
#define PIO16 0 /* NOTE: pio 16 functions missing */
#include "8390.h" #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)
#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 char RdmaErrMsg[] = "remote dma failed to complete";
/* /*
** Name: void ns_rw_setup(dpeth_t *dep, int mode, int size, u16_t offset); ** Name: ns_rw_setup
** Function: Sets the board for reading/writing. ** Function: Sets the board for reading/writing.
*/ */
static void ns_rw_setup(const dpeth_t *dep, int mode, int size, u16_t offset) static void ns_rw_setup(const dpeth_t *dep, int mode, int size, u16_t offset)
@ -50,11 +35,10 @@ static void ns_rw_setup(const dpeth_t *dep, int mode, int size, u16_t offset)
outb_reg0(dep, DP_RSAR1, (offset >> 8) & 0xFF); outb_reg0(dep, DP_RSAR1, (offset >> 8) & 0xFF);
mode |= (CR_PS_P0 | CR_STA); mode |= (CR_PS_P0 | CR_STA);
outb_reg0(dep, DP_CR, mode); outb_reg0(dep, DP_CR, mode);
return;
} }
/* /*
** Name: void ns_start_xmit(dpeth_t *dep, int size, int pageno); ** Name: ns_start_xmit
** Function: Sets the board for for transmitting and fires it. ** Function: Sets the board for for transmitting and fires it.
*/ */
static void ns_start_xmit(const dpeth_t * dep, int size, int pageno) static void ns_start_xmit(const dpeth_t * dep, int size, int pageno)
@ -64,110 +48,58 @@ static void ns_start_xmit(const dpeth_t * dep, int size, int pageno)
outb_reg0(dep, DP_TBCR1, size >> 8); outb_reg0(dep, DP_TBCR1, size >> 8);
outb_reg0(dep, DP_TBCR0, size & 0xFF); outb_reg0(dep, DP_TBCR0, size & 0xFF);
outb_reg0(dep, DP_CR, CR_NO_DMA | CR_STA | CR_TXP); /* Fires transmission */ outb_reg0(dep, DP_CR, CR_NO_DMA | CR_STA | CR_TXP); /* Fires transmission */
return;
} }
/* /*
** Name: void mem_getblock(dpeth_t *dep, u16_t offset, ** Name: mem_getblock
** int size, void *dst)
** Function: Reads a block of packet from board (shared memory). ** Function: Reads a block of packet from board (shared memory).
*/ */
static void mem_getblock(dpeth_t *dep, u16_t offset, int size, void *dst) static void mem_getblock(dpeth_t *dep, u16_t offset, int size, void *dst)
{ {
panic("mem_getblock: not converted to safecopies");
#if 0 assert(offset + size <= dep->de_ramsize);
sys_nic2mem(dep->de_linmem + offset, SELF, dst, size);
return; memcpy(dst, dep->de_locmem + offset, size);
#endif
} }
/* /*
** Name: void mem_nic2user(dpeth_t *dep, int pageno, int pktsize); ** Name: mem_nic2user
** Function: Copies a packet from board to user area (shared memory). ** Function: Copies a packet from board to user area (shared memory).
*/ */
static void mem_nic2user(dpeth_t * dep, int pageno, int pktsize) static void mem_nic2user(dpeth_t *dep, int pageno, struct netdriver_data *data,
size_t size)
{ {
panic("mem_nic2user: not converted to safecopies"); size_t offset, left;
#if 0
phys_bytes offset;
iovec_dat_s_t *iovp = &dep->de_read_iovec;
int bytes, ix = 0;
/* Computes shared memory address (skipping receive header) */ /* Computes shared memory address (skipping receive header) */
offset = pageno * DP_PAGESIZE + sizeof(dp_rcvhdr_t); offset = pageno * DP_PAGESIZE + sizeof(dp_rcvhdr_t);
do { /* Reads chuncks of packet into user area */ if (offset + size > dep->de_stoppage * DP_PAGESIZE) {
left = dep->de_stoppage * DP_PAGESIZE - offset;
bytes = iovp->iod_iovec[ix].iov_size; /* Size of a chunck */ netdriver_copyout(data, 0, dep->de_locmem + offset, left);
if (bytes > pktsize) bytes = pktsize; offset = dep->de_startpage * DP_PAGESIZE;
netdriver_copyout(data, left, dep->de_locmem + offset, size - left);
/* Reads from board to user area */ } else
if ((offset + bytes) > (dep->de_stoppage * DP_PAGESIZE)) { netdriver_copyout(data, 0, dep->de_locmem + offset, size);
/* Circular buffer wrap-around */
bytes = dep->de_stoppage * DP_PAGESIZE - offset;
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_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 */
dp_next_iovec(iovp);
ix = 0;
}
/* Till packet done */
} while ((pktsize -= bytes) > 0);
return;
#endif
} }
/* /*
** Name: void mem_user2nic(dpeth_t *dep, int pageno, int pktsize) ** Name: mem_user2nic
** Function: Copies a packet from user area to board (shared memory). ** Function: Copies a packet from user area to board (shared memory).
*/ */
static void mem_user2nic(dpeth_t *dep, int pageno, int pktsize) static void mem_user2nic(dpeth_t *dep, int pageno, struct netdriver_data *data,
size_t size)
{ {
#if 1 size_t offset;
panic("mem_user2nic: not converted to safecopies");
#else
phys_bytes offset, phys_user;
iovec_dat_s_t *iovp = &dep->de_write_iovec;
int bytes, ix = 0;
/* Computes shared memory address */ /* Computes shared memory address */
offset = pageno * DP_PAGESIZE; offset = pageno * DP_PAGESIZE;
do { /* Reads chuncks of packet from user area */ netdriver_copyin(data, 0, dep->de_locmem + offset, size);
bytes = iovp->iod_iovec[ix].iov_size; /* Size of chunck */
if (bytes > pktsize) bytes = pktsize;
/* Reads from user area to board (shared memory) */
sys_user2nic_s(iovp->iod_proc_nr, iovp->iod_iovec[ix].iov_grant,
dep->de_linmem + offset, bytes);
offset += bytes;
if (++ix >= IOVEC_NR) { /* Next buffer of IO vector */
dp_next_iovec(iovp);
ix = 0;
}
/* Till packet done */
} while ((pktsize -= bytes) > 0);
return;
#endif
} }
/* /*
** Name: void pio_getblock(dpeth_t *dep, u16_t offset, ** Name: pio_getblock
** int size, void *dst)
** Function: Reads a block of packet from board (Prog. I/O). ** Function: Reads a block of packet from board (Prog. I/O).
*/ */
static void pio_getblock(dpeth_t *dep, u16_t offset, int size, void *dst) static void pio_getblock(dpeth_t *dep, u16_t offset, int size, void *dst)
@ -176,110 +108,72 @@ static void pio_getblock(dpeth_t *dep, u16_t offset, int size, void *dst)
/* Sets up board for reading */ /* Sets up board for reading */
ns_rw_setup(dep, CR_DM_RR, size, offset); ns_rw_setup(dep, CR_DM_RR, size, offset);
#if PIO16 == 0 if (dep->de_16bit == TRUE)
insb(dep->de_data_port, SELF, dst, size);
#else
if (dep->de_16bit == TRUE) {
insw(dep->de_data_port, dst, size); insw(dep->de_data_port, dst, size);
} else { else
insb(dep->de_data_port, dst, size); insb(dep->de_data_port, dst, size);
}
#endif
return;
} }
/* /*
** Name: void pio_nic2user(dpeth_t *dep, int pageno, int pktsize) ** Name: pio_nic2user
** Function: Copies a packet from board to user area (Prog. I/O). ** Function: Copies a packet from board to user area (Prog. I/O).
*/ */
static void pio_nic2user(dpeth_t *dep, int pageno, int pktsize) static void pio_nic2user(dpeth_t *dep, int pageno, struct netdriver_data *data,
size_t size)
{ {
iovec_dat_s_t *iovp = &dep->de_read_iovec; size_t offset, left;
unsigned offset, iov_offset; int r, bytes, ix = 0;
/* Computes memory address (skipping receive header) */ /* Computes memory address (skipping receive header) */
offset = pageno * DP_PAGESIZE + sizeof(dp_rcvhdr_t); offset = pageno * DP_PAGESIZE + sizeof(dp_rcvhdr_t);
/* Sets up board for reading */
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; if (offset + size > dep->de_stoppage * DP_PAGESIZE) {
do { /* Reads chuncks of packet into user area */ left = dep->de_stoppage * DP_PAGESIZE - offset;
bytes = iovp->iod_iovec[ix].iov_size; /* Size of a chunck */ ns_rw_setup(dep, CR_DM_RR, left, offset);
if (bytes > pktsize) bytes = pktsize;
if ((offset + bytes) > (dep->de_stoppage * DP_PAGESIZE)) { if (dep->de_16bit)
netdriver_portinw(data, 0, dep->de_data_port, left);
else
netdriver_portinb(data, 0, dep->de_data_port, left);
/* Circular buffer wrap-around */ offset = dep->de_startpage * DP_PAGESIZE;
bytes = dep->de_stoppage * DP_PAGESIZE - offset; } else
r= sys_safe_insb(dep->de_data_port, iovp->iod_proc_nr, left = 0;
iovp->iod_iovec[ix].iov_grant, iov_offset, bytes);
if (r != OK) {
panic("pio_nic2user: sys_safe_insb failed: %d", r);
}
pktsize -= 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);
}
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("pio_nic2user: sys_safe_insb failed: %d", r);
offset += bytes;
if (++ix >= IOVEC_NR) { /* Next buffer of IO vector */ ns_rw_setup(dep, CR_DM_RR, size - left, offset);
dp_next_iovec(iovp);
ix = 0; if (dep->de_16bit)
} netdriver_portinw(data, left, dep->de_data_port, size - left);
iov_offset= 0; else
/* Till packet done */ netdriver_portinb(data, left, dep->de_data_port, size - left);
} while ((pktsize -= bytes) > 0);
return;
} }
/* /*
** Name: void pio_user2nic(dpeth_t *dep, int pageno, int pktsize) ** Name: pio_user2nic
** Function: Copies a packet from user area to board (Prog. I/O). ** Function: Copies a packet from user area to board (Prog. I/O).
*/ */
static void pio_user2nic(dpeth_t *dep, int pageno, int pktsize) static void pio_user2nic(dpeth_t *dep, int pageno, struct netdriver_data *data,
size_t size)
{ {
iovec_dat_s_t *iovp = &dep->de_write_iovec; int ix;
int r, bytes, ix = 0;
/* Sets up board for writing */ /* Sets up board for writing */
ns_rw_setup(dep, CR_DM_RW, pktsize, pageno * DP_PAGESIZE); ns_rw_setup(dep, CR_DM_RW, size, pageno * DP_PAGESIZE);
do { /* Reads chuncks of packet from user area */ if (dep->de_16bit)
netdriver_portoutw(data, 0, dep->de_data_port, size);
bytes = iovp->iod_iovec[ix].iov_size; /* Size of chunck */ else
if (bytes > pktsize) bytes = pktsize; netdriver_portoutb(data, 0, dep->de_data_port, size);
r= sys_safe_outsb(dep->de_data_port, iovp->iod_proc_nr,
iovp->iod_iovec[ix].iov_grant, 0, bytes);
if (r != OK)
panic("pio_user2nic: sys_safe_outsb failed: %d", r);
if (++ix >= IOVEC_NR) { /* Next buffer of I/O vector */
dp_next_iovec(iovp);
ix = 0;
}
/* Till packet done */
} while ((pktsize -= bytes) > 0);
for (ix = 0; ix < 100; ix += 1) { for (ix = 0; ix < 100; ix += 1) {
if (inb_reg0(dep, DP_ISR) & ISR_RDC) break; if (inb_reg0(dep, DP_ISR) & ISR_RDC) break;
} }
if (ix == 100) { if (ix == 100)
panic("%s", RdmaErrMsg); panic("remote dma failed to complete");
}
return;
} }
/* /*
** Name: void ns_stats(dpeth_t * dep) ** Name: ns_stats
** Function: Updates counters reading from device ** Function: Updates counters reading from device
*/ */
static void ns_stats(dpeth_t * dep) static void ns_stats(dpeth_t * dep)
@ -288,22 +182,20 @@ static void ns_stats(dpeth_t * dep)
dep->de_stat.ets_CRCerr += inb_reg0(dep, DP_CNTR0); dep->de_stat.ets_CRCerr += inb_reg0(dep, DP_CNTR0);
dep->de_stat.ets_recvErr += inb_reg0(dep, DP_CNTR1); dep->de_stat.ets_recvErr += inb_reg0(dep, DP_CNTR1);
dep->de_stat.ets_fifoOver += inb_reg0(dep, DP_CNTR2); dep->de_stat.ets_fifoOver += inb_reg0(dep, DP_CNTR2);
return;
} }
/* /*
** Name: void ns_dodump(dpeth_t * dep) ** Name: ns_dodump
** Function: Displays statistics (a request from F5 key). ** Function: Displays statistics (a request from a function key).
*/ */
static void ns_dodump(dpeth_t * dep) static void ns_dodump(dpeth_t * dep)
{ {
ns_stats(dep); /* Forces reading fo counters from board */ ns_stats(dep); /* Forces reading of counters from board */
return;
} }
/* /*
** Name: void ns_reinit(dpeth_t *dep) ** Name: ns_reinit
** Function: Updates receiver configuration. ** Function: Updates receiver configuration.
*/ */
static void ns_reinit(dpeth_t * dep) static void ns_reinit(dpeth_t * dep)
@ -315,26 +207,24 @@ static void ns_reinit(dpeth_t * dep)
if (dep->de_flags & DEF_MULTI) dp_reg |= RCR_AM; if (dep->de_flags & DEF_MULTI) dp_reg |= RCR_AM;
outb_reg0(dep, DP_CR, CR_PS_P0); outb_reg0(dep, DP_CR, CR_PS_P0);
outb_reg0(dep, DP_RCR, dp_reg); outb_reg0(dep, DP_RCR, dp_reg);
return;
} }
/* /*
** Name: void ns_send(dpeth_t * dep, int from_int, int size) ** Name: ns_send
** Function: Transfers packet to device and starts sending. ** Function: Transfers packet to device and starts sending.
*/ */
static void ns_send(dpeth_t * dep, int from_int, int size) static int ns_send(dpeth_t *dep, struct netdriver_data *data, size_t size)
{ {
int queue; int queue;
if (queue = dep->de_sendq_head, dep->de_sendq[queue].sq_filled) { queue = dep->de_sendq_head;
if (from_int) panic("should not be sending "); if (dep->de_sendq[queue].sq_filled)
dep->de_send_s = size; return SUSPEND;
return;
} (dep->de_user2nicf)(dep, dep->de_sendq[queue].sq_sendpage, data, size);
(dep->de_user2nicf) (dep, dep->de_sendq[queue].sq_sendpage, size);
dep->bytes_Tx += (long) size; dep->bytes_Tx += (long) size;
dep->de_sendq[queue].sq_filled = TRUE; dep->de_sendq[queue].sq_filled = TRUE;
dep->de_flags |= (DEF_XMIT_BUSY | DEF_ACK_SEND); dep->de_flags |= DEF_XMIT_BUSY;
if (dep->de_sendq_tail == queue) { /* there it goes.. */ if (dep->de_sendq_tail == queue) { /* there it goes.. */
ns_start_xmit(dep, size, dep->de_sendq[queue].sq_sendpage); ns_start_xmit(dep, size, dep->de_sendq[queue].sq_sendpage);
} else } else
@ -342,13 +232,12 @@ static void ns_send(dpeth_t * dep, int from_int, int size)
if (++queue == dep->de_sendq_nr) queue = 0; if (++queue == dep->de_sendq_nr) queue = 0;
dep->de_sendq_head = queue; dep->de_sendq_head = queue;
dep->de_flags &= NOT(DEF_SENDING);
return; return OK;
} }
/* /*
** Name: void ns_reset(dpeth_t *dep) ** Name: ns_reset
** Function: Resets device. ** Function: Resets device.
*/ */
static void ns_reset(dpeth_t * dep) static void ns_reset(dpeth_t * dep)
@ -359,14 +248,14 @@ static void ns_reset(dpeth_t * dep)
outb_reg0(dep, DP_CR, CR_STP | CR_NO_DMA); outb_reg0(dep, DP_CR, CR_STP | CR_NO_DMA);
outb_reg0(dep, DP_RBCR0, 0); outb_reg0(dep, DP_RBCR0, 0);
outb_reg0(dep, DP_RBCR1, 0); outb_reg0(dep, DP_RBCR1, 0);
for (ix = 0; ix < 0x1000 && ((inb_reg0(dep, DP_ISR) & ISR_RST) == 0); ix += 1) for (ix = 0; ix < 0x1000 && (inb_reg0(dep, DP_ISR) & ISR_RST) == 0; ix += 1)
/* Do nothing */ ; /* Do nothing */ ;
outb_reg0(dep, DP_TCR, TCR_1EXTERNAL | TCR_OFST); outb_reg0(dep, DP_TCR, TCR_1EXTERNAL | TCR_OFST);
outb_reg0(dep, DP_CR, CR_STA | CR_NO_DMA); outb_reg0(dep, DP_CR, CR_STA | CR_NO_DMA);
outb_reg0(dep, DP_TCR, TCR_NORMAL | TCR_OFST); outb_reg0(dep, DP_TCR, TCR_NORMAL | TCR_OFST);
/* Acknowledge the ISR_RDC (remote dma) interrupt. */ /* Acknowledge the ISR_RDC (remote dma) interrupt. */
for (ix = 0; ix < 0x1000 && ((inb_reg0(dep, DP_ISR) & ISR_RDC) == 0); ix += 1) for (ix = 0; ix < 0x1000 && (inb_reg0(dep, DP_ISR) & ISR_RDC) == 0; ix += 1)
/* Do nothing */ ; /* Do nothing */ ;
outb_reg0(dep, DP_ISR, inb_reg0(dep, DP_ISR) & NOT(ISR_RDC)); outb_reg0(dep, DP_ISR, inb_reg0(dep, DP_ISR) & NOT(ISR_RDC));
@ -376,19 +265,18 @@ static void ns_reset(dpeth_t * dep)
dep->de_sendq_head = dep->de_sendq_tail = 0; dep->de_sendq_head = dep->de_sendq_tail = 0;
for (ix = 0; ix < dep->de_sendq_nr; ix++) for (ix = 0; ix < dep->de_sendq_nr; ix++)
dep->de_sendq[ix].sq_filled = FALSE; dep->de_sendq[ix].sq_filled = FALSE;
ns_send(dep, TRUE, dep->de_send_s); netdriver_send();
return;
} }
/* /*
** Name: void ns_recv(dpeth_t *dep, int fromint, int size) ** Name: ns_recv
** Function: Gets a packet from device ** Function: Gets a packet from device
*/ */
static void ns_recv(dpeth_t *dep, int fromint, int size) static ssize_t ns_recv(dpeth_t *dep, struct netdriver_data *data, size_t max)
{ {
dp_rcvhdr_t header; dp_rcvhdr_t header;
unsigned pageno, curr, next; unsigned pageno, curr, next;
vir_bytes length; size_t length;
int packet_processed = FALSE; int packet_processed = FALSE;
#ifdef ETH_IGN_PROTO #ifdef ETH_IGN_PROTO
u16_t eth_type; u16_t eth_type;
@ -403,17 +291,21 @@ static void ns_recv(dpeth_t *dep, int fromint, int size)
curr = inb_reg1(dep, DP_CURR); curr = inb_reg1(dep, DP_CURR);
outb_reg0(dep, DP_CR, CR_PS_P0 | CR_NO_DMA | CR_STA); outb_reg0(dep, DP_CR, CR_PS_P0 | CR_NO_DMA | CR_STA);
if (curr == pageno) break; if (curr == pageno)
return SUSPEND;
(dep->de_getblockf) (dep, pageno * DP_PAGESIZE, sizeof(header), &header); (dep->de_getblockf)(dep, pageno * DP_PAGESIZE, sizeof(header),
&header);
#ifdef ETH_IGN_PROTO #ifdef ETH_IGN_PROTO
(dep->de_getblockf) (dep, pageno * DP_PAGESIZE + sizeof(header) + 2 * sizeof(ether_addr_t), sizeof(eth_type), &eth_type); (dep->de_getblockf)(dep, pageno * DP_PAGESIZE + sizeof(header) +
2 * sizeof(ether_addr_t), sizeof(eth_type), &eth_type);
#endif #endif
length = (header.dr_rbcl | (header.dr_rbch << 8)) - sizeof(dp_rcvhdr_t); length = (header.dr_rbcl | (header.dr_rbch << 8)) -
sizeof(dp_rcvhdr_t);
next = header.dr_next; next = header.dr_next;
if (length < ETH_MIN_PACK_SIZE || length > ETH_MAX_PACK_SIZE) { if (length < ETH_MIN_PACK_SIZE || length > max) {
printf("%s: packet with strange length arrived: %ld\n", printf("%s: packet with strange length arrived: %zu\n",
dep->de_name, length); dep->de_name, length);
dep->de_stat.ets_recvErr += 1; dep->de_stat.ets_recvErr += 1;
next = curr; next = curr;
@ -422,50 +314,40 @@ static void ns_recv(dpeth_t *dep, int fromint, int size)
printf("%s: strange next page\n", dep->de_name); printf("%s: strange next page\n", dep->de_name);
dep->de_stat.ets_recvErr += 1; dep->de_stat.ets_recvErr += 1;
next = curr; next = curr;
#ifdef ETH_IGN_PROTO #ifdef ETH_IGN_PROTO
} else if (eth_type == eth_ign_proto) { } else if (eth_type == eth_ign_proto) {
/* Hack: ignore packets of a given protocol */ /* Hack: ignore packets of a given protocol */
static int first = TRUE; static int first = TRUE;
if (first) { if (first) {
first = FALSE; first = FALSE;
printf("%s: dropping proto %04x packet\n", dep->de_name, ntohs(eth_ign_proto)); printf("%s: dropping proto %04x packet\n",
dep->de_name, ntohs(eth_ign_proto));
} }
next = curr; next = curr;
#endif #endif
} else if (header.dr_status & RSR_FO) { } else if (header.dr_status & RSR_FO) {
/* This is very serious, issue a warning and reset buffers */ /* This is very serious, issue a warning and reset buffers */
printf("%s: fifo overrun, resetting receive buffer\n", dep->de_name); printf("%s: fifo overrun, resetting receive buffer\n",
dep->de_name);
dep->de_stat.ets_fifoOver += 1; dep->de_stat.ets_fifoOver += 1;
next = curr; next = curr;
} else if ((header.dr_status & RSR_PRX) && (dep->de_flags & DEF_ENABLED)) { } else if (header.dr_status & RSR_PRX) {
(dep->de_nic2userf)(dep, pageno, data, length);
if (!(dep->de_flags & DEF_READING)) break;
(dep->de_nic2userf) (dep, pageno, length);
dep->de_read_s = length;
dep->de_flags |= DEF_ACK_RECV;
dep->de_flags &= NOT(DEF_READING);
packet_processed = TRUE; packet_processed = TRUE;
} }
dep->bytes_Rx += (long) length; dep->bytes_Rx += (long) length;
dep->de_stat.ets_packetR += 1; dep->de_stat.ets_packetR += 1;
outb_reg0(dep, DP_BNRY, (next == dep->de_startpage ? dep->de_stoppage : next) - 1); outb_reg0(dep, DP_BNRY,
(next == dep->de_startpage ? dep->de_stoppage : next) - 1);
pageno = next; pageno = next;
} while (!packet_processed); } while (!packet_processed);
#if 0
if ((dep->de_flags & (DEF_READING | DEF_STOPPED)) == (DEF_READING | DEF_STOPPED)) return length;
/* The chip is stopped, and all arrived packets delivered */
(*dep->de_resetf) (dep);
dep->de_flags &= NOT(DEF_STOPPED);
#endif
return;
} }
/* /*
** Name: void ns_interrupt(dpeth_t * dep) ** Name: ns_interrupt
** Function: Handles interrupt. ** Function: Handles interrupt.
*/ */
static void ns_interrupt(dpeth_t * dep) static void ns_interrupt(dpeth_t * dep)
@ -487,13 +369,15 @@ static void ns_interrupt(dpeth_t * dep)
dep->de_stat.ets_fifoUnder++; dep->de_stat.ets_fifoUnder++;
} }
if ((isr & ISR_TXE) || (tsr & (TSR_CRS | TSR_CDH | TSR_OWC))) { if ((isr & ISR_TXE) || (tsr & (TSR_CRS | TSR_CDH | TSR_OWC))) {
printf("%s: got send Error (0x%02X)\n", dep->de_name, tsr); printf("%s: got send Error (0x%02X)\n",
dep->de_name, tsr);
dep->de_stat.ets_sendErr++; dep->de_stat.ets_sendErr++;
} }
queue = dep->de_sendq_tail; queue = dep->de_sendq_tail;
if (!(dep->de_sendq[queue].sq_filled)) { /* Hardware bug? */ if (!(dep->de_sendq[queue].sq_filled)) { /* Hardware bug? */
printf("%s: transmit interrupt, but not sending\n", dep->de_name); printf("%s: transmit interrupt, but not sending\n",
dep->de_name);
continue; continue;
} }
dep->de_sendq[queue].sq_filled = FALSE; dep->de_sendq[queue].sq_filled = FALSE;
@ -503,15 +387,14 @@ static void ns_interrupt(dpeth_t * dep)
ns_start_xmit(dep, dep->de_sendq[queue].sq_size, ns_start_xmit(dep, dep->de_sendq[queue].sq_size,
dep->de_sendq[queue].sq_sendpage); dep->de_sendq[queue].sq_sendpage);
} }
if (dep->de_flags & DEF_SENDING) { netdriver_send();
ns_send(dep, TRUE, dep->de_send_s);
}
} }
if (isr & ISR_PRX) { if (isr & ISR_PRX) {
ns_recv(dep, TRUE, 0); netdriver_recv();
} }
if (isr & ISR_RXE) { if (isr & ISR_RXE) {
printf("%s: got recv Error (0x%04X)\n", dep->de_name, inb_reg0(dep, DP_RSR)); printf("%s: got recv Error (0x%04X)\n",
dep->de_name, inb_reg0(dep, DP_RSR));
dep->de_stat.ets_recvErr++; dep->de_stat.ets_recvErr++;
} }
if (isr & ISR_CNT) { if (isr & ISR_CNT) {
@ -526,26 +409,21 @@ static void ns_interrupt(dpeth_t * dep)
/* Nothing to do */ /* Nothing to do */
} }
if (isr & ISR_RST) { if (isr & ISR_RST) {
/* This means we got an interrupt but the ethernet /* This means we got an interrupt but the ethernet chip is shut
* chip is shutdown. We set the flag DEF_STOPPED, and * down. We reset the chip right away, possibly losing received
* continue processing arrived packets. When the * packets in the process. There used to be a more elaborate
* receive buffer is empty, we reset the dp8390. */ * approach of resetting only after all pending packets had
* been accepted, but it was broken and this is simpler anyway.
*/
printf("%s: network interface stopped\n", dep->de_name); printf("%s: network interface stopped\n", dep->de_name);
dep->de_flags |= DEF_STOPPED; ns_reset(dep);
break; break;
} }
} }
if ((dep->de_flags & (DEF_READING | DEF_STOPPED)) == (DEF_READING | DEF_STOPPED)) {
/* The chip is stopped, and all arrived packets delivered */
ns_reset(dep);
dep->de_flags &= NOT(DEF_STOPPED);
}
return;
} }
/* /*
** Name: void ns_init(dpeth_t *dep) ** Name: ns_init
** Function: Initializes the NS 8390 ** Function: Initializes the NS 8390
*/ */
void ns_init(dpeth_t * dep) void ns_init(dpeth_t * dep)
@ -555,12 +433,8 @@ void ns_init(dpeth_t * dep)
/* NS8390 initialization (as recommended in National Semiconductor specs) */ /* NS8390 initialization (as recommended in National Semiconductor specs) */
outb_reg0(dep, DP_CR, CR_PS_P0 | CR_STP | CR_NO_DMA); /* 0x21 */ outb_reg0(dep, DP_CR, CR_PS_P0 | CR_STP | CR_NO_DMA); /* 0x21 */
#if PIO16 == 0
outb_reg0(dep, DP_DCR, (DCR_BYTEWIDE | DCR_LTLENDIAN | DCR_8BYTES | DCR_BMS));
#else
outb_reg0(dep, DP_DCR, (((dep->de_16bit) ? DCR_WORDWIDE : DCR_BYTEWIDE) | outb_reg0(dep, DP_DCR, (((dep->de_16bit) ? DCR_WORDWIDE : DCR_BYTEWIDE) |
DCR_LTLENDIAN | DCR_8BYTES | DCR_BMS)); DCR_LTLENDIAN | DCR_8BYTES | DCR_BMS));
#endif
outb_reg0(dep, DP_RBCR0, 0); outb_reg0(dep, DP_RBCR0, 0);
outb_reg0(dep, DP_RBCR1, 0); outb_reg0(dep, DP_RBCR1, 0);
outb_reg0(dep, DP_RCR, RCR_MON); /* Sets Monitor mode */ outb_reg0(dep, DP_RCR, RCR_MON); /* Sets Monitor mode */
@ -609,13 +483,9 @@ void ns_init(dpeth_t * dep)
dep->de_nic2userf = mem_nic2user; dep->de_nic2userf = mem_nic2user;
dep->de_getblockf = mem_getblock; dep->de_getblockf = mem_getblock;
} else { } else {
#if PIO16 == 0
dep->de_user2nicf = pio_user2nic; dep->de_user2nicf = pio_user2nic;
dep->de_nic2userf = pio_nic2user; dep->de_nic2userf = pio_nic2user;
dep->de_getblockf = pio_getblock; dep->de_getblockf = pio_getblock;
#else
#error Missing I/O functions for pio 16 bits
#endif
} }
dep->de_recvf = ns_recv; dep->de_recvf = ns_recv;
dep->de_sendf = ns_send; dep->de_sendf = ns_send;
@ -624,135 +494,8 @@ void ns_init(dpeth_t * dep)
dep->de_getstatsf = ns_stats; dep->de_getstatsf = ns_stats;
dep->de_dumpstatsf = ns_dodump; dep->de_dumpstatsf = ns_dodump;
dep->de_interruptf = ns_interrupt; dep->de_interruptf = ns_interrupt;
return; /* Done */
} }
#if PIO16 == 1
/*
** Name: void dp_pio16_user2nic(dpeth_t *dep, int pageno, int pktsize)
** Function: Copies a packet from user area to board (Prog. I/O, 16bits).
*/
static void dp_pio16_user2nic(dpeth_t *dep, int pageno, int pktsize)
{
u8_t two_bytes[2];
phys_bytes phys_user, phys_2bytes = vir2phys(two_bytes);
vir_bytes ecount = (pktsize + 1) & NOT(0x0001);
int bytes, ix = 0, odd_byte = 0;
iovec_dat_t *iovp = &dep->de_write_iovec;
outb_reg0(dep, DP_ISR, ISR_RDC);
dp_read_setup(dep, ecount, pageno * DP_PAGESIZE);
do {
bytes = iovp->iod_iovec[ix].iov_size;
if (bytes > pktsize) bytes = pktsize;
phys_user = numap(iovp->iod_proc_nr, iovp->iod_iovec[ix].iov_addr, bytes);
if (!phys_user) panic(UmapErrMsg);
if (odd_byte) {
phys_copy(phys_user, phys_2bytes + 1, (phys_bytes) 1);
out_word(dep->de_data_port, *(u16_t *)two_bytes);
pktsize--;
bytes--;
phys_user++;
odd_byte = 0;
if (!bytes) continue;
}
ecount = bytes & NOT(0x0001);
if (ecount != 0) {
phys_outsw(dep->de_data_port, phys_user, ecount);
pktsize -= ecount;
bytes -= ecount;
phys_user += ecount;
}
if (bytes) {
phys_copy(phys_user, phys_2bytes, (phys_bytes) 1);
pktsize--;
bytes--;
phys_user++;
odd_byte = 1;
}
if (++ix >= IOVEC_NR) { /* Next buffer of I/O vector */
dp_next_iovec(iovp);
ix = 0;
}
} while (bytes > 0);
if (odd_byte) out_word(dep->de_data_port, *(u16_t *) two_bytes);
for (ix = 0; ix < 100; ix++) {
if (inb_reg0(dep, DP_ISR) & ISR_RDC) break;
}
if (ix == 100) {
panic(RdmaErrMsg);
}
return;
}
/*
** Name: void dp_pio16_nic2user(dpeth_t *dep, int pageno, int pktsize)
** Function: Copies a packet from board to user area (Prog. I/O, 16bits).
*/
static void dp_pio16_nic2user(dpeth_t * dep, int nic_addr, int count)
{
phys_bytes phys_user;
vir_bytes ecount;
int bytes, i;
u8_t two_bytes[2];
phys_bytes phys_2bytes;
int odd_byte;
ecount = (count + 1) & ~1;
phys_2bytes = vir2phys(two_bytes);
odd_byte = 0;
dp_read_setup(dep, ecount, nic_addr);
i = 0;
while (count > 0) {
if (i >= IOVEC_NR) {
dp_next_iovec(iovp);
i = 0;
continue;
}
bytes = iovp->iod_iovec[i].iov_size;
if (bytes > count) bytes = count;
phys_user = numap(iovp->iod_proc_nr,
iovp->iod_iovec[i].iov_addr, bytes);
if (!phys_user) panic(UmapErrMsg);
if (odd_byte) {
phys_copy(phys_2bytes + 1, phys_user, (phys_bytes) 1);
count--;
bytes--;
phys_user++;
odd_byte = 0;
if (!bytes) continue;
}
ecount = bytes & ~1;
if (ecount != 0) {
phys_insw(dep->de_data_port, phys_user, ecount);
count -= ecount;
bytes -= ecount;
phys_user += ecount;
}
if (bytes) {
*(u16_t *) two_bytes = in_word(dep->de_data_port);
phys_copy(phys_2bytes, phys_user, (phys_bytes) 1);
count--;
bytes--;
phys_user++;
odd_byte = 1;
}
}
return;
}
#endif /* PIO16 == 1 */
#endif /* ENABLE_DP8390 */ #endif /* ENABLE_DP8390 */
/** end 8390.c **/ /** end 8390.c **/

View File

@ -5,6 +5,6 @@ SRCS= 3c501.c 3c509.c 3c503.c ne.c wd.c 8390.c devio.c netbuff.c dp.c
DPADD+= ${LIBNETDRIVER} ${LIBSYS} DPADD+= ${LIBNETDRIVER} ${LIBSYS}
LDADD+= -lnetdriver -lsys LDADD+= -lnetdriver -lsys
CPPFLAGS+= -Ddebug=0 CPPFLAGS+= -DVERBOSE=0
.include <minix.service.mk> .include <minix.service.mk>

View File

@ -3,11 +3,12 @@
** **
** Author: Giovanni Falzoni <gfalzoni@inwind.it> ** Author: Giovanni Falzoni <gfalzoni@inwind.it>
** **
** This file contains the routines for readind/writing ** This file contains the routines for reading/writing
** from/to the device registers. ** from/to the device registers.
*/ */
#include <minix/drivers.h> #include <minix/drivers.h>
#include <minix/netdriver.h>
#include <net/gen/ether.h> #include <net/gen/ether.h>
#include <net/gen/eth_io.h> #include <net/gen/eth_io.h>
#include "dp.h" #include "dp.h"
@ -18,11 +19,10 @@ static void warning(const char *type, int err)
{ {
printf("Warning: eth#0 sys_%s failed (%d)\n", type, err); printf("Warning: eth#0 sys_%s failed (%d)\n", type, err);
return;
} }
/* /*
** Name: unsigned int inb(unsigned short int port); ** Name: inb
** Function: Reads a byte from specified i/o port. ** Function: Reads a byte from specified i/o port.
*/ */
unsigned int inb(unsigned short port) unsigned int inb(unsigned short port)
@ -35,7 +35,7 @@ unsigned int inb(unsigned short port)
} }
/* /*
** Name: unsigned int inw(unsigned short int port); ** Name: inw
** Function: Reads a word from specified i/o port. ** Function: Reads a word from specified i/o port.
*/ */
unsigned int inw(unsigned short port) unsigned int inw(unsigned short port)
@ -48,22 +48,31 @@ unsigned int inw(unsigned short port)
} }
/* /*
** Name: unsigned int insb(unsigned short int port, int proc_nr, void *buffer, int count); ** Name: insb
** Function: Reads a sequence of bytes from specified i/o port to user space buffer. ** Function: Reads a sequence of bytes from an i/o port.
*/ */
void insb(unsigned short int port, endpoint_t proc_nr, void insb(unsigned short int port, void *buffer, int count)
void *buffer, int count)
{ {
int rc; int rc;
if ((rc = sys_insb(port, proc_nr, buffer, count)) != OK) if ((rc = sys_insb(port, SELF, buffer, count)) != OK)
warning("insb", rc); warning("insb", rc);
return;
} }
/*
** Name: insw
** Function: Reads a sequence of words from an i/o port.
*/
void insw(unsigned short int port, void *buffer, int count)
{
int rc;
if ((rc = sys_insw(port, SELF, buffer, count)) != OK)
warning("insw", rc);
}
/* /*
** Name: void outb(unsigned short int port, unsigned long value); ** Name: outb
** Function: Writes a byte to specified i/o port. ** Function: Writes a byte to specified i/o port.
*/ */
void outb(unsigned short port, unsigned long value) void outb(unsigned short port, unsigned long value)
@ -71,11 +80,10 @@ void outb(unsigned short port, unsigned long value)
int rc; int rc;
if ((rc = sys_outb(port, value)) != OK) warning("outb", rc); if ((rc = sys_outb(port, value)) != OK) warning("outb", rc);
return;
} }
/* /*
** Name: void outw(unsigned short int port, unsigned long value); ** Name: outw
** Function: Writes a word to specified i/o port. ** Function: Writes a word to specified i/o port.
*/ */
void outw(unsigned short port, unsigned long value) void outw(unsigned short port, unsigned long value)
@ -83,20 +91,18 @@ void outw(unsigned short port, unsigned long value)
int rc; int rc;
if ((rc = sys_outw(port, value)) != OK) warning("outw", rc); if ((rc = sys_outw(port, value)) != OK) warning("outw", rc);
return;
} }
/* /*
** Name: void outsb(unsigned short int port, int proc_nr, void *buffer, int count); ** Name: outsb
** Function: Writes a sequence of bytes from user space to specified i/o port. ** Function: Writes a sequence of bytes to an i/o port.
*/ */
void outsb(unsigned short port, endpoint_t proc_nr, void *buffer, int count) void outsb(unsigned short port, void *buffer, int count)
{ {
int rc; int rc;
if ((rc = sys_outsb(port, proc_nr, buffer, count)) != OK) if ((rc = sys_outsb(port, SELF, buffer, count)) != OK)
warning("outsb", rc); warning("outsb", rc);
return;
} }
#else #else

View File

@ -14,9 +14,10 @@
#include <minix/drivers.h> #include <minix/drivers.h>
#include <minix/netdriver.h> #include <minix/netdriver.h>
#include <minix/endpoint.h> #include <minix/endpoint.h>
#include <minix/ds.h>
#include <net/gen/ether.h> #include <net/gen/ether.h>
#include <net/gen/eth_io.h> #include <net/gen/eth_io.h>
#include <sys/mman.h>
#include <assert.h>
#include "dp.h" #include "dp.h"
@ -24,7 +25,6 @@
** Local data ** Local data
*/ */
static dpeth_t de_state; static dpeth_t de_state;
static int de_instance;
typedef struct dp_conf { /* Configuration description structure */ typedef struct dp_conf { /* Configuration description structure */
port_t dpc_port; port_t dpc_port;
@ -41,90 +41,43 @@ static dp_conf_t dp_conf[DP_CONF_NR] = {
{ 0x000, 0, 0x00000, }, { 0x000, 0, 0x00000, },
}; };
static char CopyErrMsg[] = "unable to read/write user data"; static int do_init(unsigned int instance, ether_addr_t *addr);
static char RecvErrMsg[] = "netdriver_receive failed"; static void do_stop(void);
static char SendErrMsg[] = "send failed"; static void do_mode(unsigned int mode);
static char SizeErrMsg[] = "illegal packet size"; static int do_send(struct netdriver_data *data, size_t size);
static char TypeErrMsg[] = "illegal message type"; static ssize_t do_recv(struct netdriver_data *data, size_t max);
static char DevName[] = "eth#?"; static void do_stat(eth_stat_t *stat);
static void do_intr(unsigned int mask);
static void do_other(const message *m_ptr, int ipc_status);
static const struct netdriver dp_table = {
.ndr_init = do_init,
.ndr_stop = do_stop,
.ndr_mode = do_mode,
.ndr_recv = do_recv,
.ndr_send = do_send,
.ndr_stat = do_stat,
.ndr_intr = do_intr,
.ndr_other = do_other
};
/* /*
** Name: void reply(dpeth_t *dep, int err, int m_type) ** Name: update_conf
** Function: Fills a reply message and sends it.
*/
static void reply(dpeth_t * dep)
{
message reply;
int r, flags;
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;
DEBUG(printf("\t reply %d (%lx)\n", reply.m_type,
reply.m_netdrv_net_dl_task.flags));
if ((r = ipc_send(dep->de_client, &reply)) != OK)
panic(SendErrMsg, r);
dep->de_read_s = 0;
dep->de_flags &= NOT(DEF_ACK_SEND | DEF_ACK_RECV);
return;
}
/*
** Name: void dp_confaddr(dpeth_t *dep)
** Function: Checks environment for a User defined ethernet address.
*/
static void dp_confaddr(dpeth_t * dep)
{
static char ea_fmt[] = "x:x:x:x:x:x";
char ea_key[16];
int ix;
long val;
strlcpy(ea_key, "DPETH0_EA", sizeof(ea_key));
ea_key[5] += de_instance;
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;
}
if (ix != 0 && ix != SA_ADDR_LEN)
/* It's all or nothing, force a panic */
env_parse(ea_key, "?", 0, &val, 0L, 0L);
return;
}
/*
** Name: void update_conf(dpeth_t *dep, dp_conf_t *dcp)
** Function: Gets the default settings from 'dp_conf' table and ** Function: Gets the default settings from 'dp_conf' table and
** modifies them from the environment. ** modifies them from the environment.
*/ */
static void update_conf(dpeth_t * dep, const dp_conf_t * dcp) static void update_conf(dpeth_t * dep, const dp_conf_t * dcp,
unsigned int instance)
{ {
static char dpc_fmt[] = "x:d:x"; static char dpc_fmt[] = "x:d:x";
char ec_key[16]; char ec_key[16];
long val; long val;
strlcpy(ec_key, "DPETH0", sizeof(ec_key)); strlcpy(ec_key, "DPETH0", sizeof(ec_key));
ec_key[5] += de_instance; ec_key[5] += instance;
dep->de_mode = DEM_SINK;
val = dcp->dpc_port; /* Get I/O port address */ val = dcp->dpc_port; /* Get I/O port address */
switch (env_parse(ec_key, dpc_fmt, 0, &val, 0x000L, 0x3FFL)) { env_parse(ec_key, dpc_fmt, 0, &val, 0x000L, 0x3FFL);
case EP_OFF: dep->de_mode = DEM_DISABLED; break;
case EP_ON:
case EP_SET: dep->de_mode = DEM_ENABLED; break;
}
dep->de_base_port = val; dep->de_base_port = val;
val = dcp->dpc_irq | DEI_DEFAULT; /* Get Interrupt line (IRQ) */ val = dcp->dpc_irq | DEI_DEFAULT; /* Get Interrupt line (IRQ) */
@ -134,15 +87,13 @@ static void update_conf(dpeth_t * dep, const dp_conf_t * dcp)
val = dcp->dpc_mem; /* Get shared memory address */ val = dcp->dpc_mem; /* Get shared memory address */
env_parse(ec_key, dpc_fmt, 2, &val, 0L, LONG_MAX); env_parse(ec_key, dpc_fmt, 2, &val, 0L, LONG_MAX);
dep->de_linmem = val; dep->de_linmem = val;
return;
} }
/* /*
** Name: void do_dump(message *mp) ** Name: do_dump
** Function: Displays statistics on screen (SFx key from console) ** Function: Displays statistics on screen (SFx key from console)
*/ */
static void do_dump(const message *mp) static void do_dump(void)
{ {
dpeth_t *dep; dpeth_t *dep;
@ -150,14 +101,12 @@ static void do_dump(const message *mp)
printf("\n\n"); printf("\n\n");
if (dep->de_mode == DEM_DISABLED) return;
printf("%s statistics:\t\t", dep->de_name); printf("%s statistics:\t\t", dep->de_name);
/* Network interface status */ /* Network interface status */
printf("Status: 0x%04x (%d)\n\n", dep->de_flags, dep->de_int_pending); printf("Status: 0x%04x\n\n", dep->de_flags);
(*dep->de_dumpstatsf) (dep); (*dep->de_dumpstatsf)(dep);
/* Transmitted/received bytes */ /* Transmitted/received bytes */
printf("Tx bytes:%10ld\t", dep->bytes_Tx); printf("Tx bytes:%10ld\t", dep->bytes_Tx);
@ -178,40 +127,31 @@ static void do_dump(const message *mp)
/* Transmit collisions/receive CRC errors */ /* Transmit collisions/receive CRC errors */
printf("Tx Coll: %8ld\t", dep->de_stat.ets_collision); printf("Tx Coll: %8ld\t", dep->de_stat.ets_collision);
printf("Rx CRC: %8ld\n", dep->de_stat.ets_CRCerr); printf("Rx CRC: %8ld\n", dep->de_stat.ets_CRCerr);
return;
} }
/* /*
** Name: void get_userdata_s(int user_proc, vir_bytes user_addr, int count, void *loc_addr) ** Name: do_first_init
** Function: Copies data from user area.
*/
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_safecopyfrom(user_proc, grant, 0, (vir_bytes)loc_addr, len)) != OK)
panic(CopyErrMsg, rc);
return;
}
/*
** Name: void do_first_init(dpeth_t *dep, dp_conf_t *dcp);
** Function: Init action to setup task ** Function: Init action to setup task
*/ */
static void do_first_init(dpeth_t *dep, const dp_conf_t *dcp) static void do_first_init(dpeth_t *dep, const dp_conf_t *dcp)
{ {
dep->de_linmem = 0xFFFF0000; dep->de_linmem = 0xFFFF0000; /* FIXME: this overrides update_conf, why? */
/* Make sure statisics are cleared */ /* Make sure statisics are cleared */
memset((void *) &(dep->de_stat), 0, sizeof(eth_stat_t)); memset(&dep->de_stat, 0, sizeof(dep->de_stat));
/* Device specific initialization */ /* Device specific initialization */
(*dep->de_initf) (dep); (*dep->de_initf)(dep);
/* Map memory if requested */
if (dep->de_linmem != 0) {
assert(dep->de_ramsize > 0);
dep->de_locmem =
vm_map_phys(SELF, (void *)dep->de_linmem, dep->de_ramsize);
if (dep->de_locmem == MAP_FAILED)
panic("unable to map memory");
}
/* Set the interrupt handler policy. Request interrupts not to be reenabled /* Set the interrupt handler policy. Request interrupts not to be reenabled
* automatically. Return the IRQ line number when an interrupt occurs. * automatically. Return the IRQ line number when an interrupt occurs.
@ -219,402 +159,160 @@ static void do_first_init(dpeth_t *dep, const dp_conf_t *dcp)
dep->de_hook = dep->de_irq; dep->de_hook = dep->de_irq;
if (sys_irqsetpolicy(dep->de_irq, 0 /*IRQ_REENABLE*/, &dep->de_hook) != OK) if (sys_irqsetpolicy(dep->de_irq, 0 /*IRQ_REENABLE*/, &dep->de_hook) != OK)
panic("unable to set IRQ policy"); panic("unable to set IRQ policy");
dep->de_int_pending = FALSE;
sys_irqenable(&dep->de_hook); sys_irqenable(&dep->de_hook);
return;
} }
/* /*
** Name: void do_init(message *mp) ** Name: do_init
** Function: Checks for hardware presence. ** Function: Checks for hardware presence.
** Provides initialization of hardware and data structures ** Initialize hardware and data structures.
** Return status and ethernet address.
*/ */
static void do_init(const message * mp) static int do_init(unsigned int instance, ether_addr_t *addr)
{ {
dpeth_t *dep; dpeth_t *dep;
dp_conf_t *dcp; dp_conf_t *dcp;
message reply_mess; int confnr, fkeys, sfkeys;
int r, confnr;
dep = &de_state; dep = &de_state;
strlcpy(dep->de_name, "dpeth#?", sizeof(dep->de_name));
dep->de_name[4] = '0' + instance;
/* Pick a default configuration for this instance. */ /* Pick a default configuration for this instance. */
confnr = MIN(de_instance, DP_CONF_NR-1); confnr = MIN(instance, DP_CONF_NR-1);
dcp = &dp_conf[confnr]; dcp = &dp_conf[confnr];
strlcpy(dep->de_name, DevName, sizeof(dep->de_name));
dep->de_name[4] = '0' + de_instance;
if (dep->de_mode == DEM_DISABLED) { update_conf(dep, dcp, instance);
update_conf(dep, dcp); /* First time thru */ if (!el1_probe(dep) && /* Probe for 3c501 */
if (dep->de_mode == DEM_ENABLED && !wdeth_probe(dep) && /* Probe for WD80x3 */
!el1_probe(dep) && /* Probe for 3c501 */ !ne_probe(dep) && /* Probe for NEx000 */
!wdeth_probe(dep) && /* Probe for WD80x3 */ !el2_probe(dep) && /* Probe for 3c503 */
!ne_probe(dep) && /* Probe for NEx000 */ !el3_probe(dep)) { /* Probe for 3c509 */
!el2_probe(dep) && /* Probe for 3c503 */ printf("%s: warning no ethernet card found at 0x%04X\n",
!el3_probe(dep)) { /* Probe for 3c509 */ dep->de_name, dep->de_base_port);
printf("%s: warning no ethernet card found at 0x%04X\n", return ENXIO;
dep->de_name, dep->de_base_port);
dep->de_mode = DEM_DISABLED;
}
} }
r = OK; do_first_init(dep, dcp);
/* 'de_mode' may change if probe routines fail, test again */ /* Request function key for debug dumps */
switch (dep->de_mode) { fkeys = sfkeys = 0; bit_set(sfkeys, 7);
if (fkey_map(&fkeys, &sfkeys) != OK)
printf("%s: couldn't bind Shift+F7 key (%d)\n", dep->de_name, errno);
case DEM_DISABLED: memcpy(addr, dep->de_address.ea_addr, sizeof(*addr));
/* Device is configured OFF or hardware probe failed */ return OK;
r = ENXIO;
break;
case DEM_ENABLED:
/* Device is present and probed */
if (dep->de_flags == DEF_EMPTY) {
/* These actions only the first time */
do_first_init(dep, dcp);
dep->de_flags |= DEF_ENABLED;
}
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;
(*dep->de_flagsf) (dep);
break;
case DEM_SINK:
/* Device not present (sink mode) */
memset(dep->de_address.ea_addr, 0, sizeof(ether_addr_t));
dp_confaddr(dep); /* Station address from env. */
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));
DEBUG(printf("\t reply %d\n", reply_mess.m_type));
if (ipc_send(mp->m_source, &reply_mess) != OK) /* Can't send */
panic(SendErrMsg, mp->m_source);
return;
} }
/* /*
** Name: void dp_next_iovec(iovec_dat_t *iovp) ** Name: de_mode
** Function: Retrieves data from next iovec element. ** Function: Sets packet receipt mode.
*/ */
void dp_next_iovec(iovec_dat_s_t * iovp) static void do_mode(unsigned int mode)
{ {
iovp->iod_iovec_s -= IOVEC_NR;
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;
}
/*
** Name: int calc_iovec_size(iovec_dat_t *iovp)
** Function: Compute the size of a request.
*/
static int calc_iovec_size(iovec_dat_s_t * iovp)
{
int size, ix;
size = ix = 0;
do {
size += iovp->iod_iovec[ix].iov_size;
if (++ix >= IOVEC_NR) {
dp_next_iovec(iovp);
ix = 0;
}
/* Till all vectors added */
} while (ix < iovp->iod_iovec_s);
return size;
}
/*
** Name: void do_vwrite_s(message *mp)
** Function:
*/
static void do_vwrite_s(const message * mp)
{
int size;
dpeth_t *dep; dpeth_t *dep;
dep = &de_state; dep = &de_state;
dep->de_client = mp->m_source; dep->de_flags &= NOT(DEF_PROMISC | DEF_MULTI | DEF_BROAD);
if (mode & NDEV_PROMISC)
if (dep->de_mode == DEM_ENABLED) { dep->de_flags |= DEF_PROMISC | DEF_MULTI | DEF_BROAD;
if (mode & NDEV_MULTI)
if (dep->de_flags & DEF_SENDING) /* Is sending in progress? */ dep->de_flags |= DEF_MULTI;
panic("send already in progress "); if (mode & NDEV_BROAD)
dep->de_flags |= DEF_BROAD;
dep->de_write_iovec.iod_proc_nr = mp->m_source; (*dep->de_flagsf)(dep);
get_userdata_s(mp->m_source, mp->m_net_netdrv_dl_writev_s.grant, 0,
mp->m_net_netdrv_dl_writev_s.count, dep->de_write_iovec.iod_iovec);
dep->de_write_iovec.iod_iovec_s = mp->m_net_netdrv_dl_writev_s.count;
dep->de_write_iovec.iod_grant = mp->m_net_netdrv_dl_writev_s.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(SizeErrMsg, size);
dep->de_flags |= DEF_SENDING;
(*dep->de_sendf) (dep, FALSE, size);
} else if (dep->de_mode == DEM_SINK)
dep->de_flags |= DEF_ACK_SEND;
reply(dep);
return;
} }
/* /*
** Name: void do_vread_s(message *mp, int vectored) ** Name: do_send
** Function: ** Function: Send a packet, if possible.
*/ */
static void do_vread_s(const message * mp) static int do_send(struct netdriver_data *data, size_t size)
{ {
int size;
dpeth_t *dep; dpeth_t *dep;
dep = &de_state; dep = &de_state;
dep->de_client = mp->m_source; return (*dep->de_sendf)(dep, data, size);
if (dep->de_mode == DEM_ENABLED) {
if (dep->de_flags & DEF_READING) /* Reading in progress */
panic("read already in progress");
dep->de_read_iovec.iod_proc_nr = mp->m_source;
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 = calc_iovec_size(&dep->de_read_iovec);
if (size < ETH_MAX_PACK_SIZE) panic(SizeErrMsg, size);
dep->de_flags |= DEF_READING;
(*dep->de_recvf) (dep, FALSE, size);
#if 0
if ((dep->de_flags & (DEF_READING | DEF_STOPPED)) == (DEF_READING | DEF_STOPPED))
/* The chip is stopped, and all arrived packets delivered */
(*dep->de_resetf) (dep);
dep->de_flags &= NOT(DEF_STOPPED);
#endif
}
reply(dep);
return;
} }
/* /*
** Name: void do_getstat_s(message *mp) ** Name: do_recv
** Function: Receive a packet, if possible.
*/
static ssize_t do_recv(struct netdriver_data *data, size_t max)
{
dpeth_t *dep;
dep = &de_state;
return (*dep->de_recvf)(dep, data, max);
}
/*
** Name: do_stat
** Function: Reports device statistics. ** Function: Reports device statistics.
*/ */
static void do_getstat_s(const message * mp) static void do_stat(eth_stat_t *stat)
{ {
int rc;
dpeth_t *dep;
message reply_mess;
dep = &de_state; memcpy(stat, &de_state.de_stat, sizeof(*stat));
if (dep->de_mode == DEM_ENABLED) (*dep->de_getstatsf) (dep);
if ((rc = sys_safecopyto(mp->m_source, mp->m_net_netdrv_dl_getstat_s.grant, 0,
(vir_bytes)&dep->de_stat,
(vir_bytes)sizeof(dep->de_stat))) != OK)
panic(CopyErrMsg, rc);
reply_mess.m_type = DL_STAT_REPLY;
rc= ipc_send(mp->m_source, &reply_mess);
if (rc != OK)
panic("do_getname: ipc_send failed: %d", rc);
return;
} }
/* /*
** Name: void dp_stop(dpeth_t *dep) ** Name: do_stop
** Function: Stops network interface. ** Function: Stops network interface.
*/ */
static void dp_stop(dpeth_t * dep) static void do_stop(void)
{ {
dpeth_t *dep;
if (dep->de_mode == DEM_ENABLED && (dep->de_flags & DEF_ENABLED)) { dep = &de_state;
/* Stop device */ /* Stop device */
(dep->de_stopf) (dep); (dep->de_stopf)(dep);
dep->de_flags = DEF_EMPTY;
dep->de_mode = DEM_DISABLED;
}
return;
} }
static void do_watchdog(const void *UNUSED(message)) /*
{ ** Name: do_intr
** Function; Handles interrupts.
DEBUG(printf("\t no reply")); */
return; static void do_intr(unsigned int __unused mask)
}
static void handle_hw_intr(void)
{ {
dpeth_t *dep; dpeth_t *dep;
dep = &de_state; dep = &de_state;
/* If device is enabled and interrupt pending */ /* If device is enabled and interrupt pending */
if (dep->de_mode == DEM_ENABLED) { (*dep->de_interruptf)(dep);
dep->de_int_pending = TRUE; sys_irqenable(&dep->de_hook);
(*dep->de_interruptf) (dep);
if (dep->de_flags & (DEF_ACK_SEND | DEF_ACK_RECV))
reply(dep);
dep->de_int_pending = FALSE;
sys_irqenable(&dep->de_hook);
}
} }
/* SEF functions and variables. */ /*
static void sef_local_startup(void); ** Name: do_other
static int sef_cb_init_fresh(int type, sef_init_info_t *info); ** Function: Processes miscellaneous messages.
static void sef_cb_signal_handler(int signo); */
static void do_other(const message *m_ptr, int ipc_status)
{
if (is_ipc_notify(ipc_status) && m_ptr->m_source == TTY_PROC_NR)
do_dump();
}
/* /*
** Name: int dpeth_task(void) ** Name: main
** Function: Main entry for dp task ** Function: Main entry for dp task
*/ */
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
message m;
int ipc_status;
int rc;
/* SEF local startup. */
env_setargs(argc, argv); env_setargs(argc, argv);
sef_local_startup();
while (TRUE) { netdriver_task(&dp_table);
if ((rc = netdriver_receive(ANY, &m, &ipc_status)) != OK){
panic(RecvErrMsg, rc);
}
DEBUG(printf("eth: got message %d, ", m.m_type)); return 0;
if (is_ipc_notify(ipc_status)) {
switch(_ENDPOINT_P(m.m_source)) {
case CLOCK:
/* to be defined */
do_watchdog(&m);
break;
case HARDWARE:
/* Interrupt from device */
handle_hw_intr();
break;
case TTY_PROC_NR:
/* Function key pressed */
do_dump(&m);
break;
default:
/* Invalid message type */
panic(TypeErrMsg, m.m_type);
break;
}
/* message processed, get another one */
continue;
}
switch (m.m_type) {
case DL_WRITEV_S: /* Write message to device */
do_vwrite_s(&m);
break;
case DL_READV_S: /* Read message from device */
do_vread_s(&m);
break;
case DL_CONF: /* Initialize device */
do_init(&m);
break;
case DL_GETSTAT_S: /* Get device statistics */
do_getstat_s(&m);
break;
default: /* Invalid message type */
panic(TypeErrMsg, m.m_type);
break;
}
}
return OK; /* Never reached, but keeps compiler happy */
} }
/*===========================================================================*
* sef_local_startup *
*===========================================================================*/
static void sef_local_startup()
{
/* 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);
/* 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);
/* Register signal callbacks. */
sef_setcb_signal_handler(sef_cb_signal_handler);
/* Let SEF perform startup. */
sef_startup();
}
/*===========================================================================*
* sef_cb_init_fresh *
*===========================================================================*/
static int sef_cb_init_fresh(int type, sef_init_info_t *UNUSED(info))
{
/* Initialize the dpeth driver. */
int fkeys, sfkeys;
long v;
/* Request function key for debug dumps */
fkeys = sfkeys = 0; bit_set(sfkeys, 8);
if ((fkey_map(&fkeys, &sfkeys)) != OK)
printf("%s: couldn't program Shift+F8 key (%d)\n", DevName, errno);
v = 0;
(void) env_parse("instance", "d", 0, &v, 0, 255);
de_instance = (int) v;
/* Announce we are up! */
netdriver_announce();
return(OK);
}
/*===========================================================================*
* sef_cb_signal_handler *
*===========================================================================*/
static void sef_cb_signal_handler(int signo)
{
/* Only check for termination signal, ignore anything else. */
if (signo != SIGTERM) return;
if (de_state.de_mode == DEM_ENABLED)
dp_stop(&de_state);
exit(0);
}
/** dp.c **/

View File

@ -51,7 +51,7 @@
#define NOT(x) (~(x)) #define NOT(x) (~(x))
#if debug == 1 #if VERBOSE == 1
# define DEBUG(statm) statm # define DEBUG(statm) statm
#else #else
# define DEBUG(statm) # define DEBUG(statm)
@ -70,26 +70,19 @@ typedef struct _buff_t { /* Receive/Transmit buffer header */
} buff_t; } buff_t;
struct dpeth; struct dpeth;
struct iovec_dat; typedef void (*dp_eth_t)(struct dpeth *);
typedef void (*dp_eth_t) (struct dpeth *); typedef int (*dp_send_t)(struct dpeth *, struct netdriver_data *, size_t);
typedef void (*dp_send_recv_t) (struct dpeth *, int, int); typedef ssize_t (*dp_recv_t)(struct dpeth *, struct netdriver_data *, size_t);
#if ENABLE_DP8390 == 1 #if ENABLE_DP8390 == 1
typedef void (*dp_user2nicf_t) (struct dpeth *, int, int); typedef void (*dp_user2nicf_t)(struct dpeth *, int, struct netdriver_data *,
typedef void (*dp_nic2userf_t) (struct dpeth *, int, int); size_t);
typedef void (*dp_getblock_t) (struct dpeth *, u16_t, int, void *); typedef void (*dp_nic2userf_t)(struct dpeth *, int, struct netdriver_data *,
size_t);
typedef void (*dp_getblock_t)(struct dpeth *, u16_t, int, void *);
#endif #endif
#define SENDQ_NR 2 /* Size of the send queue */ #define SENDQ_NR 2 /* Size of the send queue */
#define IOVEC_NR 16 /* Number of IOVEC entries at a time */
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 dpeth { typedef struct dpeth {
/* The de_base_port field is the starting point of the probe. The /* The de_base_port field is the starting point of the probe. The
@ -109,7 +102,6 @@ typedef struct dpeth {
port_t de_data_port; /* For boards using Prog. I/O for xmit/recv */ port_t de_data_port; /* For boards using Prog. I/O for xmit/recv */
int de_irq; int de_irq;
int de_int_pending;
int de_hook; /* interrupt hook at kernel */ int de_hook; /* interrupt hook at kernel */
char de_name[8]; char de_name[8];
@ -117,7 +109,7 @@ typedef struct dpeth {
#define DEI_DEFAULT 0x8000 #define DEI_DEFAULT 0x8000
phys_bytes de_linmem; /* For boards using shared memory */ phys_bytes de_linmem; /* For boards using shared memory */
vir_bytes de_memoffs; char *de_locmem; /* Locally mapped (virtual) address */
int de_ramsize; /* Size of on board memory */ int de_ramsize; /* Size of on board memory */
int de_offset_page; /* Offset of shared memory page */ int de_offset_page; /* Offset of shared memory page */
@ -129,8 +121,8 @@ typedef struct dpeth {
dp_eth_t de_getstatsf; dp_eth_t de_getstatsf;
dp_eth_t de_dumpstatsf; dp_eth_t de_dumpstatsf;
dp_eth_t de_interruptf; dp_eth_t de_interruptf;
dp_send_recv_t de_recvf; dp_recv_t de_recvf;
dp_send_recv_t de_sendf; dp_send_t de_sendf;
ether_addr_t de_address; /* Ethernet Address */ ether_addr_t de_address; /* Ethernet Address */
eth_stat_t de_stat; /* Ethernet Statistics */ eth_stat_t de_stat; /* Ethernet Statistics */
@ -141,35 +133,12 @@ typedef struct dpeth {
int de_flags; /* Send/Receive mode (Configuration) */ int de_flags; /* Send/Receive mode (Configuration) */
#define DEF_EMPTY 0x0000 #define DEF_EMPTY 0x00
#define DEF_READING 0x0001 #define DEF_XMIT_BUSY 0x01
#define DEF_RECV_BUSY 0x0002 #define DEF_PROMISC 0x02
#define DEF_ACK_RECV 0x0004 #define DEF_MULTI 0x04
#define DEF_SENDING 0x0010 #define DEF_BROAD 0x08
#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
/* 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;
int de_client;
/*
message de_sendmsg;
iovec_dat_t de_tmp_iovec;
*/
#if ENABLE_DP8390 == 1 #if ENABLE_DP8390 == 1
/* For use by NS DP8390 driver */ /* For use by NS DP8390 driver */
port_t de_dp8390_port; port_t de_dp8390_port;
@ -203,8 +172,6 @@ typedef struct dpeth {
/* For use by 3Com Etherlink (3c501 and 3c509) driver */ /* For use by 3Com Etherlink (3c501 and 3c509) driver */
buff_t *de_recvq_head; buff_t *de_recvq_head;
buff_t *de_recvq_tail; buff_t *de_recvq_tail;
buff_t *de_xmitq_head;
buff_t *de_xmitq_tail;
u16_t de_recv_mode; u16_t de_recv_mode;
clock_t de_xmit_start; clock_t de_xmit_start;
#endif #endif
@ -215,29 +182,23 @@ typedef struct dpeth {
* Function definitions * Function definitions
*/ */
/* dp.c */
void dp_next_iovec(iovec_dat_s_t * iovp);
/* devio.c */ /* devio.c */
#if defined USE_IOPL #if defined USE_IOPL
#include <machine/portio.h> #include <machine/portio.h>
#else #else
unsigned int inb(unsigned short int); unsigned int inb(unsigned short int);
unsigned int inw(unsigned short int); unsigned int inw(unsigned short int);
void insb(unsigned short int, endpoint_t, void *, int); void insb(unsigned short int, void *, int);
void insw(unsigned short int, int, void *, int); void insw(unsigned short int, void *, int);
void outb(unsigned short int, unsigned long); void outb(unsigned short int, unsigned long);
void outw(unsigned short int, unsigned long); void outw(unsigned short int, unsigned long);
void outsb(unsigned short int, endpoint_t, void *, int); void outsb(unsigned short int, void *, int);
void outsw(unsigned short int, int, void *, int);
#endif #endif
/* netbuff.c */ /* netbuff.c */
void *alloc_buff(dpeth_t *, int); void *alloc_buff(dpeth_t *, int);
void free_buff(dpeth_t *, void *); void free_buff(dpeth_t *, void *);
void init_buff(dpeth_t *, buff_t **); void init_buff(dpeth_t *, buff_t **);
void mem2user(dpeth_t *, buff_t *);
void user2mem(dpeth_t *, buff_t *);
/* 3c501.c */ /* 3c501.c */
#if ENABLE_3C501 == 1 #if ENABLE_3C501 == 1
@ -274,8 +235,4 @@ int wdeth_probe(dpeth_t * dep);
#define wdeth_probe(x) (0) #define wdeth_probe(x) (0)
#endif #endif
#define lock() (++dep->de_int_pending,sys_irqdisable(&dep->de_hook))
#define unlock() do{int i=(--dep->de_int_pending)?0:sys_irqenable(&dep->de_hook);(void) i;}while(0)
#define milli_delay(t) tickdelay(1)
/** dp.h **/ /** dp.h **/

View File

@ -13,6 +13,7 @@
*/ */
#include <minix/drivers.h> #include <minix/drivers.h>
#include <minix/netdriver.h>
#include <net/gen/ether.h> #include <net/gen/ether.h>
#include <net/gen/eth_io.h> #include <net/gen/eth_io.h>
#include "dp.h" #include "dp.h"
@ -23,7 +24,7 @@
#include "ne.h" #include "ne.h"
/* /*
** Name: void ne_reset(dpeth_t * dep); ** Name: ne_reset
** Function: Resets the board and checks if reset cycle completes ** Function: Resets the board and checks if reset cycle completes
*/ */
static int ne_reset(dpeth_t * dep) static int ne_reset(dpeth_t * dep)
@ -34,13 +35,13 @@ static int ne_reset(dpeth_t * dep)
outb_ne(dep, NE_RESET, inb_ne(dep, NE_RESET)); outb_ne(dep, NE_RESET, inb_ne(dep, NE_RESET));
do { do {
if (++count > 10) return FALSE; /* 20 mSecs. timeout */ if (++count > 10) return FALSE; /* 20 mSecs. timeout */
milli_delay(2); micro_delay(2000);
} while ((inb_ne(dep, DP_ISR) & ISR_RST) == 0); } while ((inb_ne(dep, DP_ISR) & ISR_RST) == 0);
return TRUE; return TRUE;
} }
/* /*
** Name: void ne_close(dpeth_t * dep); ** Name: ne_close
** Function: Stops the board by resetting it and masking interrupts. ** Function: Stops the board by resetting it and masking interrupts.
*/ */
static void ne_close(dpeth_t * dep) static void ne_close(dpeth_t * dep)
@ -49,11 +50,10 @@ static void ne_close(dpeth_t * dep)
(void)ne_reset(dep); (void)ne_reset(dep);
outb_ne(dep, DP_ISR, 0xFF); outb_ne(dep, DP_ISR, 0xFF);
sys_irqdisable(&dep->de_hook); sys_irqdisable(&dep->de_hook);
return;
} }
/* /*
** Name: void ne_init(dpeth_t * dep); ** Name: ne_init
** Function: Initialize the board making it ready to work. ** Function: Initialize the board making it ready to work.
*/ */
static void ne_init(dpeth_t * dep) static void ne_init(dpeth_t * dep)
@ -90,12 +90,12 @@ static void ne_init(dpeth_t * dep)
dep->de_ramsize / 1024, dep->de_ramsize / 1024,
dep->de_base_port, dep->de_irq); dep->de_base_port, dep->de_irq);
for (ix = 0; ix < SA_ADDR_LEN; ix += 1) for (ix = 0; ix < SA_ADDR_LEN; ix += 1)
printf("%02X%c", dep->de_address.ea_addr[ix], ix < SA_ADDR_LEN - 1 ? ':' : '\n'); printf("%02X%c", dep->de_address.ea_addr[ix],
return; ix < SA_ADDR_LEN - 1 ? ':' : '\n');
} }
/* /*
** Name: int ne_probe(dpeth_t * dep); ** Name: ne_probe
** Function: Probe for the presence of a NE*000 card by testing ** Function: Probe for the presence of a NE*000 card by testing
** whether the board is reachable through the dp8390. ** whether the board is reachable through the dp8390.
** Note that the NE1000 is an 8bit card and has a memory ** Note that the NE1000 is an 8bit card and has a memory

View File

@ -8,6 +8,7 @@
*/ */
#include <minix/drivers.h> #include <minix/drivers.h>
#include <minix/netdriver.h>
#include <net/gen/ether.h> #include <net/gen/ether.h>
#include <net/gen/eth_io.h> #include <net/gen/eth_io.h>
#include "dp.h" #include "dp.h"
@ -18,7 +19,7 @@ static m_hdr_t *allocptr = NULL;
static char tx_rx_buff[8192]; static char tx_rx_buff[8192];
/* /*
** Name: void *alloc_buff(dpeth_t *dep, int size) ** Name: alloc_buff
** Function: Allocates a buffer from the common pool. ** Function: Allocates a buffer from the common pool.
*/ */
void *alloc_buff(dpeth_t *dep, int size) void *alloc_buff(dpeth_t *dep, int size)
@ -26,7 +27,6 @@ void *alloc_buff(dpeth_t *dep, int size)
m_hdr_t *ptr, *wrk = allocptr; m_hdr_t *ptr, *wrk = allocptr;
int units = ((size + sizeof(m_hdr_t) - 1) / sizeof(m_hdr_t)) + 1; int units = ((size + sizeof(m_hdr_t) - 1) / sizeof(m_hdr_t)) + 1;
lock();
for (ptr = wrk->next;; wrk = ptr, ptr = ptr->next) { for (ptr = wrk->next;; wrk = ptr, ptr = ptr->next) {
if (ptr->size >= units) { if (ptr->size >= units) {
/* Memory is available, carve requested size from pool */ /* Memory is available, carve requested size from pool */
@ -39,24 +39,22 @@ void *alloc_buff(dpeth_t *dep, int size)
ptr->size = units; ptr->size = units;
} }
allocptr = wrk; allocptr = wrk;
unlock();
return ptr + 1; return ptr + 1;
} }
if (ptr == allocptr) break; if (ptr == allocptr) break;
} }
unlock();
return NULL; /* No memory available */ return NULL; /* No memory available */
} }
/* /*
** Name: void free_buff(dpeth_t *dep, void *blk) ** Name: free_buff
** Function: Returns a buffer to the common pool. ** Function: Returns a buffer to the common pool.
*/ */
void free_buff(dpeth_t *dep, void *blk) void free_buff(dpeth_t *dep, void *blk)
{ {
m_hdr_t *wrk, *ptr = (m_hdr_t *) blk - 1; m_hdr_t *wrk, *ptr = (m_hdr_t *) blk - 1;
lock(); /* Scan linked list for the correct place */ /* Scan linked list for the correct place */
for (wrk = allocptr; !(ptr > wrk && ptr < wrk->next); wrk = wrk->next) for (wrk = allocptr; !(ptr > wrk && ptr < wrk->next); wrk = wrk->next)
if (wrk >= wrk->next && (ptr > wrk || ptr < wrk->next)) break; if (wrk >= wrk->next && (ptr > wrk || ptr < wrk->next)) break;
@ -72,12 +70,10 @@ void free_buff(dpeth_t *dep, void *blk)
} else } else
wrk->next = ptr; wrk->next = ptr;
allocptr = wrk; /* Point allocptr to block just released */ allocptr = wrk; /* Point allocptr to block just released */
unlock();
return;
} }
/* /*
** Name: void init_buff(dpeth_t *dep, buff_t **tx_buff) ** Name: init_buff
** Function: Initalizes driver data structures. ** Function: Initalizes driver data structures.
*/ */
void init_buff(dpeth_t *dep, buff_t **tx_buff) void init_buff(dpeth_t *dep, buff_t **tx_buff)
@ -98,69 +94,6 @@ void init_buff(dpeth_t *dep, buff_t **tx_buff)
(*tx_buff)->size = 0; (*tx_buff)->size = 0;
} }
} }
return; /* Done */
}
/*
** Name: void mem2user(dpeth_t *dep, buff_t *rxbuff);
** Function: Copies a packet from local buffer to user area.
*/
void mem2user(dpeth_t *dep, buff_t *rxbuff)
{
int bytes, ix = 0;
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 */
bytes = iovp->iod_iovec[ix].iov_size; /* Size of buffer */
if (bytes > pktsize) bytes = pktsize;
/* Reads from Rx buffer to user area */
r= sys_safecopyto(iovp->iod_proc_nr, iovp->iod_iovec[ix].iov_grant, 0,
(vir_bytes)buffer, bytes);
if (r != OK)
panic("mem2user: sys_safecopyto failed: %d", r);
buffer += bytes;
if (++ix >= IOVEC_NR) { /* Next buffer of IO vector */
dp_next_iovec(iovp);
ix = 0;
}
/* Till packet done */
} while ((pktsize -= bytes) > 0);
return;
}
/*
** Name: void user2mem(dpeth_t *dep, buff_t *txbuff)
** Function: Copies a packet from user area to local buffer.
*/
void user2mem(dpeth_t *dep, buff_t *txbuff)
{
int bytes, ix = 0;
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;
r= sys_safecopyfrom(iovp->iod_proc_nr, iovp->iod_iovec[ix].iov_grant,
0, (vir_bytes)buffer, bytes);
if (r != OK)
panic("user2mem: sys_safecopyfrom failed: %d", r);
buffer += bytes;
if (++ix >= IOVEC_NR) { /* Next buffer of IO vector */
dp_next_iovec(iovp);
ix = 0;
}
/* Till packet done */
} while ((pktsize -= bytes) > 0);
return;
} }
#endif /* HAVE_BUFFERS */ #endif /* HAVE_BUFFERS */

View File

@ -13,6 +13,7 @@
*/ */
#include <minix/drivers.h> #include <minix/drivers.h>
#include <minix/netdriver.h>
#include <net/gen/ether.h> #include <net/gen/ether.h>
#include <net/gen/eth_io.h> #include <net/gen/eth_io.h>
#include "dp.h" #include "dp.h"
@ -43,8 +44,7 @@ static int we_ultra(dpeth_t * dep);
/*===========================================================================* /*===========================================================================*
* wdeth_probe * * wdeth_probe *
*===========================================================================*/ *===========================================================================*/
int wdeth_probe(dep) int wdeth_probe(dpeth_t *dep)
dpeth_t *dep;
{ {
int sum; int sum;
@ -67,8 +67,7 @@ dpeth_t *dep;
/*===========================================================================* /*===========================================================================*
* we_init * * we_init *
*===========================================================================*/ *===========================================================================*/
static void we_init(dep) static void we_init(dpeth_t *dep)
dpeth_t *dep;
{ {
int i, int_indx, int_nr; int i, int_indx, int_nr;
int tlb, rambit, revision; int tlb, rambit, revision;
@ -212,8 +211,7 @@ dpeth_t *dep;
/*===========================================================================* /*===========================================================================*
* we_stop * * we_stop *
*===========================================================================*/ *===========================================================================*/
static void we_stop(dep) static void we_stop(dpeth_t *dep)
dpeth_t *dep;
{ {
if (dep->de_16bit) outb_we(dep, EPL_LAAR, E_LAAR_A19 | E_LAAR_LAN16E); if (dep->de_16bit) outb_we(dep, EPL_LAAR, E_LAAR_A19 | E_LAAR_LAN16E);
@ -226,8 +224,7 @@ dpeth_t *dep;
/*===========================================================================* /*===========================================================================*
* we_aliasing * * we_aliasing *
*===========================================================================*/ *===========================================================================*/
static int we_aliasing(dep) static int we_aliasing(dpeth_t *dep)
dpeth_t *dep;
{ {
/* Determine whether wd8003 hardware performs register aliasing. This implies /* Determine whether wd8003 hardware performs register aliasing. This implies
* an old WD8003E board. */ * an old WD8003E board. */
@ -243,8 +240,7 @@ dpeth_t *dep;
/*===========================================================================* /*===========================================================================*
* we_interface_chip * * we_interface_chip *
*===========================================================================*/ *===========================================================================*/
static int we_interface_chip(dep) static int we_interface_chip(dpeth_t *dep)
dpeth_t *dep;
{ {
/* Determine if the board has an interface chip. */ /* Determine if the board has an interface chip. */
@ -258,8 +254,7 @@ dpeth_t *dep;
/*===========================================================================* /*===========================================================================*
* we_16bitboard * * we_16bitboard *
*===========================================================================*/ *===========================================================================*/
static int we_16bitboard(dep) static int we_16bitboard(dpeth_t *dep)
dpeth_t *dep;
{ {
/* Determine whether the board is capable of doing 16 bit memory moves. /* Determine whether the board is capable of doing 16 bit memory moves.
* If the 16 bit enable bit is unchangable by software we'll assume an * If the 16 bit enable bit is unchangable by software we'll assume an
@ -286,8 +281,7 @@ dpeth_t *dep;
/*===========================================================================* /*===========================================================================*
* we_16bitslot * * we_16bitslot *
*===========================================================================*/ *===========================================================================*/
static int we_16bitslot(dep) static int we_16bitslot(dpeth_t *dep)
dpeth_t *dep;
{ {
/* Determine if the 16 bit board in plugged into a 16 bit slot. */ /* Determine if the 16 bit board in plugged into a 16 bit slot. */
@ -297,8 +291,7 @@ dpeth_t *dep;
/*===========================================================================* /*===========================================================================*
* we_ultra * * we_ultra *
*===========================================================================*/ *===========================================================================*/
static int we_ultra(dep) static int we_ultra(dpeth_t *dep)
dpeth_t *dep;
{ {
/* Determine if we has an '790 chip. */ /* Determine if we has an '790 chip. */
u8_t tlb; u8_t tlb;

View File

@ -6,7 +6,7 @@ FILES=$(PROG).conf
FILESNAME=$(PROG) FILESNAME=$(PROG)
FILESDIR= /etc/system.conf.d FILESDIR= /etc/system.conf.d
DPADD+= ${LIBNETDRIVER} ${LIBSYS} ${LIBTIMERS} DPADD+= ${LIBNETDRIVER} ${LIBSYS}
LDADD+= -lnetdriver -lsys -ltimers LDADD+= -lnetdriver -lsys
.include <minix.service.mk> .include <minix.service.mk>

File diff suppressed because it is too large Load Diff

View File

@ -18,13 +18,6 @@
#ifndef __E1000_H #ifndef __E1000_H
#define __E1000_H #define __E1000_H
#include <minix/drivers.h>
#include <stdlib.h>
#include <net/hton.h>
#include <net/gen/ether.h>
#include <net/gen/eth_io.h>
#include <machine/pci.h>
#include <minix/ds.h>
#include "e1000_hw.h" #include "e1000_hw.h"
/** /**
@ -38,14 +31,11 @@
/** Number of transmit descriptors per card. */ /** Number of transmit descriptors per card. */
#define E1000_TXDESC_NR 256 #define E1000_TXDESC_NR 256
/** Number of I/O vectors to use. */
#define E1000_IOVEC_NR 16
/** Size of each I/O buffer per descriptor. */ /** Size of each I/O buffer per descriptor. */
#define E1000_IOBUF_SIZE 2048 #define E1000_IOBUF_SIZE 2048
/** Debug verbosity. */ /** Debug verbosity. */
#define E1000_VERBOSE 1 #define E1000_VERBOSE 0
/** MAC address override variable. */ /** MAC address override variable. */
#define E1000_ENVVAR "E1000ETH" #define E1000_ENVVAR "E1000ETH"
@ -59,24 +49,6 @@
* @{ * @{
*/ */
/** Card has been detected on the PCI bus. */
#define E1000_DETECTED (1 << 0)
/** Card is enabled. */
#define E1000_ENABLED (1 << 1)
/** Client has requested to receive packets. */
#define E1000_READING (1 << 2)
/** Client has requested to write packets. */
#define E1000_WRITING (1 << 3)
/** Received some packets on the card. */
#define E1000_RECEIVED (1 << 4)
/** Transmitted some packets on the card. */
#define E1000_TRANSMIT (1 << 5)
/** /**
* @} * @}
*/ */
@ -141,36 +113,25 @@
typedef struct e1000 typedef struct e1000
{ {
char name[8]; /**< String containing the device name. */ char name[8]; /**< String containing the device name. */
int status; /**< Describes the card's current state. */
int irq; /**< Interrupt Request Vector. */ int irq; /**< Interrupt Request Vector. */
int irq_hook; /**< Interrupt Request Vector Hook. */ int irq_hook; /**< Interrupt Request Vector Hook. */
int revision; /**< Hardware Revision Number. */
u8_t *regs; /**< Memory mapped hardware registers. */ u8_t *regs; /**< Memory mapped hardware registers. */
u8_t *flash; /**< Optional flash memory. */ u8_t *flash; /**< Optional flash memory. */
u32_t flash_base_addr; /**< Flash base address. */ u32_t flash_base_addr; /**< Flash base address. */
ether_addr_t address; /**< Ethernet MAC address. */ u16_t (*eeprom_read)(struct e1000 *, int reg);
u16_t (*eeprom_read)(void *, int reg); /**< Function to read /**< Function to read the EEPROM. */
the EEPROM. */
int eeprom_done_bit; /**< Offset of the EERD.DONE bit. */ int eeprom_done_bit; /**< Offset of the EERD.DONE bit. */
int eeprom_addr_off; /**< Offset of the EERD.ADDR field. */ int eeprom_addr_off; /**< Offset of the EERD.ADDR field. */
e1000_rx_desc_t *rx_desc; /**< Receive Descriptor table. */ e1000_rx_desc_t *rx_desc; /**< Receive Descriptor table. */
phys_bytes rx_desc_p; /**< Physical Receive Descriptor Address. */
int rx_desc_count; /**< Number of Receive Descriptors. */ int rx_desc_count; /**< Number of Receive Descriptors. */
char *rx_buffer; /**< Receive buffer returned by malloc(). */ char *rx_buffer; /**< Receive buffer returned by malloc(). */
int rx_buffer_size; /**< Size of the receive buffer. */ int rx_buffer_size; /**< Size of the receive buffer. */
e1000_tx_desc_t *tx_desc; /**< Transmit Descriptor table. */ e1000_tx_desc_t *tx_desc; /**< Transmit Descriptor table. */
phys_bytes tx_desc_p; /**< Physical Transmit Descriptor Address. */
int tx_desc_count; /**< Number of Transmit Descriptors. */ int tx_desc_count; /**< Number of Transmit Descriptors. */
char *tx_buffer; /**< Transmit buffer returned by malloc(). */ char *tx_buffer; /**< Transmit buffer returned by malloc(). */
int tx_buffer_size; /**< Size of the transmit buffer. */ int tx_buffer_size; /**< Size of the transmit buffer. */
} e1000_t;
int client; /**< Process ID being served by e1000. */
message rx_message; /**< Read message received from client. */
message tx_message; /**< Write message received from client. */
size_t rx_size; /**< Size of one packet received. */
}
e1000_t;
#endif /* __E1000_H */ #endif /* __E1000_H */

View File

@ -6,7 +6,7 @@ FILES=$(PROG).conf
FILESNAME=$(PROG) FILESNAME=$(PROG)
FILESDIR= /etc/system.conf.d FILESDIR= /etc/system.conf.d
DPADD+= ${LIBNETDRIVER} ${LIBSYS} ${LIBTIMERS} DPADD+= ${LIBNETDRIVER} ${LIBSYS}
LDADD+= -lnetdriver -lsys -ltimers LDADD+= -lnetdriver -lsys
.include <minix.service.mk> .include <minix.service.mk>

File diff suppressed because it is too large Load Diff

View File

@ -6,7 +6,7 @@ FILES=$(PROG).conf
FILESNAME=$(PROG) FILESNAME=$(PROG)
FILESDIR= /etc/system.conf.d FILESDIR= /etc/system.conf.d
DPADD+= ${LIBNETDRIVER} ${LIBSYS} ${LIBTIMERS} DPADD+= ${LIBNETDRIVER} ${LIBSYS}
LDADD+= -lnetdriver -lsys -ltimers LDADD+= -lnetdriver -lsys
.include <minix.service.mk> .include <minix.service.mk>

View File

@ -1,31 +1,28 @@
#include <minix/drivers.h> #include <minix/drivers.h>
#include <minix/netdriver.h> #include <minix/netdriver.h>
#include <net/gen/ether.h>
#include <net/gen/eth_io.h>
#include <minix/sysutil.h>
#include <minix/board.h> #include <minix/board.h>
#include <sys/mman.h>
#include "assert.h" #include "assert.h"
#include "lan8710a.h" #include "lan8710a.h"
#include "lan8710a_reg.h" #include "lan8710a_reg.h"
/* Local functions */ /* Local functions */
static void lan8710a_readv_s(message *m, int from_int); static int lan8710a_init(unsigned int instance, ether_addr_t *addr);
static void lan8710a_writev_s(message *m, int from_int);
static void lan8710a_conf(message *m);
static void lan8710a_getstat(message *m);
static void lan8710a_init(void);
static void lan8710a_enable_interrupt(int interrupt);
static void lan8710a_interrupt(message *m);
static void lan8710a_map_regs(void);
static void lan8710a_stop(void); static void lan8710a_stop(void);
static ssize_t lan8710a_recv(struct netdriver_data *data, size_t max);
static int lan8710a_send(struct netdriver_data *data, size_t size);
static void lan8710a_stat(eth_stat_t *stat);
static void lan8710a_intr(unsigned int mask);
static void lan8710a_enable_interrupt(int interrupt);
static void lan8710a_map_regs(void);
static void lan8710a_dma_config_tx(u8_t desc_idx); static void lan8710a_dma_config_tx(u8_t desc_idx);
static void lan8710a_dma_reset_init(void); static void lan8710a_dma_reset_init(void);
static void lan8710a_init_addr(void); static void lan8710a_init_addr(ether_addr_t *addr);
static void lan8710a_init_desc(void); static void lan8710a_init_desc(void);
static void lan8710a_init_mdio(void); static void lan8710a_init_mdio(void);
static int lan8710a_init_hw(void); static int lan8710a_init_hw(ether_addr_t *addr);
static void lan8710a_reset_hw(); static void lan8710a_reset_hw(void);
static void lan8710a_phy_write(u32_t reg, u32_t value); static void lan8710a_phy_write(u32_t reg, u32_t value);
static u32_t lan8710a_phy_read(u32_t reg); static u32_t lan8710a_phy_read(u32_t reg);
@ -35,16 +32,17 @@ static void lan8710a_reg_write(volatile u32_t *reg, u32_t value);
static void lan8710a_reg_set(volatile u32_t *reg, u32_t value); static void lan8710a_reg_set(volatile u32_t *reg, u32_t value);
static void lan8710a_reg_unset(volatile u32_t *reg, u32_t value); static void lan8710a_reg_unset(volatile u32_t *reg, u32_t value);
static void mess_reply(message *req, message *reply);
static void reply(lan8710a_t *e);
/* Local variables */ /* Local variables */
static lan8710a_t lan8710a_state; static lan8710a_t lan8710a_state;
/* SEF functions and variables. */ static const struct netdriver lan8710a_table = {
static void sef_local_startup(void); .ndr_init = lan8710a_init,
static int sef_cb_init_fresh(int type, sef_init_info_t *info); .ndr_stop = lan8710a_stop,
static void sef_cb_signal_handler(int signal); .ndr_recv = lan8710a_recv,
.ndr_send = lan8710a_send,
.ndr_stat = lan8710a_stat,
.ndr_intr = lan8710a_intr
};
/*============================================================================* /*============================================================================*
* main * * main *
@ -52,122 +50,45 @@ static void sef_cb_signal_handler(int signal);
int int
main(int argc, char *argv[]) main(int argc, char *argv[])
{ {
struct machine machine;
/* Local variables */ env_setargs(argc, argv);
message m;
int r;
int ipc_status;
struct machine machine ;
sys_getmachine(&machine); sys_getmachine(&machine);
if ( BOARD_IS_BB(machine.board_id)) { if (BOARD_IS_BB(machine.board_id))
netdriver_task(&lan8710a_table);
/* SEF local startup */
env_setargs(argc, argv);
sef_local_startup();
/* Main driver loop */
for (;;) {
r = netdriver_receive(ANY, &m, &ipc_status);
if (r != OK) {
panic("netdriver_receive failed: %d", r);
}
if (is_ipc_notify(ipc_status)) {
switch (_ENDPOINT_P(m.m_source)) {
case HARDWARE:
lan8710a_interrupt(&m);
break;
}
} else {
switch (m.m_type) {
case DL_WRITEV_S:
lan8710a_writev_s(&m, FALSE);
break;
case DL_READV_S:
lan8710a_readv_s(&m, FALSE);
break;
case DL_CONF:
lan8710a_conf(&m);
break;
case DL_GETSTAT_S:
lan8710a_getstat(&m);
break;
default:
panic("Illegal message: %d", m.m_type);
}
}
}
}
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
/*============================================================================* /*============================================================================*
* sef_local_startup * * lan8710a_init *
*============================================================================*/
static void
sef_local_startup()
{
/* 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);
/* 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);
/* Register signal callbacks. */
sef_setcb_signal_handler(sef_cb_signal_handler);
/* Let SEF perform startup. */
sef_startup();
}
/*============================================================================*
* sef_cb_init_fresh *
*============================================================================*/ *============================================================================*/
static int static int
sef_cb_init_fresh(int UNUSED( type), sef_init_info_t *UNUSED( info)) lan8710a_init(unsigned int instance, ether_addr_t * addr)
{ {
/* Initialize the ethernet driver. */ /* Initialize the ethernet driver. */
long v = 0;
/* Clear state. */ /* Clear state. */
memset(&lan8710a_state, 0, sizeof(lan8710a_state)); memset(&lan8710a_state, 0, sizeof(lan8710a_state));
strlcpy(lan8710a_state.name, "lan8710a#0", LAN8710A_NAME_LEN);
lan8710a_state.name[9] += instance;
lan8710a_state.instance = instance;
/* Initialize driver. */ /* Initialize driver. */
lan8710a_init(); lan8710a_map_regs();
/* Get instance of ethernet device */ lan8710a_init_hw(addr);
env_parse("instance", "d", 0, &v, 0, 255);
lan8710a_state.instance = (int) v;
/* Announce we are up! */
netdriver_announce();
return OK; return OK;
} }
/*============================================================================*
* sef_cb_signal_handler *
*============================================================================*/
static void
sef_cb_signal_handler(int signal)
{
/* Only check for termination signal, ignore anything else. */
if (signal != SIGTERM)
return;
lan8710a_stop();
}
/*============================================================================* /*============================================================================*
* lan8710a_enable_interrupt * * lan8710a_enable_interrupt *
*============================================================================*/ *============================================================================*/
static void static void
lan8710a_enable_interrupt(interrupt) lan8710a_enable_interrupt(int interrupt)
u8_t interrupt;
{ {
int r; int r;
@ -182,14 +103,13 @@ u8_t interrupt;
} }
} }
} }
/*============================================================================* /*============================================================================*
* lan8710a_interrupt * * lan8710a_intr *
*============================================================================*/ *============================================================================*/
static void static void
lan8710a_interrupt(m) lan8710a_intr(unsigned int mask)
message *m;
{ {
lan8710a_t *e = &lan8710a_state;
u32_t dma_status; u32_t dma_status;
/* Check the card for interrupt reason(s). */ /* Check the card for interrupt reason(s). */
@ -201,7 +121,7 @@ message *m;
if (rx_stat) { if (rx_stat) {
cp = lan8710a_reg_read(CPDMA_STRAM_RX_CP(0)); cp = lan8710a_reg_read(CPDMA_STRAM_RX_CP(0));
lan8710a_readv_s(&(e->rx_message), TRUE); netdriver_recv();
lan8710a_reg_write(CPDMA_STRAM_RX_CP(0), cp); lan8710a_reg_write(CPDMA_STRAM_RX_CP(0), cp);
lan8710a_reg_write(CPDMA_EOI_VECTOR, RX_INT); lan8710a_reg_write(CPDMA_EOI_VECTOR, RX_INT);
@ -212,7 +132,7 @@ message *m;
/* Disabling channels, where Tx interrupt occurred */ /* Disabling channels, where Tx interrupt occurred */
lan8710a_reg_set(CPDMA_TX_INTMASK_CLEAR, tx_stat); lan8710a_reg_set(CPDMA_TX_INTMASK_CLEAR, tx_stat);
lan8710a_writev_s(&(e->tx_message), TRUE); netdriver_send();
lan8710a_reg_write(CPDMA_STRAM_TX_CP(0), cp); lan8710a_reg_write(CPDMA_STRAM_TX_CP(0), cp);
lan8710a_reg_write(CPDMA_EOI_VECTOR, TX_INT); lan8710a_reg_write(CPDMA_EOI_VECTOR, TX_INT);
@ -226,61 +146,19 @@ message *m;
} }
/* Re-enable Rx interrupt. */ /* Re-enable Rx interrupt. */
if(m->m_notify.interrupts & (1 << RX_INT)) if (mask & (1 << RX_INT))
lan8710a_enable_interrupt(RX_INT); lan8710a_enable_interrupt(RX_INT);
/* Re-enable Tx interrupt. */ /* Re-enable Tx interrupt. */
if(m->m_notify.interrupts & (1 << TX_INT)) if (mask & (1 << TX_INT))
lan8710a_enable_interrupt(TX_INT); lan8710a_enable_interrupt(TX_INT);
} }
/*============================================================================*
* lan8710a_conf *
*============================================================================*/
static void
lan8710a_conf(m)
message *m;
{
message reply;
if (!(lan8710a_state.status & LAN8710A_ENABLED) &&
!(lan8710a_init_hw())) {
reply.m_type = DL_CONF_REPLY;
reply.m_netdrv_net_dl_conf.stat = ENXIO;
mess_reply(m, &reply);
return;
}
/* Reply back to INET. */
reply.m_type = DL_CONF_REPLY;
reply.m_netdrv_net_dl_conf.stat = OK;
memcpy(reply.m_netdrv_net_dl_conf.hw_addr,
lan8710a_state.address.ea_addr,
sizeof(reply.m_netdrv_net_dl_conf.hw_addr));
mess_reply(m, &reply);
}
/*============================================================================*
* lan8710a_init *
*============================================================================*/
static void
lan8710a_init(void)
{
lan8710a_map_regs();
strlcpy(lan8710a_state.name, "lan8710a#0", LAN8710A_NAME_LEN);
lan8710a_state.name[9] += lan8710a_state.instance;
lan8710a_state.status |= LAN8710A_DETECTED;
if (!(lan8710a_state.status & LAN8710A_ENABLED) &&
!(lan8710a_init_hw())) {
return;
}
}
/*============================================================================* /*============================================================================*
* lan8710a_init_addr * * lan8710a_init_addr *
*============================================================================*/ *============================================================================*/
static void static void
lan8710a_init_addr(void) lan8710a_init_addr(ether_addr_t * addr)
{ {
static char eakey[]= LAN8710A_ENVVAR "#_EA"; static char eakey[]= LAN8710A_ENVVAR "#_EA";
static char eafmt[]= "x:x:x:x:x:x"; static char eafmt[]= "x:x:x:x:x:x";
@ -296,22 +174,20 @@ lan8710a_init_addr(void)
if (env_parse(eakey, eafmt, i, &v, 0x00L, 0xFFL) != EP_SET) if (env_parse(eakey, eafmt, i, &v, 0x00L, 0xFFL) != EP_SET)
break; break;
else else
lan8710a_state.address.ea_addr[i] = v; addr->ea_addr[i] = v;
}
if (i != 6) {
lan8710a_state.address.ea_addr[0] =
(lan8710a_reg_read(CTRL_MAC_ID0_HI) & 0xFF);
lan8710a_state.address.ea_addr[1] =
((lan8710a_reg_read(CTRL_MAC_ID0_HI) & 0xFF00) >> 8);
lan8710a_state.address.ea_addr[2] =
((lan8710a_reg_read(CTRL_MAC_ID0_HI) & 0xFF0000) >> 16);
lan8710a_state.address.ea_addr[3] =
((lan8710a_reg_read(CTRL_MAC_ID0_HI) & 0xFF000000) >> 24);
lan8710a_state.address.ea_addr[4] =
(lan8710a_reg_read(CTRL_MAC_ID0_LO) & 0xFF);
lan8710a_state.address.ea_addr[5] =
((lan8710a_reg_read(CTRL_MAC_ID0_LO) & 0xFF00) >> 8);
} }
if (i == 6)
return;
/*
* No; get the address from the chip itself.
*/
addr->ea_addr[0] = lan8710a_reg_read(CTRL_MAC_ID0_HI) & 0xFF;
addr->ea_addr[1] = (lan8710a_reg_read(CTRL_MAC_ID0_HI) >> 8) & 0xFF;
addr->ea_addr[2] = (lan8710a_reg_read(CTRL_MAC_ID0_HI) >> 16) & 0xFF;
addr->ea_addr[3] = (lan8710a_reg_read(CTRL_MAC_ID0_HI) >> 24) & 0xFF;
addr->ea_addr[4] = lan8710a_reg_read(CTRL_MAC_ID0_LO) & 0xFF;
addr->ea_addr[5] = (lan8710a_reg_read(CTRL_MAC_ID0_LO) >> 8) & 0xFF;
} }
/*============================================================================* /*============================================================================*
@ -411,40 +287,28 @@ lan8710a_map_regs(void)
} }
/*============================================================================* /*============================================================================*
* lan8710a_getstat * * lan8710a_stat *
*============================================================================*/ *============================================================================*/
static void static void
lan8710a_getstat(mp) lan8710a_stat(eth_stat_t * stat)
message *mp;
{ {
int r; stat->ets_recvErr = lan8710a_reg_read(CPSW_STAT_RX_CRC_ERR)
eth_stat_t stats;
stats.ets_recvErr = lan8710a_reg_read(CPSW_STAT_RX_CRC_ERR)
+ lan8710a_reg_read(CPSW_STAT_RX_AGNCD_ERR) + lan8710a_reg_read(CPSW_STAT_RX_AGNCD_ERR)
+ lan8710a_reg_read(CPSW_STAT_RX_OVERSIZE); + lan8710a_reg_read(CPSW_STAT_RX_OVERSIZE);
stats.ets_sendErr = 0; stat->ets_sendErr = 0;
stats.ets_OVW = 0; stat->ets_OVW = 0;
stats.ets_CRCerr = lan8710a_reg_read(CPSW_STAT_RX_CRC_ERR); stat->ets_CRCerr = lan8710a_reg_read(CPSW_STAT_RX_CRC_ERR);
stats.ets_frameAll = lan8710a_reg_read(CPSW_STAT_RX_AGNCD_ERR); stat->ets_frameAll = lan8710a_reg_read(CPSW_STAT_RX_AGNCD_ERR);
stats.ets_missedP = 0; stat->ets_missedP = 0;
stats.ets_packetR = lan8710a_reg_read(CPSW_STAT_RX_GOOD); stat->ets_packetR = lan8710a_reg_read(CPSW_STAT_RX_GOOD);
stats.ets_packetT = lan8710a_reg_read(CPSW_STAT_TX_GOOD); stat->ets_packetT = lan8710a_reg_read(CPSW_STAT_TX_GOOD);
stats.ets_collision = lan8710a_reg_read(CPSW_STAT_COLLISIONS); stat->ets_collision = lan8710a_reg_read(CPSW_STAT_COLLISIONS);
stats.ets_transAb = 0; stat->ets_transAb = 0;
stats.ets_carrSense = lan8710a_reg_read(CPSW_STAT_CARR_SENS_ERR); stat->ets_carrSense = lan8710a_reg_read(CPSW_STAT_CARR_SENS_ERR);
stats.ets_fifoUnder = lan8710a_reg_read(CPSW_STAT_TX_UNDERRUN); stat->ets_fifoUnder = lan8710a_reg_read(CPSW_STAT_TX_UNDERRUN);
stats.ets_fifoOver = lan8710a_reg_read(CPSW_STAT_RX_OVERRUN); stat->ets_fifoOver = lan8710a_reg_read(CPSW_STAT_RX_OVERRUN);
stats.ets_CDheartbeat = 0; stat->ets_CDheartbeat = 0;
stats.ets_OWC = 0; stat->ets_OWC = 0;
sys_safecopyto(mp->m_source, mp->m_net_netdrv_dl_getstat_s.grant, 0,
(vir_bytes)&stats, sizeof(stats));
mp->m_type = DL_STAT_REPLY;
if ((r=ipc_send(mp->m_source, mp)) != OK) {
panic("lan8710a_getstat: ipc_send() failed: %d", r);
}
} }
/*============================================================================* /*============================================================================*
@ -455,17 +319,13 @@ lan8710a_stop(void)
{ {
/* Reset hardware. */ /* Reset hardware. */
lan8710a_reset_hw(); lan8710a_reset_hw();
/* Exit driver. */
exit(EXIT_SUCCESS);
} }
/*============================================================================* /*============================================================================*
* lan8710a_dma_config_tx * * lan8710a_dma_config_tx *
*============================================================================*/ *============================================================================*/
static void static void
lan8710a_dma_config_tx(desc_idx) lan8710a_dma_config_tx(u8_t desc_idx)
u8_t desc_idx;
{ {
phys_bytes phys_addr; phys_bytes phys_addr;
int i; int i;
@ -585,12 +445,10 @@ lan8710a_init_desc(void)
* lan8710a_init_hw * * lan8710a_init_hw *
*============================================================================*/ *============================================================================*/
static int static int
lan8710a_init_hw(void) lan8710a_init_hw(ether_addr_t * addr)
{ {
int r, i; int r, i;
lan8710a_state.status |= LAN8710A_ENABLED;
/* /*
* Set the interrupt handler and policy. Do not automatically * Set the interrupt handler and policy. Do not automatically
* re-enable interrupts. Return the IRQ line number on interrupts. * re-enable interrupts. Return the IRQ line number on interrupts.
@ -757,7 +615,7 @@ lan8710a_init_hw(void)
lan8710a_init_mdio(); lan8710a_init_mdio();
/* Getting MAC Address */ /* Getting MAC Address */
lan8710a_init_addr(); lan8710a_init_addr(addr);
/* Initialize descriptors */ /* Initialize descriptors */
lan8710a_init_desc(); lan8710a_init_desc();
@ -825,244 +683,145 @@ lan8710a_init_mdio(void)
} }
/*============================================================================* /*============================================================================*
* lan8710a_writev_s * * lan8710a_send *
*============================================================================*/ *============================================================================*/
static void static int
lan8710a_writev_s(mp, from_int) lan8710a_send(struct netdriver_data * data, size_t size)
message *mp;
int from_int;
{ {
iovec_s_t iovec[LAN8710A_IOVEC_NR];
lan8710a_t *e = &lan8710a_state; lan8710a_t *e = &lan8710a_state;
lan8710a_desc_t *p_tx_desc; lan8710a_desc_t *p_tx_desc;
u8_t *p_buf; u8_t *buf;
int r, size, buf_data_len, i;
/* Are we called from the interrupt handler? */ /* setup descriptors */
if (!from_int) { p_tx_desc = &(e->tx_desc[e->tx_desc_idx]);
/* We cannot write twice simultaneously. */
assert(!(e->status & LAN8710A_WRITING));
/* Copy write message. */ /*
e->tx_message = *mp; * Check if descriptor is available for host and suspend if not.
e->client = mp->m_source; */
e->status |= LAN8710A_WRITING; if (LAN8710A_DESC_FLAG_OWN & p_tx_desc->pkt_len_flags)
return SUSPEND;
/* verify vector count */ /* Drop packets that exceed the size of our transmission buffer. */
assert(mp->m_net_netdrv_dl_writev_s.count > 0); if (size > LAN8710A_IOBUF_SIZE) {
assert(mp->m_net_netdrv_dl_writev_s.count < LAN8710A_IOVEC_NR); printf("%s: dropping large packet (%zu)\n", e->name, size);
/* return OK;
* Copy the I/O vector table.
*/
if ((r = sys_safecopyfrom(mp->m_source,
mp->m_net_netdrv_dl_writev_s.grant, 0,
(vir_bytes) iovec,
mp->m_net_netdrv_dl_writev_s.count *
sizeof(iovec_s_t))) != OK) {
panic("sys_safecopyfrom() failed: %d", r);
}
/* setup descriptors */
p_tx_desc = &(e->tx_desc[e->tx_desc_idx]);
/*
* Check if descriptor is available for host
* and drop the packet if not.
*/
if (LAN8710A_DESC_FLAG_OWN & p_tx_desc->pkt_len_flags) {
panic("No available transmit descriptor.");
}
/* virtual address of buffer */
p_buf = e->p_tx_buf + e->tx_desc_idx * LAN8710A_IOBUF_SIZE;
buf_data_len = 0;
for (i = 0; i < mp->m_net_netdrv_dl_writev_s.count; i++) {
if ((buf_data_len + iovec[i].iov_size)
> LAN8710A_IOBUF_SIZE) {
panic("packet too long");
}
/* copy data to buffer */
size = iovec[i].iov_size
< (LAN8710A_IOBUF_SIZE - buf_data_len) ?
iovec[i].iov_size
: (LAN8710A_IOBUF_SIZE - buf_data_len);
/* Copy bytes to TX queue buffers. */
if ((r = sys_safecopyfrom(mp->m_source,
iovec[i].iov_grant, 0,
(vir_bytes) p_buf, size)) != OK) {
panic("sys_safecopyfrom() failed: %d", r);
}
p_buf += size;
buf_data_len += size;
}
/* set descriptor length */
p_tx_desc->buffer_length_off = buf_data_len;
/* set flags */
p_tx_desc->pkt_len_flags = (LAN8710A_DESC_FLAG_OWN |
LAN8710A_DESC_FLAG_SOP |
LAN8710A_DESC_FLAG_EOP |
TX_DESC_TO_PORT1 |
TX_DESC_TO_PORT_EN);
p_tx_desc->pkt_len_flags |= buf_data_len;
/* setup DMA transfer */
lan8710a_dma_config_tx(e->tx_desc_idx);
e->tx_desc_idx++;
if (LAN8710A_NUM_TX_DESC == e->tx_desc_idx) {
e->tx_desc_idx = 0;
}
} else {
e->status |= LAN8710A_TRANSMIT;
} }
reply(e);
/* virtual address of buffer */
buf = e->p_tx_buf + e->tx_desc_idx * LAN8710A_IOBUF_SIZE;
netdriver_copyin(data, 0, buf, size);
/* set descriptor length */
p_tx_desc->buffer_length_off = size;
/* set flags */
p_tx_desc->pkt_len_flags = (LAN8710A_DESC_FLAG_OWN |
LAN8710A_DESC_FLAG_SOP |
LAN8710A_DESC_FLAG_EOP |
TX_DESC_TO_PORT1 |
TX_DESC_TO_PORT_EN);
p_tx_desc->pkt_len_flags |= size;
/* setup DMA transfer */
lan8710a_dma_config_tx(e->tx_desc_idx);
e->tx_desc_idx++;
if (LAN8710A_NUM_TX_DESC == e->tx_desc_idx)
e->tx_desc_idx = 0;
return OK;
} }
/*============================================================================* /*============================================================================*
* lan8710a_readv_s * * lan8710a_recv *
*============================================================================*/ *============================================================================*/
static void static ssize_t
lan8710a_readv_s(mp, from_int) lan8710a_recv(struct netdriver_data * data, size_t max)
message *mp;
int from_int;
{ {
iovec_s_t iovec[LAN8710A_IOVEC_NR];
lan8710a_t *e = &lan8710a_state; lan8710a_t *e = &lan8710a_state;
lan8710a_desc_t *p_rx_desc; lan8710a_desc_t *p_rx_desc;
u32_t flags; u32_t flags;
u8_t *p_buf; u8_t *buf;
u16_t pkt_data_len; size_t off, size, chunk;
u16_t buf_bytes, buf_len;
int i, r, size;
/* Are we called from the interrupt handler? */ /*
if (!from_int) { * Only handle one packet at a time.
e->rx_message = *mp; */
e->client = mp->m_source; p_rx_desc = &(e->rx_desc[e->rx_desc_idx]);
e->status |= LAN8710A_READING; /* find next OWN descriptor with SOP flag */
e->rx_size = 0; while ((0 == (LAN8710A_DESC_FLAG_SOP & p_rx_desc->pkt_len_flags)) &&
(0 == (LAN8710A_DESC_FLAG_OWN & p_rx_desc->pkt_len_flags))) {
p_rx_desc->buffer_length_off = LAN8710A_IOBUF_SIZE;
/* set ownership of current descriptor to EMAC */
p_rx_desc->pkt_len_flags = LAN8710A_DESC_FLAG_OWN;
assert(e->rx_message.m_net_netdrv_dl_readv_s.count > 0); e->rx_desc_idx++;
assert(e->rx_message.m_net_netdrv_dl_readv_s.count < LAN8710A_IOVEC_NR); if (LAN8710A_NUM_RX_DESC == e->rx_desc_idx)
} e->rx_desc_idx = 0;
if (e->status & LAN8710A_READING) {
/*
* Copy the I/O vector table first.
*/
if ((r = sys_safecopyfrom(e->rx_message.m_source,
e->rx_message.m_net_netdrv_dl_readv_s.grant, 0,
(vir_bytes) iovec,
e->rx_message.m_net_netdrv_dl_readv_s.count *
sizeof(iovec_s_t))) != OK) {
panic("sys_safecopyfrom() failed: %d", r);
}
/*
* Only handle one packet at a time.
*/
p_rx_desc = &(e->rx_desc[e->rx_desc_idx]); p_rx_desc = &(e->rx_desc[e->rx_desc_idx]);
/* find next OWN descriptor with SOP flag */
while ((0 == (LAN8710A_DESC_FLAG_SOP &
p_rx_desc->pkt_len_flags)) &&
(0 == (LAN8710A_DESC_FLAG_OWN &
p_rx_desc->pkt_len_flags))) {
p_rx_desc->buffer_length_off = LAN8710A_IOBUF_SIZE;
/* set ownership of current descriptor to EMAC */
p_rx_desc->pkt_len_flags = LAN8710A_DESC_FLAG_OWN;
e->rx_desc_idx++;
if (LAN8710A_NUM_RX_DESC == e->rx_desc_idx)
e->rx_desc_idx = 0;
p_rx_desc = &(e->rx_desc[e->rx_desc_idx]);
}
if (0 == (LAN8710A_DESC_FLAG_SOP & p_rx_desc->pkt_len_flags)) {
/* SOP was not found */
reply(e);
return;
}
/*
* Copy to vector elements.
*/
pkt_data_len = 0;
buf_bytes = 0;
p_buf = e->p_rx_buf + e->rx_desc_idx * LAN8710A_IOBUF_SIZE;
for (i = 0; i < e->rx_message.m_net_netdrv_dl_readv_s.count; i++) {
buf_len = p_rx_desc->buffer_length_off & 0xFFFF;
if (buf_bytes == buf_len) {
/* Whole buffer move to the next descriptor */
p_rx_desc->buffer_length_off =
LAN8710A_IOBUF_SIZE;
/* set ownership of current desc to EMAC */
p_rx_desc->pkt_len_flags =
LAN8710A_DESC_FLAG_OWN;
buf_bytes = 0;
e->rx_desc_idx++;
if (LAN8710A_NUM_RX_DESC == e->rx_desc_idx)
e->rx_desc_idx = 0;
p_rx_desc = &(e->rx_desc[e->rx_desc_idx]);
p_buf = e->p_rx_buf + (e->rx_desc_idx *
LAN8710A_IOBUF_SIZE) +
(p_rx_desc->buffer_length_off >> 16);
buf_len = p_rx_desc->buffer_length_off & 0xFFFF;
}
size = iovec[i].iov_size < (buf_len - buf_bytes) ?
iovec[i].iov_size :
(buf_len - buf_bytes);
if ((r = sys_safecopyto(e->rx_message.m_source,
iovec[i].iov_grant, 0,
(vir_bytes) p_buf,
size)) != OK) {
panic("sys_safecopyto() failed: %d", r);
}
p_buf += size;
buf_bytes += size;
pkt_data_len += size;
/* if EOP flag is set -> stop processing */
if ((LAN8710A_DESC_FLAG_EOP & p_rx_desc->pkt_len_flags) &&
(buf_bytes == buf_len)) {
/* end of packet */
break;
}
}
do {
/* reset owned descriptors up to EOP flag */
flags = p_rx_desc->pkt_len_flags;
p_rx_desc->buffer_length_off = LAN8710A_IOBUF_SIZE;
/* set ownership of current descriptor to EMAC */
p_rx_desc->pkt_len_flags = LAN8710A_DESC_FLAG_OWN;
e->rx_desc_idx++;
if (LAN8710A_NUM_RX_DESC == e->rx_desc_idx)
e->rx_desc_idx = 0;
p_rx_desc = &(e->rx_desc[e->rx_desc_idx]);
}
while (0 == (flags & LAN8710A_DESC_FLAG_EOP));
/*
* Update state.
*/
e->status |= LAN8710A_RECEIVED;
e->rx_size = pkt_data_len;
} }
reply(e);
if (0 == (LAN8710A_DESC_FLAG_SOP & p_rx_desc->pkt_len_flags)) {
/* SOP was not found */
return SUSPEND;
}
/*
* Copy data from descriptors, from SOP to EOP inclusive.
* TODO: make sure that the presence of a SOP slot implies the presence
* of an EOP slot, because we are not checking for ownership below..
*/
size = 0;
off = 0;
for (;;) {
buf = e->p_rx_buf + e->rx_desc_idx * LAN8710A_IOBUF_SIZE + off;
chunk = p_rx_desc->buffer_length_off & 0xFFFF;
/* Truncate packets that are too large. */
if (chunk > max - size)
chunk = max - size;
if (chunk > 0) {
netdriver_copyout(data, size, buf, chunk);
size += chunk;
}
flags = p_rx_desc->pkt_len_flags;
/* Whole buffer move to the next descriptor */
p_rx_desc->buffer_length_off = LAN8710A_IOBUF_SIZE;
/* set ownership of current desc to EMAC */
p_rx_desc->pkt_len_flags = LAN8710A_DESC_FLAG_OWN;
e->rx_desc_idx++;
if (LAN8710A_NUM_RX_DESC == e->rx_desc_idx)
e->rx_desc_idx = 0;
p_rx_desc = &(e->rx_desc[e->rx_desc_idx]);
/* if EOP flag is set -> stop processing */
if (flags & LAN8710A_DESC_FLAG_EOP)
break;
/*
* TODO: the upper 16 bits of buffer_length_off are used *only*
* for descriptors *after* the first one; I'm retaining this
* behavior because I don't have the chip's spec, but it may be
* better to simplify/correct this behavior. --David
*/
off = p_rx_desc->buffer_length_off >> 16;
}
return size;
} }
/*============================================================================* /*============================================================================*
* lan8710a_phy_write * * lan8710a_phy_write *
*============================================================================*/ *============================================================================*/
static void static void
lan8710a_phy_write(reg, value) lan8710a_phy_write(u32_t reg, u32_t value)
u32_t reg;
u32_t value;
{ {
if (!(lan8710a_reg_read(MDIOUSERACCESS0) & MDIO_GO)) { if (!(lan8710a_reg_read(MDIOUSERACCESS0) & MDIO_GO)) {
/* Clearing MDIOUSERACCESS0 register */ /* Clearing MDIOUSERACCESS0 register */
@ -1073,7 +832,8 @@ u32_t value;
lan8710a_reg_set(MDIOUSERACCESS0, lan8710a_reg_set(MDIOUSERACCESS0,
lan8710a_state.phy_address << MDIO_PHYADR); lan8710a_state.phy_address << MDIO_PHYADR);
/* Data written only 16 bits. */ /* Data written only 16 bits. */
lan8710a_reg_set(MDIOUSERACCESS0, (value & 0xFFFF) << MDIO_DATA); lan8710a_reg_set(MDIOUSERACCESS0,
(value & 0xFFFF) << MDIO_DATA);
lan8710a_reg_set(MDIOUSERACCESS0, MDIO_GO); lan8710a_reg_set(MDIOUSERACCESS0, MDIO_GO);
/* Waiting for writing completion */ /* Waiting for writing completion */
@ -1085,8 +845,7 @@ u32_t value;
* lan8710a_phy_read * * lan8710a_phy_read *
*============================================================================*/ *============================================================================*/
static u32_t static u32_t
lan8710a_phy_read(reg) lan8710a_phy_read(u32_t reg)
u32_t reg;
{ {
u32_t value = 0xFFFFFFFF; u32_t value = 0xFFFFFFFF;
@ -1116,7 +875,7 @@ u32_t reg;
* lan8710a_reset_hw * * lan8710a_reset_hw *
*============================================================================*/ *============================================================================*/
static void static void
lan8710a_reset_hw() lan8710a_reset_hw(void)
{ {
/* Assert a Device Reset signal. */ /* Assert a Device Reset signal. */
lan8710a_phy_write(LAN8710A_CTRL_REG, LAN8710A_SOFT_RESET); lan8710a_phy_write(LAN8710A_CTRL_REG, LAN8710A_SOFT_RESET);
@ -1129,8 +888,7 @@ lan8710a_reset_hw()
* lan8710a_reg_read * * lan8710a_reg_read *
*============================================================================*/ *============================================================================*/
static u32_t static u32_t
lan8710a_reg_read(reg) lan8710a_reg_read(volatile u32_t *reg)
volatile u32_t *reg;
{ {
u32_t value; u32_t value;
@ -1145,9 +903,7 @@ volatile u32_t *reg;
* lan8710a_reg_write * * lan8710a_reg_write *
*============================================================================*/ *============================================================================*/
static void static void
lan8710a_reg_write(reg, value) lan8710a_reg_write(volatile u32_t *reg, u32_t value)
volatile u32_t *reg;
u32_t value;
{ {
/* Write to memory mapped register. */ /* Write to memory mapped register. */
*reg = value; *reg = value;
@ -1157,9 +913,7 @@ u32_t value;
* lan8710a_reg_set * * lan8710a_reg_set *
*============================================================================*/ *============================================================================*/
static void static void
lan8710a_reg_set(reg, value) lan8710a_reg_set(volatile u32_t *reg, u32_t value)
volatile u32_t *reg;
u32_t value;
{ {
u32_t data; u32_t data;
@ -1174,9 +928,7 @@ u32_t value;
* lan8710a_reg_unset * * lan8710a_reg_unset *
*============================================================================*/ *============================================================================*/
static void static void
lan8710a_reg_unset(reg, value) lan8710a_reg_unset(volatile u32_t *reg, u32_t value)
volatile u32_t *reg;
u32_t value;
{ {
u32_t data; u32_t data;
@ -1186,61 +938,3 @@ u32_t value;
/* Unset value, and write back. */ /* Unset value, and write back. */
lan8710a_reg_write(reg, data & ~value); lan8710a_reg_write(reg, data & ~value);
} }
/*============================================================================*
* mess_reply *
*============================================================================*/
static void
mess_reply(req, reply)
message *req;message *reply;
{
if (ipc_send(req->m_source, reply) != OK) {
panic("unable to send reply message");
}
}
/*============================================================================*
* reply *
*============================================================================*/
static void
reply(e)
lan8710a_t *e;
{
message msg;
int r;
/* Only reply to client for read/write request. */
if (!(e->status & LAN8710A_READING ||
e->status & LAN8710A_WRITING)) {
return;
}
/* Construct reply message. */
msg.m_type = DL_TASK_REPLY;
msg.m_netdrv_net_dl_task.flags = DL_NOFLAGS;
msg.m_netdrv_net_dl_task.count = 0;
/* Did we successfully receive packet(s)? */
if (e->status & LAN8710A_READING &&
e->status & LAN8710A_RECEIVED) {
msg.m_netdrv_net_dl_task.flags |= DL_PACK_RECV;
msg.m_netdrv_net_dl_task.count =
e->rx_size >= ETH_MIN_PACK_SIZE ?
e->rx_size : ETH_MIN_PACK_SIZE;
/* Clear flags. */
e->status &= ~(LAN8710A_READING | LAN8710A_RECEIVED);
}
/* Did we successfully transmit packet(s)? */
if (e->status & LAN8710A_TRANSMIT &&
e->status & LAN8710A_WRITING) {
msg.m_netdrv_net_dl_task.flags |= DL_PACK_SEND;
/* Clear flags. */
e->status &= ~(LAN8710A_WRITING | LAN8710A_TRANSMIT);
}
/* Acknowledge to INET. */
if ((r = ipc_send(e->client, &msg) != OK)) {
panic("ipc_send() failed: %d", r);
}
}

View File

@ -16,26 +16,9 @@
#define LAN8710A_DEBUG_PRINT(args) #define LAN8710A_DEBUG_PRINT(args)
#endif #endif
#ifndef ERR
#define ERR (-1) /* general error flag */
#endif
#ifndef OK
#define OK 0 /* general OK flag */
#endif
#define MAP_FAILED ((void *) -1) /* mmap() failed */
/* Ethernet driver defines */ /* Ethernet driver defines */
#define LAN8710A_NAME_LEN (11) #define LAN8710A_NAME_LEN (11)
/* Ethernet driver states */
#define LAN8710A_DETECTED (1 << 0)
#define LAN8710A_ENABLED (1 << 1)
#define LAN8710A_READING (1 << 2)
#define LAN8710A_WRITING (1 << 3)
#define LAN8710A_RECEIVED (1 << 4)
#define LAN8710A_TRANSMIT (1 << 5)
/* Descriptors flags */ /* Descriptors flags */
#define LAN8710A_DESC_FLAG_OWN (1 << 29) /* ownership flag */ #define LAN8710A_DESC_FLAG_OWN (1 << 29) /* ownership flag */
#define LAN8710A_DESC_FLAG_SOP (1 << 31) /* start of packet flag */ #define LAN8710A_DESC_FLAG_SOP (1 << 31) /* start of packet flag */
@ -58,9 +41,6 @@
/** Number of receive descriptors */ /** Number of receive descriptors */
#define LAN8710A_NUM_RX_DESC (255) #define LAN8710A_NUM_RX_DESC (255)
/** Number of I/O vectors to use. */
#define LAN8710A_IOVEC_NR (16)
/** Size of each I/O buffer per descriptor. */ /** Size of each I/O buffer per descriptor. */
#define LAN8710A_IOBUF_SIZE (1520) #define LAN8710A_IOBUF_SIZE (1520)
@ -89,11 +69,9 @@ typedef struct lan8710a_t
phys_bytes rx_desc_phy; phys_bytes rx_desc_phy;
phys_bytes tx_desc_phy; phys_bytes tx_desc_phy;
char name[LAN8710A_NAME_LEN]; char name[LAN8710A_NAME_LEN];
int status;
int irq_rx_hook; /* Rx interrupt Request Vector Hook. */ int irq_rx_hook; /* Rx interrupt Request Vector Hook. */
int irq_tx_hook; /* Tx interrupt Request Vector Hook. */ int irq_tx_hook; /* Tx interrupt Request Vector Hook. */
int instance; int instance;
ether_addr_t address; /* Ethernet MAC address. */
u8_t *regs; u8_t *regs;
u32_t phy_address; u32_t phy_address;
u8_t *p_rx_buf; /* pointer to the buffer with receive frames */ u8_t *p_rx_buf; /* pointer to the buffer with receive frames */
@ -101,10 +79,6 @@ typedef struct lan8710a_t
u16_t tx_desc_idx; /* index of the next transmit desciptor */ u16_t tx_desc_idx; /* index of the next transmit desciptor */
u16_t rx_desc_idx; /* index of the next receive desciptor */ u16_t rx_desc_idx; /* index of the next receive desciptor */
int client;
message tx_message;
message rx_message;
unsigned int rx_size;
/* register mapping */ /* register mapping */
vir_bytes regs_cp_per; vir_bytes regs_cp_per;

File diff suppressed because it is too large Load Diff

View File

@ -1,39 +1,8 @@
/* macros for 'mode' */
#define EC_DISABLED 0x0
#define EC_SINK 0x1
#define EC_ENABLED 0x2
/* macros for 'flags' */ /* macros for 'flags' */
#define ECF_EMPTY 0x000 #define ECF_PROMISC 0x01
#define ECF_PACK_SEND 0x001 #define ECF_MULTI 0x02
#define ECF_PACK_RECV 0x002 #define ECF_BROAD 0x04
#define ECF_SEND_AVAIL 0x004
#define ECF_READING 0x010
#define ECF_PROMISC 0x040
#define ECF_MULTI 0x080
#define ECF_BROAD 0x100
#define ECF_ENABLED 0x200
#define ECF_STOPPED 0x400
/* === macros for ether cards (our generalized version) === */
#define EC_ISR_RINT 0x0001
#define EC_ISR_WINT 0x0002
#define EC_ISR_RERR 0x0010
#define EC_ISR_WERR 0x0020
#define EC_ISR_ERR 0x0040
#define EC_ISR_RST 0x0100
/* IOVEC */
#define IOVEC_NR 16
typedef struct iovec_dat
{
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_t;
/* ====== ethernet card info. ====== */ /* ====== ethernet card info. ====== */
typedef struct ether_card typedef struct ether_card
@ -41,35 +10,14 @@ typedef struct ether_card
/* ####### MINIX style ####### */ /* ####### MINIX style ####### */
char port_name[sizeof("lance#n")]; char port_name[sizeof("lance#n")];
int flags; int flags;
int mode;
int transfer_mode;
eth_stat_t eth_stat; eth_stat_t eth_stat;
iovec_dat_t read_iovec;
iovec_dat_t write_iovec;
iovec_dat_t tmp_iovec;
vir_bytes write_s;
vir_bytes read_s;
int client;
message sendmsg;
/* ######## device info. ####### */ /* ######## device info. ####### */
port_t ec_port; port_t ec_port;
phys_bytes ec_linmem;
int ec_irq; int ec_irq;
int ec_int_pending;
int ec_hook; int ec_hook;
int ec_ramsize;
/* Addrassing */
u16_t ec_memseg;
vir_bytes ec_memoff;
ether_addr_t mac_address;
} ether_card_t; } ether_card_t;
#define DEI_DEFAULT 0x8000
/* /*
* NOTE: Not all the CSRs are defined. Just the ones that were deemed * NOTE: Not all the CSRs are defined. Just the ones that were deemed
* necessary or potentially useful. * necessary or potentially useful.

View File

@ -2,8 +2,8 @@
PROG= orinoco PROG= orinoco
SRCS= orinoco.c hermes.c SRCS= orinoco.c hermes.c
DPADD+= ${LIBNETDRIVER} ${LIBSYS} ${LIBTIMERS} DPADD+= ${LIBNETDRIVER} ${LIBSYS}
LDADD+= -lnetdriver -lsys -ltimers LDADD+= -lnetdriver -lsys
CPPFLAGS.orinoco.c+= -I${NETBSDSRCDIR}/minix CPPFLAGS.orinoco.c+= -I${NETBSDSRCDIR}/minix

File diff suppressed because it is too large Load Diff

View File

@ -26,74 +26,39 @@ typedef struct s_or
{ {
int or_irq; int or_irq;
int or_hook_id; int or_hook_id;
int or_mode;
int or_flags;
char *or_model;
int or_client;
int or_link_up; int or_link_up;
int or_got_int; int or_got_int;
int or_tx_alive; int or_tx_alive;
int or_send_int; int or_send_int;
int or_clear_rx;
u32_t or_base_port;
int or_need_reset; int or_need_reset;
int or_report_link; int or_report_link;
/* Events */ /* Events */
int or_ev_rx;
int or_ev_tx;
int or_ev_info;
int or_ev_txexc;
int or_ev_alloc;
int connected; int connected;
u16_t channel_mask;
u16_t channel;
u16_t ap_density;
u16_t rts_thresh;
int bitratemode;
int last_linkstatus; int last_linkstatus;
int max_data_len;
int port_type;
/* Rx */ /* Rx */
phys_bytes or_rx_buf; phys_bytes or_rx_buf;
vir_bytes or_read_s;
u16_t rxfid[NR_RX_BUFS]; u16_t rxfid[NR_RX_BUFS];
int rx_length[NR_RX_BUFS]; int rx_length[NR_RX_BUFS];
u8_t rx_buf[NR_RX_BUFS][IEEE802_11_FRAME_LEN]; u8_t rx_buf[NR_RX_BUFS][IEEE802_11_FRAME_LEN];
u8_t rx_offset[NR_RX_BUFS];
int rx_first; int rx_first;
int rx_last; int rx_last;
int rx_current; int rx_current;
/* Tx */ /* Tx */
u16_t or_nicbuf_size; u16_t or_nicbuf_size;
vir_bytes or_transm_s;
int or_tx_head; int or_tx_head;
int or_tx_tail; int or_tx_tail;
int or_tx_busy;
struct struct
{ {
int ret_busy; int ret_busy;
u16_t or_txfid; u16_t or_txfid;
} or_tx; } or_tx;
u32_t or_ertxth;
/* PCI related */
int or_seen;
int devind;
/* 'large' items */
irq_hook_t or_hook;
eth_stat_t or_stat; eth_stat_t or_stat;
message or_rx_mess; char or_name[sizeof(OR_NAME)];
message or_tx_mess;
ether_addr_t or_address;
iovec_t or_iovec[IOVEC_NR];
iovec_s_t or_iovec_s[IOVEC_NR];
char or_name[sizeof (OR_NAME)];
hermes_t hw; hermes_t hw;
char nick[IW_ESSID_MAX_SIZE + 1];
} t_or; } t_or;

View File

@ -1,13 +1,13 @@
# Makefile for the Realtek RTL8139 ethernet driver (RTL8139) # Makefile for the Realtek RTL8139 ethernet driver (RTL8139)
PROG= rtl8139 PROG= rtl8139
SRCS= rtl8139.c liveupdate.c SRCS= rtl8139.c
FILES=$(PROG).conf FILES=$(PROG).conf
FILESNAME=$(PROG) FILESNAME=$(PROG)
FILESDIR= /etc/system.conf.d FILESDIR= /etc/system.conf.d
DPADD+= ${LIBNETDRIVER} ${LIBSYS} ${LIBTIMERS} DPADD+= ${LIBNETDRIVER} ${LIBSYS}
LDADD+= -lnetdriver -lsys -ltimers LDADD+= -lnetdriver -lsys
CPPFLAGS+= -I${NETBSDSRCDIR}/minix CPPFLAGS+= -I${NETBSDSRCDIR}/minix

View File

@ -1,3 +1,5 @@
/* Code left here for historical purposes only. TODO: move into libnetdriver */
#include "rtl8139.h" #include "rtl8139.h"
/* State management variables. */ /* State management variables. */

File diff suppressed because it is too large Load Diff

View File

@ -6,32 +6,9 @@ Created: Aug 2003 by Philip Homburg <philip@cs.vu.nl>
#include <minix/drivers.h> #include <minix/drivers.h>
#include <minix/netdriver.h> #include <minix/netdriver.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stddef.h>
#include <minix/com.h>
#include <minix/ds.h>
#include <minix/keymap.h>
#include <minix/syslib.h>
#include <minix/type.h>
#include <minix/sysutil.h>
#include <minix/endpoint.h>
#include <minix/timers.h>
#include <net/hton.h>
#include <net/gen/ether.h>
#include <net/gen/eth_io.h>
#include <machine/pci.h> #include <machine/pci.h>
#include <minix/ds.h>
#include <sys/types.h>
#include <fcntl.h>
#include <assert.h> #include <assert.h>
#include <unistd.h>
#include <sys/ioc_memory.h>
#include "kernel/const.h"
#include "kernel/config.h"
#include "kernel/type.h"
#define RL_IDR 0x00 /* Ethernet address #define RL_IDR 0x00 /* Ethernet address
* Note: RL_9346CR_EEM_CONFIG mode is * Note: RL_9346CR_EEM_CONFIG mode is
@ -453,18 +430,12 @@ d8 R/W Config5 Configuration register 5
d9-ff reserved d9-ff reserved
#endif #endif
#define Proc_number(p) proc_number(p)
#define debug 0
#define printW() ((void)0)
#define vm_1phys2bus(p) (p) #define vm_1phys2bus(p) (p)
#define RX_BUFSIZE RL_RCR_RBLEN_64K_SIZE #define RX_BUFSIZE RL_RCR_RBLEN_64K_SIZE
#define RX_BUFBITS RL_RCR_RBLEN_64K #define RX_BUFBITS RL_RCR_RBLEN_64K
#define N_TX_BUF RL_N_TX #define N_TX_BUF RL_N_TX
/* I/O vectors are handled IOVEC_NR entries at a time. */
#define IOVEC_NR 16
/* Configuration */ /* Configuration */
#define RL_ENVVAR "RTLETH" #define RL_ENVVAR "RTLETH"
@ -473,8 +444,6 @@ typedef struct re
port_t re_base_port; port_t re_base_port;
int re_irq; int re_irq;
int re_mode; int re_mode;
int re_flags;
int re_client;
int re_link_up; int re_link_up;
int re_got_int; int re_got_int;
int re_send_int; int re_send_int;
@ -482,12 +451,12 @@ typedef struct re
int re_clear_rx; int re_clear_rx;
int re_need_reset; int re_need_reset;
int re_tx_alive; int re_tx_alive;
char *re_model; int re_tx_busy;
const char *re_model;
/* Rx */ /* Rx */
phys_bytes re_rx_buf; phys_bytes re_rx_buf;
char *v_re_rx_buf; char *v_re_rx_buf;
vir_bytes re_read_s;
/* Tx */ /* Tx */
int re_tx_head; int re_tx_head;
@ -500,33 +469,10 @@ typedef struct re
} re_tx[N_TX_BUF]; } re_tx[N_TX_BUF];
u32_t re_ertxth; /* Early Tx Threshold */ u32_t re_ertxth; /* Early Tx Threshold */
/* PCI related */
int re_seen; /* TRUE iff device available */
/* 'large' items */
int re_hook_id; /* IRQ hook id at kernel */ int re_hook_id; /* IRQ hook id at kernel */
eth_stat_t re_stat; eth_stat_t re_stat;
ether_addr_t re_address;
message re_rx_mess;
message re_tx_mess;
char re_name[sizeof("rtl8139#n")]; char re_name[sizeof("rtl8139#n")];
iovec_t re_iovec[IOVEC_NR]; } re_t;
iovec_s_t re_iovec_s[IOVEC_NR];
}
re_t;
#define REM_DISABLED 0x0
#define REM_ENABLED 0x1
#define REF_PACK_SENT 0x001
#define REF_PACK_RECV 0x002
#define REF_SEND_AVAIL 0x004
#define REF_READING 0x010
#define REF_EMPTY 0x000
#define REF_PROMISC 0x040
#define REF_MULTI 0x080
#define REF_BROAD 0x100
#define REF_ENABLED 0x200
/* /*
* $PchId: rtl8139.h,v 1.1 2003/09/05 10:58:50 philip Exp $ * $PchId: rtl8139.h,v 1.1 2003/09/05 10:58:50 philip Exp $

View File

@ -6,8 +6,8 @@ FILES=$(PROG).conf
FILESNAME=$(PROG) FILESNAME=$(PROG)
FILESDIR= /etc/system.conf.d FILESDIR= /etc/system.conf.d
DPADD+= ${LIBNETDRIVER} ${LIBSYS} ${LIBTIMERS} DPADD+= ${LIBNETDRIVER} ${LIBSYS}
LDADD+= -lnetdriver -lsys -ltimers LDADD+= -lnetdriver -lsys
CPPFLAGS+= -I${NETBSDSRCDIR}/minix CPPFLAGS+= -I${NETBSDSRCDIR}/minix

File diff suppressed because it is too large Load Diff

View File

@ -22,11 +22,18 @@
#include "virtio_net.h" #include "virtio_net.h"
#define VERBOSE 0
#if VERBOSE
#define dput(s) do { dprintf(s); printf("\n"); } while (0) #define dput(s) do { dprintf(s); printf("\n"); } while (0)
#define dprintf(s) do { \ #define dprintf(s) do { \
printf("%s: ", name); \ printf("%s: ", name); \
printf s; \ printf s; \
} while (0) } while (0)
#else
#define dput(s)
#define dprintf(s)
#endif
static struct virtio_device *net_dev; static struct virtio_device *net_dev;
@ -50,6 +57,7 @@ struct packet {
phys_bytes phdr; phys_bytes phdr;
char *vdata; char *vdata;
phys_bytes pdata; phys_bytes pdata;
size_t len;
STAILQ_ENTRY(packet) next; STAILQ_ENTRY(packet) next;
}; };
@ -60,7 +68,6 @@ static struct virtio_net_hdr *hdrs_vir;
static phys_bytes hdrs_phys; static phys_bytes hdrs_phys;
static struct packet *packets; static struct packet *packets;
static int in_rx; static int in_rx;
static int started;
/* Packets on this list can be given to the host */ /* Packets on this list can be given to the host */
static STAILQ_HEAD(free_list, packet) free_list; static STAILQ_HEAD(free_list, packet) free_list;
@ -68,21 +75,13 @@ static STAILQ_HEAD(free_list, packet) free_list;
/* Packets on this list are to be given to inet */ /* Packets on this list are to be given to inet */
static STAILQ_HEAD(recv_list, packet) recv_list; static STAILQ_HEAD(recv_list, packet) recv_list;
/* State about pending inet messages */
static int rx_pending;
static message pending_rx_msg;
static int tx_pending;
static message pending_tx_msg;
/* Various state data */ /* Various state data */
static u8_t virtio_net_mac[6];
static eth_stat_t virtio_net_stats; static eth_stat_t virtio_net_stats;
static int spurious_interrupt; static int spurious_interrupt;
/* Prototypes */ /* Prototypes */
static int virtio_net_probe(int skip); static int virtio_net_probe(unsigned int skip);
static int virtio_net_config(void); static void virtio_net_config(ether_addr_t *addr);
static int virtio_net_alloc_bufs(void); static int virtio_net_alloc_bufs(void);
static void virtio_net_init_queues(void); static void virtio_net_init_queues(void);
@ -90,28 +89,24 @@ static void virtio_net_refill_rx_queue(void);
static void virtio_net_check_queues(void); static void virtio_net_check_queues(void);
static void virtio_net_check_pending(void); static void virtio_net_check_pending(void);
static void virtio_net_fetch_iovec(iovec_s_t *iov, message *m, static int virtio_net_init(unsigned int instance, ether_addr_t *addr);
cp_grant_id_t grant, size_t count); static void virtio_net_stop(void);
static int virtio_net_cpy_to_user(message *m); static int virtio_net_send(struct netdriver_data *data, size_t len);
static int virtio_net_cpy_from_user(message *m); static ssize_t virtio_net_recv(struct netdriver_data *data, size_t max);
static void virtio_net_stat(eth_stat_t *stat);
static void virtio_net_intr(message *m); static void virtio_net_intr(unsigned int mask);
static void virtio_net_write(message *m);
static void virtio_net_read(message *m);
static void virtio_net_conf(message *m);
static void virtio_net_getstat(message *m);
static void virtio_net_notify(message *m);
static void virtio_net_msg(message *m);
static void virtio_net_main_loop(void);
static void sef_local_startup(void);
static int sef_cb_init_fresh(int type, sef_init_info_t *info);
static void sef_cb_signal_handler(int signo);
static const struct netdriver virtio_net_table = {
.ndr_init = virtio_net_init,
.ndr_stop = virtio_net_stop,
.ndr_recv = virtio_net_recv,
.ndr_send = virtio_net_send,
.ndr_stat = virtio_net_stat,
.ndr_intr = virtio_net_intr,
};
/* TODO: Features are pretty much ignored */ /* TODO: Features are pretty much ignored */
struct virtio_feature netf[] = { static struct virtio_feature netf[] = {
{ "partial csum", VIRTIO_NET_F_CSUM, 0, 0 }, { "partial csum", VIRTIO_NET_F_CSUM, 0, 0 },
{ "given mac", VIRTIO_NET_F_MAC, 0, 1 }, { "given mac", VIRTIO_NET_F_MAC, 0, 1 },
{ "status ", VIRTIO_NET_F_STATUS, 0, 0 }, { "status ", VIRTIO_NET_F_STATUS, 0, 0 },
@ -120,7 +115,7 @@ struct virtio_feature netf[] = {
}; };
static int static int
virtio_net_probe(int skip) virtio_net_probe(unsigned int skip)
{ {
/* virtio-net has at least 2 queues */ /* virtio-net has at least 2 queues */
int queues = 2; int queues = 2;
@ -142,8 +137,8 @@ virtio_net_probe(int skip)
return OK; return OK;
} }
static int static void
virtio_net_config(void) virtio_net_config(ether_addr_t * addr)
{ {
u32_t mac14; u32_t mac14;
u32_t mac56; u32_t mac56;
@ -153,12 +148,12 @@ virtio_net_config(void)
dprintf(("Mac set by host: ")); dprintf(("Mac set by host: "));
mac14 = virtio_sread32(net_dev, 0); mac14 = virtio_sread32(net_dev, 0);
mac56 = virtio_sread32(net_dev, 4); mac56 = virtio_sread32(net_dev, 4);
*(u32_t*)virtio_net_mac = mac14; memcpy(&addr->ea_addr[0], &mac14, 4);
*(u16_t*)(virtio_net_mac + 4) = mac56; memcpy(&addr->ea_addr[4], &mac56, 2);
for (i = 0; i < 6; i++) for (i = 0; i < 6; i++)
printf("%02x%s", virtio_net_mac[i], dprintf(("%02x%s", addr->ea_addr[i],
i == 5 ? "\n" : ":"); i == 5 ? "\n" : ":"));
} else { } else {
dput(("No mac")); dput(("No mac"));
} }
@ -174,8 +169,6 @@ virtio_net_config(void)
if (virtio_host_supports(net_dev, VIRTIO_NET_F_CTRL_RX)) if (virtio_host_supports(net_dev, VIRTIO_NET_F_CTRL_RX))
dput(("Host supports control channel for RX")); dput(("Host supports control channel for RX"));
return OK;
} }
static int static int
@ -233,7 +226,6 @@ virtio_net_refill_rx_queue(void)
struct packet *p; struct packet *p;
while ((in_rx < BUF_PACKETS / 2) && !STAILQ_EMPTY(&free_list)) { while ((in_rx < BUF_PACKETS / 2) && !STAILQ_EMPTY(&free_list)) {
/* peek */ /* peek */
p = STAILQ_FIRST(&free_list); p = STAILQ_FIRST(&free_list);
/* remove */ /* remove */
@ -253,7 +245,6 @@ virtio_net_refill_rx_queue(void)
virtio_to_queue(net_dev, RX_Q, phys, 2, p); virtio_to_queue(net_dev, RX_Q, phys, 2, p);
in_rx++; in_rx++;
} }
if (in_rx == 0 && STAILQ_EMPTY(&free_list)) { if (in_rx == 0 && STAILQ_EMPTY(&free_list)) {
@ -266,18 +257,21 @@ static void
virtio_net_check_queues(void) virtio_net_check_queues(void)
{ {
struct packet *p; struct packet *p;
size_t len;
/* Put the received packets into the recv list */ /* Put the received packets into the recv list */
while (virtio_from_queue(net_dev, RX_Q, (void **)&p) == 0) { while (virtio_from_queue(net_dev, RX_Q, (void **)&p, &len) == 0) {
p->len = len;
STAILQ_INSERT_TAIL(&recv_list, p, next); STAILQ_INSERT_TAIL(&recv_list, p, next);
in_rx--; in_rx--;
virtio_net_stats.ets_packetR++; virtio_net_stats.ets_packetR++;
} }
/* Packets from the TX queue just indicated they are free to /*
* Packets from the TX queue just indicated they are free to
* be reused now. inet already knows about them as being sent. * be reused now. inet already knows about them as being sent.
*/ */
while (virtio_from_queue(net_dev, TX_Q, (void **)&p) == 0) { while (virtio_from_queue(net_dev, TX_Q, (void **)&p, NULL) == 0) {
memset(p->vhdr, 0, sizeof(*p->vhdr)); memset(p->vhdr, 0, sizeof(*p->vhdr));
memset(p->vdata, 0, MAX_PACK_SIZE); memset(p->vdata, 0, MAX_PACK_SIZE);
STAILQ_INSERT_HEAD(&free_list, p, next); STAILQ_INSERT_HEAD(&free_list, p, next);
@ -288,173 +282,19 @@ virtio_net_check_queues(void)
static void static void
virtio_net_check_pending(void) virtio_net_check_pending(void)
{ {
int dst = 0xDEAD;
int r;
message reply;
reply.m_type = DL_TASK_REPLY;
reply.m_netdrv_net_dl_task.flags = DL_NOFLAGS;
reply.m_netdrv_net_dl_task.count = 0;
/* Pending read and something in recv_list? */ /* Pending read and something in recv_list? */
if (!STAILQ_EMPTY(&recv_list) && rx_pending) { if (!STAILQ_EMPTY(&recv_list))
dst = pending_rx_msg.m_source; netdriver_recv();
reply.m_netdrv_net_dl_task.count =
virtio_net_cpy_to_user(&pending_rx_msg);
reply.m_netdrv_net_dl_task.flags |= DL_PACK_RECV;
rx_pending = 0;
}
if (!STAILQ_EMPTY(&free_list) && tx_pending) { if (!STAILQ_EMPTY(&free_list))
dst = pending_tx_msg.m_source; netdriver_send();
virtio_net_cpy_from_user(&pending_tx_msg);
reply.m_netdrv_net_dl_task.flags |= DL_PACK_SEND;
tx_pending = 0;
}
/* Only reply if a pending request was handled */
if (reply.m_netdrv_net_dl_task.flags != DL_NOFLAGS)
if ((r = ipc_send(dst, &reply)) != OK)
panic("%s: ipc_send to %d failed (%d)", name, dst, r);
} }
static void static void
virtio_net_fetch_iovec(iovec_s_t *iov, message *m, cp_grant_id_t grant, size_t count) virtio_net_intr(unsigned int __unused mask)
{ {
int r;
r = sys_safecopyfrom(m->m_source, grant, 0, (vir_bytes)iov,
count * sizeof(iov[0]));
if (r != OK)
panic("%s: iovec fail for %d (%d)", name, m->m_source, r);
}
static int
virtio_net_cpy_to_user(message *m)
{
/* Hmm, this looks so similar to cpy_from_user... TODO */
int i, r, size, ivsz;
int left = MAX_PACK_SIZE; /* Try copying the whole packet */
int bytes = 0;
iovec_s_t iovec[NR_IOREQS];
struct packet *p;
/* This should only be called if recv_list has some entries */
assert(!STAILQ_EMPTY(&recv_list));
p = STAILQ_FIRST(&recv_list);
STAILQ_REMOVE_HEAD(&recv_list, next);
virtio_net_fetch_iovec(iovec, m, m->m_net_netdrv_dl_readv_s.grant,
m->m_net_netdrv_dl_readv_s.count);
for (i = 0; i < m->m_net_netdrv_dl_readv_s.count && left > 0; i++) {
ivsz = iovec[i].iov_size;
size = left > ivsz ? ivsz : left;
r = sys_safecopyto(m->m_source, iovec[i].iov_grant, 0,
(vir_bytes) p->vdata + bytes, size);
if (r != OK)
panic("%s: copy to %d failed (%d)", name,
m->m_source,
r);
left -= size;
bytes += size;
}
if (left != 0)
dput(("Uhm... left=%d", left));
/* Clean the packet */
memset(p->vhdr, 0, sizeof(*p->vhdr));
memset(p->vdata, 0, MAX_PACK_SIZE);
STAILQ_INSERT_HEAD(&free_list, p, next);
return bytes;
}
static int
sys_easy_vsafecopy_from(endpoint_t src_proc, iovec_s_t *iov, int count,
vir_bytes dst, size_t max, size_t *copied)
{
int i, r;
size_t left = max;
vir_bytes cur_off = 0;
struct vscp_vec vv[NR_IOREQS];
for (i = 0; i < count && left > 0; i++) {
vv[i].v_from = src_proc;
vv[i].v_to = SELF;
vv[i].v_gid = iov[i].iov_grant;
vv[i].v_offset = 0;
vv[i].v_addr = dst + cur_off;
vv[i].v_bytes = iov[i].iov_size;
/* More data in iov than the buffer can hold, this should be
* manageable by the caller.
*/
if (left - vv[i].v_bytes > left) {
printf("sys_easy_vsafecopy_from: buf too small!\n");
return ENOMEM;
}
left -= iov[i].iov_size;
cur_off += iov[i].iov_size;
}
/* Now that we prepared the vscp_vec, we can call vsafecopy() */
if ((r = sys_vsafecopy(vv, count)) != OK)
printf("sys_vsafecopy: failed: (%d)\n", r);
if (copied)
*copied = cur_off;
return OK;
}
static int
virtio_net_cpy_from_user(message *m)
{
/* Put user bytes into a a free packet buffer and
* then forward this packet to the TX queue.
*/
int r;
iovec_s_t iovec[NR_IOREQS];
struct vumap_phys phys[2];
struct packet *p;
size_t bytes;
/* This should only be called if free_list has some entries */
assert(!STAILQ_EMPTY(&free_list));
p = STAILQ_FIRST(&free_list);
STAILQ_REMOVE_HEAD(&free_list, next);
virtio_net_fetch_iovec(iovec, m, m->m_net_netdrv_dl_writev_s.grant,
m->m_net_netdrv_dl_writev_s.count);
r = sys_easy_vsafecopy_from(m->m_source, iovec,
m->m_net_netdrv_dl_writev_s.count, (vir_bytes)p->vdata,
MAX_PACK_SIZE, &bytes);
if (r != OK)
panic("%s: copy from %d failed", name, m->m_source);
phys[0].vp_addr = p->phdr;
assert(!(phys[0].vp_addr & 1));
phys[0].vp_size = sizeof(struct virtio_net_hdr);
phys[1].vp_addr = p->pdata;
assert(!(phys[1].vp_addr & 1));
phys[1].vp_size = bytes;
virtio_to_queue(net_dev, TX_Q, phys, 2, p);
return bytes;
}
static void
virtio_net_intr(message *m)
{
/* Check and clear interrupt flag */ /* Check and clear interrupt flag */
if (virtio_had_irq(net_dev)) { if (virtio_had_irq(net_dev)) {
virtio_net_check_queues(); virtio_net_check_queues();
@ -468,202 +308,131 @@ virtio_net_intr(message *m)
virtio_net_check_pending(); virtio_net_check_pending();
virtio_irq_enable(net_dev); virtio_irq_enable(net_dev);
/* Readd packets to the receive queue as necessary. */
virtio_net_refill_rx_queue();
} }
static void /*
virtio_net_write(message *m) * Put user bytes into a free packet buffer, forward this packet to the TX
{ * queue, and return OK. If there are no free packet buffers, return SUSPEND.
int r; */
message reply;
reply.m_type = DL_TASK_REPLY;
reply.m_netdrv_net_dl_task.flags = DL_NOFLAGS;
reply.m_netdrv_net_dl_task.count = 0;
if (!STAILQ_EMPTY(&free_list)) {
/* free_list contains at least one packet, use it */
reply.m_netdrv_net_dl_task.count = virtio_net_cpy_from_user(m);
reply.m_netdrv_net_dl_task.flags = DL_PACK_SEND;
} else {
pending_tx_msg = *m;
tx_pending = 1;
}
if ((r = ipc_send(m->m_source, &reply)) != OK)
panic("%s: ipc_send to %d failed (%d)", name, m->m_source, r);
}
static void
virtio_net_read(message *m)
{
int r;
message reply;
reply.m_type = DL_TASK_REPLY;
reply.m_netdrv_net_dl_task.flags = DL_NOFLAGS;
reply.m_netdrv_net_dl_task.count = 0;
if (!STAILQ_EMPTY(&recv_list)) {
/* recv_list contains at least one packet, copy it */
reply.m_netdrv_net_dl_task.count = virtio_net_cpy_to_user(m);
reply.m_netdrv_net_dl_task.flags = DL_PACK_RECV;
} else {
rx_pending = 1;
pending_rx_msg = *m;
}
if ((r = ipc_send(m->m_source, &reply)) != OK)
panic("%s: ipc_send to %d failed (%d)", name, m->m_source, r);
}
static void
virtio_net_conf(message *m)
{
/* TODO: Add the multicast, broadcast filtering etc. */
int i, r;
message reply;
/* If this is the first CONF message we see, fully initialize
* the device now.
*/
if (!started) {
started = 1;
virtio_device_ready(net_dev);
virtio_irq_enable(net_dev);
}
/* Prepare reply */
memcpy(reply.m_netdrv_net_dl_conf.hw_addr, virtio_net_mac,
sizeof(reply.m_netdrv_net_dl_conf.hw_addr));
reply.m_type = DL_CONF_REPLY;
reply.m_netdrv_net_dl_conf.stat = OK;
if ((r = ipc_send(m->m_source, &reply)) != OK)
panic("%s: ipc_send to %d failed (%d)", name, m->m_source, r);
}
static void
virtio_net_getstat(message *m)
{
int r;
message reply;
reply.m_type = DL_STAT_REPLY;
r = sys_safecopyto(m->m_source, m->m_net_netdrv_dl_getstat_s.grant, 0,
(vir_bytes)&virtio_net_stats,
sizeof(virtio_net_stats));
if (r != OK)
panic("%s: copy to %d failed (%d)", name, m->m_source, r);
if ((r = ipc_send(m->m_source, &reply)) != OK)
panic("%s: ipc_send to %d failed (%d)", name, m->m_source, r);
}
static void
virtio_net_notify(message *m)
{
if (_ENDPOINT_P(m->m_source) == HARDWARE)
virtio_net_intr(m);
}
static void
virtio_net_msg(message *m)
{
switch (m->m_type) {
case DL_WRITEV_S:
virtio_net_write(m);
break;
case DL_READV_S:
virtio_net_read(m);
break;
case DL_CONF:
virtio_net_conf(m);
break;
case DL_GETSTAT_S:
virtio_net_getstat(m);
break;
default:
panic("%s: illegal message: %d", name, m->m_type);
}
}
static void
virtio_net_main_loop(void)
{
message m;
int ipc_status;
int r;
while (TRUE) {
virtio_net_refill_rx_queue();
if ((r = netdriver_receive(ANY, &m, &ipc_status)) != OK)
panic("%s: netdriver_receive failed: %d", name, r);
if (is_ipc_notify(ipc_status))
virtio_net_notify(&m);
else
virtio_net_msg(&m);
}
}
int
main(int argc, char *argv[])
{
env_setargs(argc, argv);
sef_local_startup();
virtio_net_main_loop();
}
static void
sef_local_startup()
{
sef_setcb_init_fresh(sef_cb_init_fresh);
sef_setcb_init_lu(sef_cb_init_fresh);
sef_setcb_init_restart(sef_cb_init_fresh);
sef_setcb_lu_prepare(sef_cb_lu_prepare_always_ready);
sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid_workfree);
sef_setcb_signal_handler(sef_cb_signal_handler);
sef_startup();
}
static int static int
sef_cb_init_fresh(int type, sef_init_info_t *info) virtio_net_send(struct netdriver_data * data, size_t len)
{ {
long instance = 0; struct vumap_phys phys[2];
env_parse("instance", "d", 0, &instance, 0, 255); struct packet *p;
if (virtio_net_probe((int)instance) != OK) if (STAILQ_EMPTY(&free_list))
panic("%s: No device found", name); return SUSPEND;
if (virtio_net_config() != OK) p = STAILQ_FIRST(&free_list);
panic("%s: No device found", name); STAILQ_REMOVE_HEAD(&free_list, next);
if (len > MAX_PACK_SIZE)
panic("%s: packet too large to send: %zu", name, len);
netdriver_copyin(data, 0, p->vdata, len);
phys[0].vp_addr = p->phdr;
assert(!(phys[0].vp_addr & 1));
phys[0].vp_size = sizeof(struct virtio_net_hdr);
phys[1].vp_addr = p->pdata;
assert(!(phys[1].vp_addr & 1));
phys[1].vp_size = len;
virtio_to_queue(net_dev, TX_Q, phys, 2, p);
return OK;
}
/*
* Put a packet receive from the RX queue into a user buffer, and return the
* packet length. If there are no received packets, return SUSPEND.
*/
static ssize_t
virtio_net_recv(struct netdriver_data * data, size_t max)
{
struct packet *p;
ssize_t len;
/* Get the first received packet, if any. */
if (STAILQ_EMPTY(&recv_list))
return SUSPEND;
p = STAILQ_FIRST(&recv_list);
STAILQ_REMOVE_HEAD(&recv_list, next);
/* Copy out the packet contents. */
len = p->len - sizeof(struct virtio_net_hdr);
if (len > max)
len = max;
/*
* HACK: due to lack of padding, received packets may in fact be
* smaller than the minimum ethernet packet size. Inet will accept the
* packets just fine if we increase the length to its minimum. We
* already zeroed out the rest of the packet data, so this is safe.
*/
if (len < ETH_MIN_PACK_SIZE)
len = ETH_MIN_PACK_SIZE;
netdriver_copyout(data, 0, p->vdata, len);
/* Clean the packet. */
memset(p->vhdr, 0, sizeof(*p->vhdr));
memset(p->vdata, 0, MAX_PACK_SIZE);
STAILQ_INSERT_HEAD(&free_list, p, next);
/* Readd packets to the receive queue as necessary. */
virtio_net_refill_rx_queue();
return len;
}
/*
* Return statistics.
*/
static void
virtio_net_stat(eth_stat_t *stat)
{
memcpy(stat, &virtio_net_stats, sizeof(*stat));
}
/*
* Initialize the driver and the virtual hardware.
*/
static int
virtio_net_init(unsigned int instance, ether_addr_t *addr)
{
int r;
if ((r = virtio_net_probe(instance)) != OK)
return r;
virtio_net_config(addr);
if (virtio_net_alloc_bufs() != OK) if (virtio_net_alloc_bufs() != OK)
panic("%s: Buffer allocation failed", name); panic("%s: Buffer allocation failed", name);
virtio_net_init_queues(); virtio_net_init_queues();
netdriver_announce(); /* Add packets to the receive queue. */
virtio_net_refill_rx_queue();
virtio_device_ready(net_dev);
virtio_irq_enable(net_dev);
return(OK); return(OK);
} }
/*
* The driver is terminating. Clean up.
*/
static void static void
sef_cb_signal_handler(int signo) virtio_net_stop(void)
{ {
if (signo != SIGTERM)
return;
dput(("Terminating")); dput(("Terminating"));
@ -675,6 +444,18 @@ sef_cb_signal_handler(int signo)
virtio_free_queues(net_dev); virtio_free_queues(net_dev);
virtio_free_device(net_dev); virtio_free_device(net_dev);
net_dev = NULL; net_dev = NULL;
}
exit(1);
/*
* The virtio-net device driver.
*/
int
main(int argc, char *argv[])
{
env_setargs(argc, argv);
netdriver_task(&virtio_net_table);
return 0;
} }

View File

@ -439,7 +439,7 @@ virtio_blk_device_intr(void)
thread_id_t *tid; thread_id_t *tid;
/* Multiple requests might have finished */ /* Multiple requests might have finished */
while (!virtio_from_queue(blk_dev, 0, (void**)&tid)) while (!virtio_from_queue(blk_dev, 0, (void**)&tid, NULL))
blockdriver_mt_wakeup(*tid); blockdriver_mt_wakeup(*tid);
} }

View File

@ -5,9 +5,63 @@
#include <minix/endpoint.h> #include <minix/endpoint.h>
#include <minix/ipc.h> #include <minix/ipc.h>
#include <minix/com.h>
/* Functions defined by netdriver.c: */ /* The flags that make up the requested receive mode. */
void netdriver_announce(void); #define NDEV_NOMODE DL_NOMODE /* targeted packets only */
int netdriver_receive(endpoint_t src, message *m_ptr, int *status_ptr); #define NDEV_PROMISC DL_PROMISC_REQ /* promiscuous mode */
#define NDEV_MULTI DL_MULTI_REQ /* receive multicast packets */
#define NDEV_BROAD DL_BROAD_REQ /* receive broadcast packets */
/*
* For now, only ethernet-type network drivers are supported, and thus, we use
* some ethernet-specific data structures.
*/
#include <net/gen/ether.h>
#include <net/gen/eth_io.h>
/* Opaque data structure for copying in and out actual packet data. */
struct netdriver_data;
/* Function call table for network drivers. */
struct netdriver {
int (*ndr_init)(unsigned int instance, ether_addr_t *addr);
void (*ndr_stop)(void);
void (*ndr_mode)(unsigned int mode);
ssize_t (*ndr_recv)(struct netdriver_data *data, size_t max);
int (*ndr_send)(struct netdriver_data *data, size_t size);
void (*ndr_stat)(eth_stat_t *stat);
void (*ndr_intr)(unsigned int mask);
void (*ndr_alarm)(clock_t stamp);
void (*ndr_other)(const message *m_ptr, int ipc_status);
};
/* Functions defined by libnetdriver. */
void netdriver_task(const struct netdriver *ndp);
void netdriver_announce(void); /* legacy; deprecated */
int netdriver_init(const struct netdriver *ndp);
void netdriver_process(const struct netdriver * __restrict ndp,
const message * __restrict m_ptr, int ipc_status);
void netdriver_terminate(void);
void netdriver_recv(void);
void netdriver_send(void);
void netdriver_copyin(struct netdriver_data * __restrict data, size_t off,
void * __restrict ptr, size_t size);
void netdriver_copyout(struct netdriver_data * __restrict data, size_t off,
const void * __restrict ptr, size_t size);
void netdriver_portinb(struct netdriver_data *data, size_t off, long port,
size_t size);
void netdriver_portoutb(struct netdriver_data *data, size_t off, long port,
size_t size);
void netdriver_portinw(struct netdriver_data *data, size_t off, long port,
size_t size);
void netdriver_portoutw(struct netdriver_data *data, size_t off, long port,
size_t size);
#define netdriver_receive sef_receive_status /* legacy; deprecated */
#endif /* _MINIX_NETDRIVER_H */ #endif /* _MINIX_NETDRIVER_H */

View File

@ -98,11 +98,12 @@ int virtio_to_queue(struct virtio_device *dev, int qidx,
struct vumap_phys *bufs, size_t num, void *data); struct vumap_phys *bufs, size_t num, void *data);
/* /*
* If the host used a chain of descriptors, return 0 and set data * If the host used a chain of descriptors, return 0, set data as was given to
* as was given to virtio_to_queue(). If the host has not processed * virtio_to_queue(), and if len is not NULL, set it to the resulting length.
* any element returns -1. * If the host has not processed any element, return -1.
*/ */
int virtio_from_queue(struct virtio_device *dev, int qidx, void **data); int virtio_from_queue(struct virtio_device *dev, int qidx, void **data,
size_t *len);
/* IRQ related functions */ /* IRQ related functions */
void virtio_irq_enable(struct virtio_device *dev); void virtio_irq_enable(struct virtio_device *dev);

View File

@ -6,6 +6,6 @@ CPPFLAGS+= -D_MINIX_SYSTEM
LIB= netdriver LIB= netdriver
SRCS= netdriver.c SRCS= netdriver.c portio.c
.include <bsd.lib.mk> .include <bsd.lib.mk>

View File

@ -1,82 +1,620 @@
/* This file contains device independent network device driver interface. /* The device-independent network driver framework. */
*
* Changes:
* Apr 01, 2010 Created (Cristiano Giuffrida)
*
* The file contains the following entry points:
*
* netdriver_announce: called by a network driver to announce it is up
* netdriver_receive: receive() interface for network drivers
*/
#include <minix/drivers.h> #include <minix/drivers.h>
#include <minix/endpoint.h> #include <minix/endpoint.h>
#include <minix/netdriver.h> #include <minix/netdriver.h>
#include <minix/ds.h> #include <minix/ds.h>
#include <assert.h>
static int conf_expected = TRUE; #include "netdriver.h"
/*===========================================================================* static const struct netdriver *netdriver_table = NULL;
* netdriver_announce *
*===========================================================================*/ static int running;
void netdriver_announce()
static int conf_expected;
static endpoint_t pending_endpt;
static struct netdriver_data pending_recv, pending_send;
static int defer_reply;
static unsigned int pending_flags;
static size_t pending_size;
static ether_addr_t hw_addr;
/*
* Announce we are up after a fresh start or restart.
*/
void
netdriver_announce(void)
{ {
/* Announce we are up after a fresh start or restart. */ const char *driver_prefix = "drv.net.";
int r; char label[DS_MAX_KEYLEN];
char key[DS_MAX_KEYLEN]; char key[DS_MAX_KEYLEN];
char label[DS_MAX_KEYLEN]; int r;
const char *driver_prefix = "drv.net.";
/* Publish a driver up event. */ /* Publish a driver up event. */
r = ds_retrieve_label_name(label, sef_self()); if ((r = ds_retrieve_label_name(label, sef_self())) != OK)
if (r != OK) { panic("netdriver: unable to get own label: %d", r);
panic("driver_announce: unable to get own label: %d\n", r);
}
snprintf(key, DS_MAX_KEYLEN, "%s%s", driver_prefix, label);
r = ds_publish_u32(key, DS_DRIVER_UP, DSF_OVERWRITE);
if (r != OK) {
panic("driver_announce: unable to publish driver up event: %d\n", r);
}
conf_expected = TRUE; snprintf(key, sizeof(key), "%s%s", driver_prefix, label);
if ((r = ds_publish_u32(key, DS_DRIVER_UP, DSF_OVERWRITE)) != OK)
panic("netdriver: unable to publish driver up event: %d", r);
} }
/*===========================================================================* /*
* netdriver_receive * * Prepare for copying. Given a flat offset, return the vector element index
*===========================================================================*/ * and an offset into that element. Panic if the request does not fall
int netdriver_receive(src, m_ptr, status_ptr) * entirely within the vector.
endpoint_t src; */
message *m_ptr; size_t
int *status_ptr; netdriver_prepare_copy(struct netdriver_data * data, size_t off, size_t size,
unsigned int * indexp)
{ {
/* receive() interface for drivers. */ unsigned int i;
int r;
while (TRUE) { assert(data->size > 0);
/* Wait for a request. */
r = sef_receive_status(src, m_ptr, status_ptr); /*
if (r != OK) { * In theory we could truncate when copying out, but this creates a
return r; * problem for port-based I/O, where the size of the transfer is
* typically specified in advance. We could do extra port-based I/O
* to discard the extra bytes, but the driver is better off doing such
* truncation itself. Thus, we disallow copying (in and out) beyond
* the given data vector altogether.
*/
if (off + size > data->size)
panic("netdriver: request to copy beyond data size");
/*
* Find the starting offset in the vector. If this turns out to be
* expensive, this can be adapted to store the last <element,offset>
* pair in the "data" structure (this is the reason it is not 'const').
*/
for (i = 0; i < data->count; i++) {
assert(data->iovec[i].iov_size > 0);
if (off >= data->iovec[i].iov_size)
off -= data->iovec[i].iov_size;
else
break;
} }
/* Let non-datalink requests through regardless. */ assert(i < data->count);
if (!IS_DL_RQ(m_ptr->m_type)) {
return r;
}
/* See if only DL_CONF is to be expected. */ *indexp = i;
if(conf_expected) { return off;
if(m_ptr->m_type == DL_CONF) {
conf_expected = FALSE;
}
else {
continue;
}
}
break;
}
return OK;
} }
/*
* Copy in or out packet data from/to a vector of grants.
*/
static void
netdriver_copy(struct netdriver_data * data, size_t off, vir_bytes addr,
size_t size, int copyin)
{
struct vscp_vec vec[SCPVEC_NR];
size_t chunk;
unsigned int i, v;
int r;
off = netdriver_prepare_copy(data, off, size, &i);
/* Generate a new vector with all the individual copies to make. */
for (v = 0; size > 0; v++) {
chunk = data->iovec[i].iov_size - off;
if (chunk > size)
chunk = size;
assert(chunk > 0);
/*
* We should be able to fit the entire I/O request in a single
* copy vector. If not, MINIX3 has been misconfigured.
*/
if (v >= SCPVEC_NR)
panic("netdriver: invalid vector size constant");
if (copyin) {
vec[v].v_from = data->endpt;
vec[v].v_to = SELF;
} else {
vec[v].v_from = SELF;
vec[v].v_to = data->endpt;
}
vec[v].v_gid = data->iovec[i].iov_grant;
vec[v].v_offset = off;
vec[v].v_addr = addr;
vec[v].v_bytes = chunk;
i++;
off = 0;
addr += chunk;
size -= chunk;
}
assert(v > 0 && v <= SCPVEC_NR);
/*
* If only one vector element was generated, use a direct copy. This
* saves the kernel from having to copy in the vector.
*/
if (v == 1) {
if (copyin)
r = sys_safecopyfrom(vec->v_from, vec->v_gid,
vec->v_offset, vec->v_addr, vec->v_bytes);
else
r = sys_safecopyto(vec->v_to, vec->v_gid,
vec->v_offset, vec->v_addr, vec->v_bytes);
} else
r = sys_vsafecopy(vec, v);
if (r != OK)
panic("netdriver: unable to copy data: %d", r);
}
/*
* Copy in packet data.
*/
void
netdriver_copyin(struct netdriver_data * __restrict data, size_t off,
void * __restrict ptr, size_t size)
{
netdriver_copy(data, off, (vir_bytes)ptr, size, TRUE /*copyin*/);
}
/*
* Copy out packet data.
*/
void
netdriver_copyout(struct netdriver_data * __restrict data, size_t off,
const void * __restrict ptr, size_t size)
{
netdriver_copy(data, off, (vir_bytes)ptr, size, FALSE /*copyin*/);
}
/*
* Send a reply to a request.
*/
static void
send_reply(endpoint_t endpt, message * m_ptr)
{
int r;
if ((r = ipc_send(endpt, m_ptr)) != OK)
panic("netdriver: unable to send to %d: %d", endpt, r);
}
/*
* Defer sending any replies to task requests until the next call to
* check_replies(). The purpose of this is aggregation of task replies to both
* send and receive requests into a single reply message, which saves on
* messages, in particular when processing interrupts.
*/
static void
defer_replies(void)
{
assert(netdriver_table != NULL);
assert(defer_reply == FALSE);
defer_reply = TRUE;
}
/*
* Check if we have to reply to earlier task (I/O) requests, and if so, send
* the reply. If deferred is FALSE and the call to this function was preceded
* by a call to defer_replies(), do not send a reply yet. If always_send is
* TRUE, send a reply even if no tasks have completed yet.
*/
static void
check_replies(int deferred, int always_send)
{
message m_reply;
if (defer_reply && !deferred)
return;
defer_reply = FALSE;
if (pending_flags == 0 && !always_send)
return;
assert(pending_endpt != NONE);
memset(&m_reply, 0, sizeof(m_reply));
m_reply.m_type = DL_TASK_REPLY;
m_reply.m_netdrv_net_dl_task.flags = pending_flags;
m_reply.m_netdrv_net_dl_task.count = pending_size;
send_reply(pending_endpt, &m_reply);
pending_flags = 0;
pending_size = 0;
}
/*
* Resume receiving packets. In particular, if a receive request was pending,
* call the driver's receive function. If the call is successful, schedule
* sending a reply to the requesting party.
*/
void
netdriver_recv(void)
{
ssize_t r;
if (pending_recv.size == 0)
return;
assert(netdriver_table != NULL);
/*
* For convenience of driver writers: if the receive function returns
* zero, simply call it again, to simplify discarding invalid packets.
*/
do {
r = netdriver_table->ndr_recv(&pending_recv,
pending_recv.size);
/*
* The default policy is: drop undersized packets, panic on
* oversized packets. The driver may implement any other
* policy (e.g., pad small packets, drop or truncate large
* packets), but it should at least test against the given
* 'max' value. The reason that truncation should be
* implemented in the driver rather than here, is explained in
* an earlier comment about truncating copy operations.
*/
if (r >= 0 && r < ETH_MIN_PACK_SIZE)
r = 0;
else if (r > (ssize_t)pending_recv.size)
panic("netdriver: oversized packet returned: %zd", r);
} while (r == 0);
if (r == SUSPEND)
return;
if (r < 0)
panic("netdriver: driver reported receive failure: %d", r);
assert(r >= ETH_MIN_PACK_SIZE && (size_t)r <= pending_recv.size);
pending_flags |= DL_PACK_RECV;
pending_size = r;
pending_recv.size = 0;
check_replies(FALSE /*deferred*/, FALSE /*always_send*/);
}
/*
* Resume sending packets. In particular, if a send request was pending, call
* the driver's send function. If the call is successful, schedule sending a
* reply to the requesting party. This function relies on being called
* between init_pending() and check_pending().
*/
void
netdriver_send(void)
{
int r;
if (pending_send.size == 0)
return;
assert(netdriver_table != NULL);
r = netdriver_table->ndr_send(&pending_send, pending_send.size);
if (r == SUSPEND)
return;
if (r < 0)
panic("netdriver: driver reported send failure: %d", r);
pending_flags |= DL_PACK_SEND;
pending_send.size = 0;
check_replies(FALSE /*deferred*/, FALSE /*always_send*/);
}
/*
* Process a request to receive or send a packet.
*/
static void
do_readwrite(const struct netdriver * __restrict ndp, endpoint_t endpt,
cp_grant_id_t grant, unsigned int count, int write)
{
struct netdriver_data *data;
unsigned int i;
int r;
/* Copy in the I/O vector. */
data = (write) ? &pending_send : &pending_recv;
if (data->size != 0)
panic("netdriver: multiple concurrent requests");
if (count == 0 || count > NR_IOREQS)
panic("netdriver: bad I/O vector count: %u", count);
data->endpt = endpt;
data->count = count;
if ((r = sys_safecopyfrom(endpt, grant, 0, (vir_bytes)data->iovec,
sizeof(data->iovec[0]) * count)) != OK)
panic("netdriver: unable to copy in I/O vector: %d", r);
for (i = 0; i < count; i++)
data->size += data->iovec[i].iov_size;
if (data->size < ETH_MIN_PACK_SIZE ||
(!write && data->size < ETH_MAX_PACK_SIZE_TAGGED))
panic("netdriver: invalid I/O vector size: %zu\n", data->size);
/* Save the endpoint to which we should reply. */
if (pending_endpt != NONE && pending_endpt != endpt)
panic("netdriver: multiple request sources");
pending_endpt = endpt;
/* Resume sending or receiving. */
defer_replies();
if (write)
netdriver_send();
else
netdriver_recv();
/* Always send a reply in this case, even if no flags are set. */
check_replies(TRUE /*deferred*/, TRUE /*always_send*/);
}
/*
* Process a request to configure the driver, by setting its mode and obtaining
* its ethernet hardware address. We already have the latter as a result of
* calling the ndr_init callback function.
*/
static void
do_conf(const struct netdriver * __restrict ndp,
const message * __restrict m_ptr)
{
message m_reply;
if (ndp->ndr_mode != NULL)
ndp->ndr_mode(m_ptr->m_net_netdrv_dl_conf.mode);
memset(&m_reply, 0, sizeof(m_reply));
m_reply.m_type = DL_CONF_REPLY;
m_reply.m_netdrv_net_dl_conf.stat = OK; /* legacy */
memcpy(&m_reply.m_netdrv_net_dl_conf.hw_addr, &hw_addr,
sizeof(m_reply.m_netdrv_net_dl_conf.hw_addr));
send_reply(m_ptr->m_source, &m_reply);
}
/*
* Process a request to obtain statistics from the driver.
*/
static void
do_getstat(const struct netdriver * __restrict ndp,
const message * __restrict m_ptr)
{
message m_reply;
eth_stat_t stat;
int r;
memset(&stat, 0, sizeof(stat));
if (ndp->ndr_stat != NULL)
ndp->ndr_stat(&stat);
if ((r = sys_safecopyto(m_ptr->m_source,
m_ptr->m_net_netdrv_dl_getstat_s.grant, 0, (vir_bytes)&stat,
sizeof(stat))) != OK)
panic("netdriver: unable to copy out statistics: %d", r);
memset(&m_reply, 0, sizeof(m_reply));
m_reply.m_type = DL_STAT_REPLY;
send_reply(m_ptr->m_source, &m_reply);
}
/*
* Process an incoming message, and send a reply.
*/
void
netdriver_process(const struct netdriver * __restrict ndp,
const message * __restrict m_ptr, int ipc_status)
{
netdriver_table = ndp;
/* Check for notifications first. */
if (is_ipc_notify(ipc_status)) {
defer_replies();
switch (_ENDPOINT_P(m_ptr->m_source)) {
case HARDWARE:
if (ndp->ndr_intr != NULL)
ndp->ndr_intr(m_ptr->m_notify.interrupts);
break;
case CLOCK:
if (ndp->ndr_alarm != NULL)
ndp->ndr_alarm(m_ptr->m_notify.timestamp);
break;
default:
if (ndp->ndr_other != NULL)
ndp->ndr_other(m_ptr, ipc_status);
}
/*
* Any of the above calls may end up invoking netdriver_send()
* and/or netdriver_recv(), which may in turn have deferred
* sending a reply to an earlier request. See if we have to
* send the reply now.
*/
check_replies(TRUE /*deferred*/, FALSE /*always_send*/);
}
/*
* Discard datalink requests preceding a first DL_CONF request, so that
* after a driver restart, any in-flight request is discarded. This is
* a rather blunt approach and must be revised if the protocol is ever
* made less inefficient (i.e. not strictly serialized). Note that for
* correct driver operation it is important that non-datalink requests,
* interrupts in particular, do not go through this check.
*/
if (IS_DL_RQ(m_ptr->m_type) && conf_expected) {
if (m_ptr->m_type != DL_CONF)
return; /* do not send a reply */
conf_expected = FALSE;
}
switch (m_ptr->m_type) {
case DL_CONF:
do_conf(ndp, m_ptr);
break;
case DL_GETSTAT_S:
do_getstat(ndp, m_ptr);
break;
case DL_READV_S:
do_readwrite(ndp, m_ptr->m_source,
m_ptr->m_net_netdrv_dl_readv_s.grant,
m_ptr->m_net_netdrv_dl_readv_s.count, FALSE /*write*/);
break;
case DL_WRITEV_S:
do_readwrite(ndp, m_ptr->m_source,
m_ptr->m_net_netdrv_dl_writev_s.grant,
m_ptr->m_net_netdrv_dl_writev_s.count, TRUE /*write*/);
break;
default:
defer_replies();
if (ndp->ndr_other != NULL)
ndp->ndr_other(m_ptr, ipc_status);
/* As above: see if we have to send a reply now. */
check_replies(TRUE /*deferred*/, FALSE /*always_send*/);
}
}
/*
* Perform initialization. Return OK or an error code.
*/
int
netdriver_init(const struct netdriver * ndp)
{
unsigned int instance;
long v;
int r;
/* Initialize global variables. */
pending_recv.size = 0;
pending_send.size = 0;
pending_endpt = NONE;
defer_reply = FALSE;
pending_flags = 0;
pending_size = 0;
conf_expected = TRUE;
/* Get the card instance number. */
v = 0;
(void)env_parse("instance", "d", 0, &v, 0, 255);
instance = (unsigned int)v;
/* Call the initialization routine. */
memset(&hw_addr, 0, sizeof(hw_addr));
if (ndp->ndr_init != NULL &&
(r = ndp->ndr_init(instance, &hw_addr)) != OK)
return r;
/* Announce we are up! */
netdriver_announce();
return OK;
}
/*
* SEF initialization function.
*/
static int
do_init(int __unused type, sef_init_info_t * __unused info)
{
const struct netdriver *ndp;
ndp = netdriver_table;
assert(ndp != NULL);
return netdriver_init(ndp);
}
/*
* Break out of the main loop after finishing the current request.
*/
void
netdriver_terminate(void)
{
if (netdriver_table != NULL && netdriver_table->ndr_stop != NULL)
netdriver_table->ndr_stop();
running = FALSE;
sef_cancel();
}
/*
* The process has received a signal. See if we have to terminate.
*/
static void
got_signal(int sig)
{
if (sig != SIGTERM)
return;
netdriver_terminate();
}
/*
* Main program of any network driver.
*/
void
netdriver_task(const struct netdriver * ndp)
{
message mess;
int r, ipc_status;
/* Perform SEF initialization. */
sef_setcb_init_fresh(do_init);
sef_setcb_init_restart(do_init); /* TODO: revisit this */
sef_setcb_signal_handler(got_signal);
netdriver_table = ndp;
sef_startup();
netdriver_table = NULL;
/* The main message loop. */
running = TRUE;
while (running) {
if ((r = sef_receive_status(ANY, &mess, &ipc_status)) != OK) {
if (r == EINTR)
continue; /* sef_cancel() was called */
panic("netdriver: sef_receive_status failed: %d", r);
}
netdriver_process(ndp, &mess, ipc_status);
}
}

View File

@ -0,0 +1,15 @@
#ifndef _MINIX_LIB_NETDRIVER_NETDRIVER_H
#define _MINIX_LIB_NETDRIVER_NETDRIVER_H
/* Data (I/O) structure. */
struct netdriver_data {
endpoint_t endpt;
size_t size;
unsigned int count;
iovec_s_t iovec[NR_IOREQS];
};
size_t netdriver_prepare_copy(struct netdriver_data *data, size_t offp,
size_t size, unsigned int * indexp);
#endif /* !_MINIX_LIB_NETDRIVER_NETDRIVER_H */

View File

@ -0,0 +1,193 @@
/*
* Port-based I/O routines. These are in a separate module because most
* drivers will not use them, and system services are statically linked.
*/
#include <minix/drivers.h>
#include <minix/netdriver.h>
#include <assert.h>
#include "netdriver.h"
/*
* Port-based I/O byte sequence copy routine.
*/
static void
netdriver_portb(struct netdriver_data * data, size_t off, long port,
size_t size, int portin)
{
size_t chunk;
unsigned int i;
int r, req;
off = netdriver_prepare_copy(data, off, size, &i);
req = portin ? DIO_SAFE_INPUT_BYTE : DIO_SAFE_OUTPUT_BYTE;
while (size > 0) {
chunk = data->iovec[i].iov_size - off;
if (chunk > size)
chunk = size;
assert(chunk > 0);
if ((r = sys_sdevio(req, port, data->endpt,
(void *)data->iovec[i].iov_grant, chunk, off)) != OK)
panic("netdriver: port I/O failed: %d", r);
i++;
off = 0;
size -= chunk;
}
}
/*
* Transfer bytes from hardware to a destination buffer using port-based I/O.
*/
void
netdriver_portinb(struct netdriver_data * data, size_t off, long port,
size_t size)
{
return netdriver_portb(data, off, port, size, TRUE /*portin*/);
}
/*
* Transfer bytes from a source buffer to hardware using port-based I/O.
*/
void
netdriver_portoutb(struct netdriver_data * data, size_t off, long port,
size_t size)
{
return netdriver_portb(data, off, port, size, FALSE /*portin*/);
}
/*
* Transfer words from hardware to a destination buffer using port-based I/O.
*/
void
netdriver_portinw(struct netdriver_data * data, size_t off, long port,
size_t size)
{
uint8_t buf[2];
uint32_t value;
size_t chunk;
unsigned int i;
int r, odd_byte;
off = netdriver_prepare_copy(data, off, size, &i);
odd_byte = 0;
while (size > 0) {
chunk = data->iovec[i].iov_size - off;
if (chunk > size)
chunk = size;
assert(chunk > 0);
if (odd_byte) {
if ((r = sys_safecopyto(data->endpt,
data->iovec[i].iov_grant, off, (vir_bytes)&buf[1],
1)) != OK)
panic("netdriver: unable to copy data: %d", r);
off++;
size--;
chunk--;
}
odd_byte = chunk & 1;
chunk -= odd_byte;
if (chunk > 0) {
if ((r = sys_safe_insw(port, data->endpt,
data->iovec[i].iov_grant, off, chunk)) != OK)
panic("netdriver: port input failed: %d", r);
off += chunk;
size -= chunk;
}
if (odd_byte) {
if ((r = sys_inw(port, &value)) != OK)
panic("netdriver: port input failed: %d", r);
*(uint16_t *)buf = (uint16_t)value;
if ((r = sys_safecopyto(data->endpt,
data->iovec[i].iov_grant, off, (vir_bytes)&buf[0],
1)) != OK)
panic("netdriver: unable to copy data: %d", r);
size--;
}
i++;
off = 0;
}
}
/*
* Transfer words from a source buffer to hardware using port-based I/O.
*/
void
netdriver_portoutw(struct netdriver_data * data, size_t off, long port,
size_t size)
{
uint8_t buf[2];
size_t chunk;
unsigned int i;
int r, odd_byte;
off = netdriver_prepare_copy(data, off, size, &i);
odd_byte = 0;
while (size > 0) {
chunk = data->iovec[i].iov_size - off;
if (chunk > size)
chunk = size;
assert(chunk > 0);
if (odd_byte) {
if ((r = sys_safecopyfrom(data->endpt,
data->iovec[i].iov_grant, off, (vir_bytes)&buf[1],
1)) != OK)
panic("netdriver: unable to copy data: %d", r);
if ((r = sys_outw(port, *(uint16_t *)buf)) != OK)
panic("netdriver: port output failed: %d", r);
off++;
size--;
chunk--;
}
odd_byte = chunk & 1;
chunk -= odd_byte;
if (chunk > 0) {
if ((r = sys_safe_outsw(port, data->endpt,
data->iovec[i].iov_grant, off, chunk)) != OK)
panic("netdriver: port output failed: %d", r);
off += chunk;
size -= chunk;
}
if (odd_byte) {
if ((r = sys_safecopyfrom(data->endpt,
data->iovec[i].iov_grant, off, (vir_bytes)&buf[0],
1)) != OK)
panic("netdriver: unable to copy data: %d", r);
size--;
}
i++;
off = 0;
}
if (odd_byte) {
buf[1] = 0;
if ((r = sys_outw(port, *(uint16_t *)buf)) != OK)
panic("netdriver: port output failed: %d", r);
}
}

View File

@ -639,7 +639,8 @@ virtio_to_queue(struct virtio_device *dev, int qidx, struct vumap_phys *bufs,
} }
int int
virtio_from_queue(struct virtio_device *dev, int qidx, void **data) virtio_from_queue(struct virtio_device *dev, int qidx, void **data,
size_t *len)
{ {
struct virtio_queue *q; struct virtio_queue *q;
struct vring *vring; struct vring *vring;
@ -718,6 +719,9 @@ virtio_from_queue(struct virtio_device *dev, int qidx, void **data)
*data = q->data[uel->id]; *data = q->data[uel->id];
q->data[uel->id] = NULL; q->data[uel->id] = NULL;
if (len != NULL)
*len = uel->len;
return 0; return 0;
} }

View File

@ -6,6 +6,8 @@ SUBDIR+= inet
. if ${MKLWIP} == "yes" . if ${MKLWIP} == "yes"
SUBDIR+= lwip SUBDIR+= lwip
. endif # ${MKLWIP} == "yes" . endif # ${MKLWIP} == "yes"
SUBDIR+= uds
.endif # ${MKIMAGEONLY} == "no" .endif # ${MKIMAGEONLY} == "no"
.include <bsd.subdir.mk> .include <bsd.subdir.mk>