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:
parent
7f59afadd5
commit
3570bf6aa8
|
|
@ -255,7 +255,10 @@ service dp8390
|
|||
SDEVIO # 22
|
||||
;
|
||||
pci device 10ec:8029;
|
||||
uid 0;
|
||||
io
|
||||
300:20
|
||||
;
|
||||
irq 9;
|
||||
};
|
||||
|
||||
service dpeth
|
||||
|
|
|
|||
|
|
@ -184,7 +184,7 @@ start|autoboot)
|
|||
for label in $(get_eth_labels); do
|
||||
driver=$(echo $label | sed 's/\(.*\)_.*/\1/')
|
||||
instance=$(echo $label | sed 's/.*_//')
|
||||
eval arg=\$${label}_arg
|
||||
eval arg=\$${driver}_arg
|
||||
if [ ! -z "$arg" ]; then arg=" $arg"; fi
|
||||
arg="-args \"instance=$instance$arg\""
|
||||
eval up $driver -label $label $arg -period 5HZ
|
||||
|
|
|
|||
|
|
@ -109,7 +109,7 @@ cards()
|
|||
card 0 "No Ethernet card (no networking)"
|
||||
card 1 "3Com 501 or 3Com 509 based card"
|
||||
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)"
|
||||
n=$first_pcicard
|
||||
for pcicard in $pci_list
|
||||
|
|
@ -197,10 +197,11 @@ drv_params()
|
|||
test "$v" = 1 && echo "Note: After installing, edit $LOCALRC to the right configuration."
|
||||
;;
|
||||
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 "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; ;;
|
||||
$first_after_pci) driver="psip0"; ;;
|
||||
|
|
|
|||
|
|
@ -18,6 +18,4 @@ SUBDIR+= virtio_net
|
|||
SUBDIR+= lan8710a
|
||||
.endif # ${MACHINE_ARCH} == "earm"
|
||||
|
||||
SUBDIR+= uds
|
||||
|
||||
.include <bsd.subdir.mk>
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -179,5 +179,3 @@
|
|||
#define ATL2_TXS_ABORTCOL 0x04000000 /* collision abort */
|
||||
#define ATL2_TXS_UNDERRUN 0x08000000 /* buffer underrun */
|
||||
#define ATL2_TXS_UPDATE 0x80000000 /* updated by device */
|
||||
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -11,37 +11,21 @@ Created: 09/01/2009 Nicolas Tittley (first.last @ gmail DOT com)
|
|||
|
||||
#include <sys/null.h>
|
||||
|
||||
#define DE_FKEY 7 /* Shift+ this value will dump info on console */
|
||||
|
||||
#define NOT(x) (~(x))
|
||||
|
||||
#if debug == 1
|
||||
# define DEBUG(statm) statm
|
||||
#else
|
||||
# define DEBUG(statm)
|
||||
#endif
|
||||
|
||||
|
||||
#define SA_ADDR_LEN sizeof(ether_addr_t)
|
||||
|
||||
#define DE_NB_SEND_DESCR 32
|
||||
#define DE_SEND_BUF_SIZE (ETH_MAX_PACK_SIZE+2)
|
||||
#define DE_NB_RECV_DESCR 32
|
||||
#define DE_RECV_BUF_SIZE (ETH_MAX_PACK_SIZE+2)
|
||||
#define IOVEC_NR 16
|
||||
|
||||
#define DE_MIN_BASE_ADDR 0x0400
|
||||
#define DE_SROM_EA_OFFSET 20
|
||||
#define DE_SETUP_FRAME_SIZE 192
|
||||
|
||||
|
||||
typedef struct iovec_dat_s {
|
||||
iovec_s_t iod_iovec[IOVEC_NR];
|
||||
int iod_iovec_s;
|
||||
endpoint_t iod_proc_nr;
|
||||
cp_grant_id_t iod_grant;
|
||||
vir_bytes iod_iovec_offset;
|
||||
} iovec_dat_s_t;
|
||||
|
||||
typedef struct de_descr {
|
||||
u32_t des[4];
|
||||
} de_descr_t;
|
||||
|
|
@ -53,9 +37,6 @@ typedef struct de_local_descr {
|
|||
} de_loc_descr_t;
|
||||
|
||||
typedef struct dpeth {
|
||||
|
||||
message rx_return_msg; /* Holds VREAD message until int */
|
||||
message tx_return_msg; /* Holds VWRITE message until int */
|
||||
char de_name[32]; /* Name of this interface */
|
||||
port_t de_base_port; /* Base port, for multiple card instance */
|
||||
int de_irq; /* IRQ line number */
|
||||
|
|
@ -63,10 +44,7 @@ typedef struct dpeth {
|
|||
|
||||
int de_type; /* What kind of hardware */
|
||||
|
||||
ether_addr_t de_address; /* Ethernet Address */
|
||||
eth_stat_t de_stat; /* Stats */
|
||||
unsigned long bytes_tx; /* Number of bytes sent */
|
||||
unsigned long bytes_rx; /* Number of bytes recv */
|
||||
|
||||
/* Space reservation. We will allocate all structures later in the code.
|
||||
here we just make sure we have the space we need at compile time */
|
||||
|
|
@ -81,42 +59,11 @@ typedef struct dpeth {
|
|||
#define DESCR_RECV 0
|
||||
#define DESCR_TRAN 1
|
||||
|
||||
int de_flags; /* Send/Receive mode (Configuration) */
|
||||
|
||||
#define DEF_EMPTY 0x0000
|
||||
#define DEF_READING 0x0001
|
||||
#define DEF_RECV_BUSY 0x0002
|
||||
#define DEF_ACK_RECV 0x0004
|
||||
#define DEF_SENDING 0x0010
|
||||
#define DEF_XMIT_BUSY 0x0020
|
||||
#define DEF_ACK_SEND 0x0040
|
||||
#define DEF_PROMISC 0x0100
|
||||
#define DEF_MULTI 0x0200
|
||||
#define DEF_BROAD 0x0400
|
||||
#define DEF_ENABLED 0x2000
|
||||
#define DEF_STOPPED 0x4000
|
||||
|
||||
int de_mode; /* Status of the Interface */
|
||||
|
||||
#define DEM_DISABLED 0x0000
|
||||
#define DEM_SINK 0x0001
|
||||
#define DEM_ENABLED 0x0002
|
||||
|
||||
|
||||
/* Serial ROM */
|
||||
#define SROM_BITWIDTH 6
|
||||
|
||||
u8_t srom[((1<<SROM_BITWIDTH)-1)*2]; /* Space to read in
|
||||
all the configuration ROM */
|
||||
|
||||
|
||||
/* Temporary storage for RECV/SEND requests */
|
||||
iovec_dat_s_t de_read_iovec;
|
||||
iovec_dat_s_t de_write_iovec;
|
||||
vir_bytes de_read_s;
|
||||
vir_bytes de_send_s;
|
||||
endpoint_t de_client;
|
||||
|
||||
} dpeth_t;
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
*/
|
||||
|
||||
#include <minix/drivers.h>
|
||||
#include <minix/netdriver.h>
|
||||
|
||||
#include <net/gen/ether.h>
|
||||
#include <net/gen/eth_io.h>
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
PROG= dp8390
|
||||
SRCS= 3c503.c dp8390.c ne2000.c rtl8029.c wdeth.c
|
||||
|
||||
DPADD+= ${LIBNETDRIVER} ${LIBSYS} ${LIBTIMERS}
|
||||
LDADD+= -lnetdriver -lsys -ltimers
|
||||
DPADD+= ${LIBNETDRIVER} ${LIBSYS}
|
||||
LDADD+= -lnetdriver -lsys
|
||||
|
||||
.include <minix.service.mk>
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -173,45 +173,19 @@ typedef struct dp_rcvhdr
|
|||
struct dpeth;
|
||||
struct iovec_dat;
|
||||
struct iovec_dat_s;
|
||||
typedef void(*dp_initf_t) (struct dpeth *dep);
|
||||
typedef void(*dp_stopf_t) (struct dpeth *dep);
|
||||
typedef void(*dp_user2nicf_t) (struct dpeth *dep, struct iovec_dat
|
||||
*iovp, vir_bytes offset, int nic_addr, vir_bytes count);
|
||||
typedef void(*dp_user2nicf_s_t) (struct dpeth *dep, struct iovec_dat_s
|
||||
*iovp, vir_bytes offset, int nic_addr, vir_bytes count);
|
||||
typedef void(*dp_nic2userf_t) (struct dpeth *dep, int nic_addr, struct
|
||||
iovec_dat *iovp, vir_bytes offset, vir_bytes count);
|
||||
typedef void(*dp_nic2userf_s_t) (struct dpeth *dep, int nic_addr, struct
|
||||
iovec_dat_s *iovp, vir_bytes offset, vir_bytes count);
|
||||
#if 0
|
||||
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
|
||||
typedef void (*dp_initf_t)(struct dpeth *dep);
|
||||
typedef void (*dp_stopf_t)(struct dpeth *dep);
|
||||
typedef void (*dp_user2nicf_s_t)(struct dpeth *dep,
|
||||
struct netdriver_data *data, int nic_addr, size_t offset,
|
||||
size_t count);
|
||||
typedef void (*dp_nic2userf_s_t)(struct dpeth *dep,
|
||||
struct netdriver_data *data, int nic_addr, size_t offset,
|
||||
size_t count);
|
||||
typedef void (*dp_getblock_t)(struct dpeth *dep, int page, size_t
|
||||
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 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_PAGES 6 /* 6 * DP_PAGESIZE >= 1514 bytes */
|
||||
|
||||
|
|
@ -250,10 +224,8 @@ typedef struct dpeth
|
|||
int de_startpage;
|
||||
int de_stoppage;
|
||||
|
||||
#if ENABLE_PCI
|
||||
/* PCI config */
|
||||
char de_pci; /* TRUE iff PCI device */
|
||||
#endif
|
||||
|
||||
/* Do it yourself send queue */
|
||||
struct sendq
|
||||
|
|
@ -268,14 +240,7 @@ typedef struct dpeth
|
|||
|
||||
/* Fields for internal use by the dp8390 driver. */
|
||||
int de_flags;
|
||||
int de_mode;
|
||||
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_nic2userf_s_t de_nic2userf_s;
|
||||
dp_getblock_t de_getblockf;
|
||||
|
|
@ -283,24 +248,10 @@ typedef struct dpeth
|
|||
|
||||
#define DEI_DEFAULT 0x8000
|
||||
|
||||
#define DEF_EMPTY 0x000
|
||||
#define DEF_PACK_SEND 0x001
|
||||
#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 DEF_EMPTY 0x00
|
||||
#define DEF_STOPPED 0x01
|
||||
|
||||
#define DEM_DISABLED 0x0
|
||||
#define DEM_SINK 0x1
|
||||
#define DEM_ENABLED 0x2
|
||||
|
||||
#if !__minix_vmd
|
||||
#define debug 0 /* Standard Minix lacks debug variable */
|
||||
#endif
|
||||
#define debug 0
|
||||
|
||||
/*
|
||||
* $PchId: dp8390.h,v 1.10 2005/02/10 17:26:06 philip Exp $
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ local.h
|
|||
#define ENABLE_WDETH 1
|
||||
#define ENABLE_NE2000 1
|
||||
#define ENABLE_3C503 1
|
||||
#define ENABLE_PCI 1
|
||||
|
||||
struct dpeth;
|
||||
|
||||
|
|
|
|||
|
|
@ -8,12 +8,10 @@ Created: March 15, 1994 by Philip Homburg <philip@f-mnx.phicoh.com>
|
|||
*/
|
||||
|
||||
#include <minix/drivers.h>
|
||||
#include <minix/netdriver.h>
|
||||
|
||||
#include <net/gen/ether.h>
|
||||
#include <net/gen/eth_io.h>
|
||||
#if __minix_vmd
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "local.h"
|
||||
#include "dp8390.h"
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ Created: April 2000 by Philip Homburg <philip@f-mnx.phicoh.com>
|
|||
*/
|
||||
|
||||
#include <minix/drivers.h>
|
||||
#include <minix/netdriver.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
|
|
@ -20,8 +21,6 @@ Created: April 2000 by Philip Homburg <philip@f-mnx.phicoh.com>
|
|||
#include "dp8390.h"
|
||||
#include "rtl8029.h"
|
||||
|
||||
#if ENABLE_PCI
|
||||
|
||||
static void rtl_init(struct dpeth *dep);
|
||||
#if 0
|
||||
static u16_t get_ee_word(dpeth_t *dep, int a);
|
||||
|
|
@ -312,8 +311,6 @@ dpeth_t *dep;
|
|||
}
|
||||
#endif
|
||||
|
||||
#endif /* ENABLE_PCI */
|
||||
|
||||
/*
|
||||
* $PchId: rtl8029.c,v 1.7 2004/08/03 12:16:58 philip Exp $
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ Created: March 14, 1994 by Philip Homburg
|
|||
*/
|
||||
|
||||
#include <minix/drivers.h>
|
||||
#include <minix/netdriver.h>
|
||||
|
||||
#include <net/gen/ether.h>
|
||||
#include <net/gen/eth_io.h>
|
||||
|
|
@ -70,9 +71,6 @@ dpeth_t *dep;
|
|||
int we_type;
|
||||
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[1] = inb_we(dep, EPL_EA1);
|
||||
dep->de_address.ea_addr[2] = inb_we(dep, EPL_EA2);
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
*/
|
||||
|
||||
#include <minix/drivers.h>
|
||||
#include <minix/com.h>
|
||||
#include <minix/netdriver.h>
|
||||
#include <net/gen/ether.h>
|
||||
#include <net/gen/eth_io.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;
|
||||
|
||||
/*
|
||||
** Name: void el1_getstats(dpeth_t *dep)
|
||||
** Name: el1_getstats
|
||||
** Function: Reads statistics counters from board.
|
||||
**/
|
||||
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.
|
||||
*/
|
||||
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)
|
||||
outb_el1(dep, ix, StationAddress[ix]);
|
||||
|
||||
lock();
|
||||
/* Enable DMA/Interrupt, gain control of Buffer */
|
||||
outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_SYS);
|
||||
/* Clear RX packet area */
|
||||
|
|
@ -60,22 +59,19 @@ static void el1_reset(dpeth_t * dep)
|
|||
inb_el1(dep, EL1_RECV);
|
||||
inb_el1(dep, EL1_XMIT);
|
||||
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).
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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);
|
||||
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
|
||||
** 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;
|
||||
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 */
|
||||
lock();
|
||||
if (dep->de_recvq_tail == dep->de_recvq_head)
|
||||
dep->de_recvq_head = dep->de_recvq_tail = NULL;
|
||||
else
|
||||
dep->de_recvq_head = rxptr->next;
|
||||
unlock();
|
||||
/* Remove buffer from queue and free buffer */
|
||||
if (dep->de_recvq_tail == dep->de_recvq_head)
|
||||
dep->de_recvq_head = dep->de_recvq_tail = NULL;
|
||||
else
|
||||
dep->de_recvq_head = rxptr->next;
|
||||
|
||||
/* Copy buffer to user area */
|
||||
mem2user(dep, rxptr);
|
||||
/* Copy buffer to user area */
|
||||
size = MIN(rxptr->size, max);
|
||||
|
||||
/* Reply information */
|
||||
dep->de_read_s = rxptr->size;
|
||||
dep->de_flags |= DEF_ACK_RECV;
|
||||
dep->de_flags &= NOT(DEF_READING);
|
||||
netdriver_copyout(data, 0, rxptr->buffer, size);
|
||||
|
||||
/* Return buffer to the idle pool */
|
||||
free_buff(dep, rxptr);
|
||||
}
|
||||
return;
|
||||
/* Return buffer to the idle pool */
|
||||
free_buff(dep, rxptr);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
/*
|
||||
** Name: void el1_send(dpeth_t *dep, int from_int, int pktsize)
|
||||
** Function: Send function. Called from main to transit a packet or
|
||||
** from interrupt handler when a new packet was queued.
|
||||
** Name: el1_send
|
||||
** Function: Send function.
|
||||
*/
|
||||
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;
|
||||
clock_t now;
|
||||
|
||||
if (from_int == FALSE) {
|
||||
|
||||
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 ");
|
||||
if (dep->de_flags & DEF_XMIT_BUSY) {
|
||||
getticks(&now);
|
||||
if ((now - dep->de_xmit_start) > 4) {
|
||||
/* Transmitter timed out */
|
||||
DEBUG(printf("3c501: transmitter timed out ... \n"));
|
||||
dep->de_stat.ets_sendErr += 1;
|
||||
dep->de_flags &= NOT(DEF_XMIT_BUSY);
|
||||
el1_reset(dep);
|
||||
}
|
||||
|
||||
/* 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);
|
||||
/* Try sending anyway. */
|
||||
} else
|
||||
return SUSPEND;
|
||||
}
|
||||
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.
|
||||
*/
|
||||
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_SYS);
|
||||
sys_irqdisable(&dep->de_hook); /* Disable interrupt */
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
** Name: void el1_interrupt(dpeth_t *dep)
|
||||
** Name: el1_interrupt
|
||||
** Function: Interrupt handler. Acknwledges transmit interrupts
|
||||
** 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));
|
||||
el1_reset(dep);
|
||||
|
||||
} else {
|
||||
/** if (inw_el1(dep, EL1_XMITPTR) == EL1_BFRSIZ) **/
|
||||
/* Packet transmitted successfully */
|
||||
|
|
@ -272,12 +234,9 @@ static void el1_interrupt(dpeth_t * dep)
|
|||
dep->bytes_Tx += (long) (TxBuff->size);
|
||||
free_buff(dep, TxBuff);
|
||||
dep->de_flags &= NOT(DEF_XMIT_BUSY);
|
||||
if ((dep->de_flags & DEF_SENDING) && dep->de_xmitq_head) {
|
||||
/* Pending transmit request available in queue */
|
||||
el1_send(dep, TRUE, 0);
|
||||
if (dep->de_flags & (DEF_XMIT_BUSY | DEF_ACK_SEND))
|
||||
return;
|
||||
}
|
||||
netdriver_send();
|
||||
if (dep->de_flags & DEF_XMIT_BUSY)
|
||||
return;
|
||||
}
|
||||
|
||||
} 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 */
|
||||
outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_SYS);
|
||||
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->size = pktsize;
|
||||
dep->de_stat.ets_packetR += 1;
|
||||
dep->bytes_Rx += (long) pktsize;
|
||||
lock(); /* Queue packet to receive queue */
|
||||
/* Queue packet to receive queue */
|
||||
if (dep->de_recvq_head == NULL)
|
||||
dep->de_recvq_head = rxptr;
|
||||
else
|
||||
dep->de_recvq_tail->next = rxptr;
|
||||
dep->de_recvq_tail = rxptr;
|
||||
unlock();
|
||||
|
||||
/* Reply to pending Receive requests, if any */
|
||||
el1_recv(dep, TRUE, 0);
|
||||
netdriver_recv();
|
||||
}
|
||||
} else { /* Nasty condition, should never happen */
|
||||
DEBUG(
|
||||
|
|
@ -337,11 +295,10 @@ static void el1_interrupt(dpeth_t * dep)
|
|||
/* Be sure that interrupts are cleared */
|
||||
inb_el1(dep, EL1_RECV);
|
||||
inb_el1(dep, EL1_XMIT);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
** Name: void el1_init(dpeth_t *dep)
|
||||
** Name: el1_init
|
||||
** Function: Initalizes board hardware and driver data structures.
|
||||
*/
|
||||
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_dumpstatsf = el1_dumpstats;
|
||||
dep->de_interruptf = el1_interrupt;
|
||||
|
||||
return; /* Done */
|
||||
}
|
||||
|
||||
/*
|
||||
** Name: int el1_probe(dpeth_t *dep)
|
||||
** Name: el1_probe
|
||||
** Function: Checks for presence of the board.
|
||||
*/
|
||||
int el1_probe(dpeth_t * dep)
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
*/
|
||||
|
||||
#include <minix/drivers.h>
|
||||
#include <minix/netdriver.h>
|
||||
#include <net/gen/ether.h>
|
||||
#include <net/gen/eth_io.h>
|
||||
#include "dp.h"
|
||||
|
|
@ -20,7 +21,7 @@
|
|||
#include "3c503.h"
|
||||
|
||||
/*
|
||||
** Name: void el2_init(dpeth_t *dep);
|
||||
** Name: el2_init
|
||||
** Function: Initalize hardware and data structures.
|
||||
*/
|
||||
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)
|
||||
printf("%02X%c", dep->de_address.ea_addr[ix],
|
||||
ix < SA_ADDR_LEN - 1 ? ':' : '\n');
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
** Name: void el2_stop(dpeth_t *dep);
|
||||
** Name: el2_stop
|
||||
** Function: Stops board by disabling interrupts.
|
||||
*/
|
||||
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);
|
||||
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.
|
||||
** Initialize memory addressing if card detected.
|
||||
*/
|
||||
|
|
@ -132,9 +131,9 @@ int el2_probe(dpeth_t * dep)
|
|||
|
||||
/* Resets board */
|
||||
outb_el2(dep, EL2_CNTR, ECNTR_RESET | thin);
|
||||
milli_delay(1);
|
||||
micro_delay(1000);
|
||||
outb_el2(dep, EL2_CNTR, thin);
|
||||
milli_delay(5);
|
||||
micro_delay(5000);
|
||||
|
||||
/* Map the address PROM to lower I/O address range */
|
||||
outb_el2(dep, EL2_CNTR, ECNTR_SAPROM | thin);
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
*/
|
||||
|
||||
#include <minix/drivers.h>
|
||||
#include <minix/com.h>
|
||||
#include <minix/netdriver.h>
|
||||
#include <net/gen/ether.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
|
||||
** and updates local counters.
|
||||
*/
|
||||
|
|
@ -52,36 +52,30 @@ static void el3_update_stats(dpeth_t * dep)
|
|||
/* Goes back to operating window and enables statistics */
|
||||
SetWindow(WNO_Operating);
|
||||
outw_el3(dep, REG_CmdStatus, CMD_StatsEnable);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
** Name: void el3_getstats(dpeth_t *dep)
|
||||
** Name: el3_getstats
|
||||
** Function: Reads statistics counters from board.
|
||||
*/
|
||||
static void el3_getstats(dpeth_t * dep)
|
||||
{
|
||||
|
||||
lock();
|
||||
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).
|
||||
*/
|
||||
static void el3_dodump(dpeth_t * dep)
|
||||
{
|
||||
|
||||
el3_getstats(dep);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
** Name: void el3_rx_mode(dpeth_t *dep)
|
||||
** Name: el3_rx_mode
|
||||
** Function: Initializes receiver mode
|
||||
*/
|
||||
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_SetRxFilter | dep->de_recv_mode);
|
||||
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.
|
||||
*/
|
||||
static void el3_reset(dpeth_t * UNUSED(dep))
|
||||
{
|
||||
|
||||
return; /* Done */
|
||||
}
|
||||
|
||||
/*
|
||||
** Name: void el3_write_fifo(dpeth_t * dep, int pktsize);
|
||||
** 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)
|
||||
** Name: el3_recv
|
||||
** Function: Receive function. Called from interrupt handler or
|
||||
** 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;
|
||||
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 */
|
||||
if (dep->de_recvq_tail == dep->de_recvq_head)
|
||||
dep->de_recvq_head = dep->de_recvq_tail = NULL;
|
||||
else
|
||||
dep->de_recvq_head = rxptr->next;
|
||||
unlock();
|
||||
/* Remove buffer from queue */
|
||||
if (dep->de_recvq_tail == dep->de_recvq_head)
|
||||
dep->de_recvq_head = dep->de_recvq_tail = NULL;
|
||||
else
|
||||
dep->de_recvq_head = rxptr->next;
|
||||
|
||||
/* Copy buffer to user area and free it */
|
||||
mem2user(dep, rxptr);
|
||||
/* Copy buffer to user area and free it */
|
||||
size = MIN(rxptr->size, max);
|
||||
|
||||
dep->de_read_s = rxptr->size;
|
||||
dep->de_flags |= DEF_ACK_RECV;
|
||||
dep->de_flags &= NOT(DEF_READING);
|
||||
netdriver_copyout(data, 0, rxptr->buffer, size);
|
||||
|
||||
/* Return buffer to the idle pool */
|
||||
free_buff(dep, rxptr);
|
||||
}
|
||||
return;
|
||||
/* Return buffer to the idle pool */
|
||||
free_buff(dep, rxptr);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
/*
|
||||
** Name: void el3_rx_complete(dpeth_t * dep);
|
||||
** Name: el3_rx_complete
|
||||
** Function: Upon receiving a packet, provides status checks
|
||||
** and if packet is OK copies it to local buffer.
|
||||
*/
|
||||
|
|
@ -205,38 +163,36 @@ static void el3_rx_complete(dpeth_t * dep)
|
|||
|
||||
} else {
|
||||
/* 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->size = pktsize;
|
||||
|
||||
lock(); /* Queue packet to receive queue */
|
||||
/* Queue packet to receive queue */
|
||||
if (dep->de_recvq_head == NULL)
|
||||
dep->de_recvq_head = rxptr;
|
||||
else
|
||||
dep->de_recvq_tail->next = rxptr;
|
||||
dep->de_recvq_tail = rxptr;
|
||||
unlock();
|
||||
|
||||
/* Reply to pending Receive requests, if any */
|
||||
el3_recv(dep, TRUE, pktsize);
|
||||
netdriver_recv();
|
||||
}
|
||||
|
||||
/* Discard top packet from queue */
|
||||
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
|
||||
** 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;
|
||||
int ix;
|
||||
short int TxStatus;
|
||||
size_t padding;
|
||||
|
||||
getticks(&now);
|
||||
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);
|
||||
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) */
|
||||
outw_el3(dep, REG_TxFIFO, count);
|
||||
/* Writes Transmitter preamble 2nd Word (all zero) */
|
||||
outw_el3(dep, REG_TxFIFO, 0);
|
||||
/* Writes packet */
|
||||
el3_write_fifo(dep, count);
|
||||
/* Writes Transmitter preamble 1st Word (packet len, no ints) */
|
||||
outw_el3(dep, REG_TxFIFO, size);
|
||||
/* Writes Transmitter preamble 2nd Word (all zero) */
|
||||
outw_el3(dep, REG_TxFIFO, 0);
|
||||
/* Writes packet */
|
||||
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);
|
||||
dep->de_flags |= (DEF_XMIT_BUSY | DEF_ACK_SEND);
|
||||
if (inw_el3(dep, REG_TxFree) > ETH_MAX_PACK_SIZE) {
|
||||
/* Tx has enough room for a packet of maximum size */
|
||||
dep->de_flags &= NOT(DEF_XMIT_BUSY | DEF_SENDING);
|
||||
} else {
|
||||
/* Interrupt driver when enough room is available */
|
||||
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);
|
||||
}
|
||||
getticks(&dep->de_xmit_start);
|
||||
dep->de_flags |= DEF_XMIT_BUSY;
|
||||
if (inw_el3(dep, REG_TxFree) > ETH_MAX_PACK_SIZE) {
|
||||
/* Tx has enough room for a packet of maximum size */
|
||||
dep->de_flags &= NOT(DEF_XMIT_BUSY);
|
||||
} else {
|
||||
/* Interrupt driver when enough room is available */
|
||||
outw_el3(dep, REG_CmdStatus, CMD_SetTxAvailable | ETH_MAX_PACK_SIZE);
|
||||
}
|
||||
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.
|
||||
*/
|
||||
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) {
|
||||
outw_el3(dep, REG_CmdStatus, CMD_StopIntXcvr);
|
||||
/* milli_delay(5); */
|
||||
/* micro_delay(5000); */
|
||||
|
||||
} else if (dep->de_if_port == TP_XCVR) {
|
||||
SetWindow(WNO_Diagnostics);
|
||||
outw_el3(dep, REG_MediaStatus, inw_el3(dep, REG_MediaStatus) &
|
||||
NOT((MediaLBeatEnable | MediaJabberEnable)));
|
||||
/* milli_delay(5); */
|
||||
/* micro_delay(5000); */
|
||||
}
|
||||
DEBUG(printf("%s: stopping Etherlink ... \n", dep->de_name));
|
||||
/* Issues a global reset
|
||||
outw_el3(dep, REG_CmdStatus, CMD_GlobalReset); */
|
||||
sys_irqdisable(&dep->de_hook); /* Disable interrupt */
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
** Name: void el3_interrupt(dpeth_t *dep)
|
||||
** Name: el3_interrupt
|
||||
** Function: Interrupt handler. Acknwledges transmit interrupts
|
||||
** 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);)
|
||||
dep->de_flags &= NOT(DEF_XMIT_BUSY);
|
||||
outw_el3(dep, REG_CmdStatus, CMD_Acknowledge | INT_TxAvailable);
|
||||
if (dep->de_flags & DEF_SENDING) /* Send pending */
|
||||
el3_send(dep, TRUE, dep->de_send_s);
|
||||
netdriver_send();
|
||||
}
|
||||
if (isr & (INT_AdapterFail | INT_RxEarly | INT_UpdateStats)) {
|
||||
|
||||
|
|
@ -354,11 +309,10 @@ static void el3_interrupt(dpeth_t * dep)
|
|||
/* Acknowledge interrupt */
|
||||
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
|
||||
*/
|
||||
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;
|
||||
outb(port, address);
|
||||
milli_delay(5); /* Allows EEPROM reads */
|
||||
micro_delay(5000); /* Allows EEPROM reads */
|
||||
for (result = 0, bit = 16; bit > 0; bit -= 1) {
|
||||
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
|
||||
*/
|
||||
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 & 0xFF;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
** Name: void el3_open(dpeth_t *dep)
|
||||
** Name: el3_open
|
||||
** Function: Initalizes board hardware and driver data structures.
|
||||
*/
|
||||
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) {
|
||||
/* Start internal transceiver for Coaxial cable */
|
||||
outw_el3(dep, REG_CmdStatus, CMD_StartIntXcvr);
|
||||
milli_delay(5);
|
||||
micro_delay(5000);
|
||||
|
||||
} else if (dep->de_if_port == TP_XCVR) {
|
||||
/* 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)
|
||||
printf("%02X%c", dep->de_address.ea_addr[ix],
|
||||
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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
static void el3_write_id(port_t port)
|
||||
|
|
@ -548,11 +499,10 @@ static void el3_write_id(port_t port)
|
|||
pattern <<= 1;
|
||||
pattern = (pattern & 0x0100) ? pattern ^ 0xCF : pattern;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
** Name: int el3_probe(dpeth_t *dep)
|
||||
** Name: el3_probe
|
||||
** Function: Checks for presence of the board.
|
||||
*/
|
||||
int el3_probe(dpeth_t * dep)
|
||||
|
|
@ -572,10 +522,10 @@ int el3_probe(dpeth_t * dep)
|
|||
|
||||
el3_write_id(id_port);
|
||||
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);
|
||||
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_ramsize = /* RAM size is meaningless */
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
#include <assert.h>
|
||||
/*
|
||||
** File: 8390.c May 02, 2000
|
||||
**
|
||||
|
|
@ -12,32 +11,18 @@
|
|||
*/
|
||||
|
||||
#include <minix/drivers.h>
|
||||
#include <minix/com.h>
|
||||
#include <minix/netdriver.h>
|
||||
#include <net/gen/ether.h>
|
||||
#include <net/gen/eth_io.h>
|
||||
#include <assert.h>
|
||||
#include "dp.h"
|
||||
|
||||
#if (ENABLE_DP8390 == 1)
|
||||
|
||||
#define PIO16 0 /* NOTE: pio 16 functions missing */
|
||||
|
||||
#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.
|
||||
*/
|
||||
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);
|
||||
mode |= (CR_PS_P0 | CR_STA);
|
||||
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.
|
||||
*/
|
||||
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_TBCR0, size & 0xFF);
|
||||
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,
|
||||
** int size, void *dst)
|
||||
** Name: mem_getblock
|
||||
** Function: Reads a block of packet from board (shared memory).
|
||||
*/
|
||||
static void mem_getblock(dpeth_t *dep, u16_t offset, int size, void *dst)
|
||||
{
|
||||
panic("mem_getblock: not converted to safecopies");
|
||||
#if 0
|
||||
sys_nic2mem(dep->de_linmem + offset, SELF, dst, size);
|
||||
return;
|
||||
#endif
|
||||
|
||||
assert(offset + size <= dep->de_ramsize);
|
||||
|
||||
memcpy(dst, dep->de_locmem + offset, size);
|
||||
}
|
||||
|
||||
/*
|
||||
** 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).
|
||||
*/
|
||||
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");
|
||||
#if 0
|
||||
phys_bytes offset;
|
||||
iovec_dat_s_t *iovp = &dep->de_read_iovec;
|
||||
int bytes, ix = 0;
|
||||
|
||||
size_t offset, left;
|
||||
|
||||
/* Computes shared memory address (skipping receive header) */
|
||||
offset = pageno * DP_PAGESIZE + sizeof(dp_rcvhdr_t);
|
||||
|
||||
do { /* Reads chuncks of packet into user area */
|
||||
|
||||
bytes = iovp->iod_iovec[ix].iov_size; /* Size of a chunck */
|
||||
if (bytes > pktsize) bytes = pktsize;
|
||||
|
||||
/* Reads from board to user area */
|
||||
if ((offset + bytes) > (dep->de_stoppage * DP_PAGESIZE)) {
|
||||
|
||||
/* 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
|
||||
if (offset + size > dep->de_stoppage * DP_PAGESIZE) {
|
||||
left = dep->de_stoppage * DP_PAGESIZE - offset;
|
||||
netdriver_copyout(data, 0, dep->de_locmem + offset, left);
|
||||
offset = dep->de_startpage * DP_PAGESIZE;
|
||||
netdriver_copyout(data, left, dep->de_locmem + offset, size - left);
|
||||
} else
|
||||
netdriver_copyout(data, 0, dep->de_locmem + offset, size);
|
||||
}
|
||||
|
||||
/*
|
||||
** 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).
|
||||
*/
|
||||
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
|
||||
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;
|
||||
size_t offset;
|
||||
|
||||
/* Computes shared memory address */
|
||||
offset = pageno * DP_PAGESIZE;
|
||||
|
||||
do { /* Reads chuncks of packet from user area */
|
||||
|
||||
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
|
||||
netdriver_copyin(data, 0, dep->de_locmem + offset, size);
|
||||
}
|
||||
|
||||
/*
|
||||
** Name: void pio_getblock(dpeth_t *dep, u16_t offset,
|
||||
** int size, void *dst)
|
||||
** Name: pio_getblock
|
||||
** 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)
|
||||
|
|
@ -176,110 +108,72 @@ static void pio_getblock(dpeth_t *dep, u16_t offset, int size, void *dst)
|
|||
/* Sets up board for reading */
|
||||
ns_rw_setup(dep, CR_DM_RR, size, offset);
|
||||
|
||||
#if PIO16 == 0
|
||||
insb(dep->de_data_port, SELF, dst, size);
|
||||
#else
|
||||
if (dep->de_16bit == TRUE) {
|
||||
if (dep->de_16bit == TRUE)
|
||||
insw(dep->de_data_port, dst, size);
|
||||
} else {
|
||||
else
|
||||
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).
|
||||
*/
|
||||
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;
|
||||
unsigned offset, iov_offset; int r, bytes, ix = 0;
|
||||
size_t offset, left;
|
||||
|
||||
/* Computes memory address (skipping receive header) */
|
||||
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;
|
||||
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 */
|
||||
if (bytes > pktsize) bytes = pktsize;
|
||||
ns_rw_setup(dep, CR_DM_RR, left, offset);
|
||||
|
||||
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 */
|
||||
bytes = dep->de_stoppage * DP_PAGESIZE - 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);
|
||||
}
|
||||
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;
|
||||
offset = dep->de_startpage * DP_PAGESIZE;
|
||||
} else
|
||||
left = 0;
|
||||
|
||||
if (++ix >= IOVEC_NR) { /* Next buffer of IO vector */
|
||||
dp_next_iovec(iovp);
|
||||
ix = 0;
|
||||
}
|
||||
iov_offset= 0;
|
||||
/* Till packet done */
|
||||
} while ((pktsize -= bytes) > 0);
|
||||
return;
|
||||
ns_rw_setup(dep, CR_DM_RR, size - left, offset);
|
||||
|
||||
if (dep->de_16bit)
|
||||
netdriver_portinw(data, left, dep->de_data_port, size - left);
|
||||
else
|
||||
netdriver_portinb(data, left, dep->de_data_port, size - left);
|
||||
}
|
||||
|
||||
/*
|
||||
** 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).
|
||||
*/
|
||||
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 r, bytes, ix = 0;
|
||||
int ix;
|
||||
|
||||
/* Sets up board for writing */
|
||||
ns_rw_setup(dep, CR_DM_RW, pktsize, pageno * DP_PAGESIZE);
|
||||
|
||||
do { /* Reads chuncks of packet from user area */
|
||||
ns_rw_setup(dep, CR_DM_RW, size, pageno * DP_PAGESIZE);
|
||||
|
||||
bytes = iovp->iod_iovec[ix].iov_size; /* Size of chunck */
|
||||
if (bytes > pktsize) bytes = pktsize;
|
||||
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);
|
||||
if (dep->de_16bit)
|
||||
netdriver_portoutw(data, 0, dep->de_data_port, size);
|
||||
else
|
||||
netdriver_portoutb(data, 0, dep->de_data_port, size);
|
||||
|
||||
for (ix = 0; ix < 100; ix += 1) {
|
||||
if (inb_reg0(dep, DP_ISR) & ISR_RDC) break;
|
||||
}
|
||||
if (ix == 100) {
|
||||
panic("%s", RdmaErrMsg);
|
||||
}
|
||||
return;
|
||||
if (ix == 100)
|
||||
panic("remote dma failed to complete");
|
||||
}
|
||||
|
||||
/*
|
||||
** Name: void ns_stats(dpeth_t * dep)
|
||||
** Name: ns_stats
|
||||
** Function: Updates counters reading from device
|
||||
*/
|
||||
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_recvErr += inb_reg0(dep, DP_CNTR1);
|
||||
dep->de_stat.ets_fifoOver += inb_reg0(dep, DP_CNTR2);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
** Name: void ns_dodump(dpeth_t * dep)
|
||||
** Function: Displays statistics (a request from F5 key).
|
||||
** Name: ns_dodump
|
||||
** Function: Displays statistics (a request from a function key).
|
||||
*/
|
||||
static void ns_dodump(dpeth_t * dep)
|
||||
{
|
||||
|
||||
ns_stats(dep); /* Forces reading fo counters from board */
|
||||
return;
|
||||
ns_stats(dep); /* Forces reading of counters from board */
|
||||
}
|
||||
|
||||
/*
|
||||
** Name: void ns_reinit(dpeth_t *dep)
|
||||
** Name: ns_reinit
|
||||
** Function: Updates receiver configuration.
|
||||
*/
|
||||
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;
|
||||
outb_reg0(dep, DP_CR, CR_PS_P0);
|
||||
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.
|
||||
*/
|
||||
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;
|
||||
|
||||
if (queue = dep->de_sendq_head, dep->de_sendq[queue].sq_filled) {
|
||||
if (from_int) panic("should not be sending ");
|
||||
dep->de_send_s = size;
|
||||
return;
|
||||
}
|
||||
(dep->de_user2nicf) (dep, dep->de_sendq[queue].sq_sendpage, size);
|
||||
queue = dep->de_sendq_head;
|
||||
if (dep->de_sendq[queue].sq_filled)
|
||||
return SUSPEND;
|
||||
|
||||
(dep->de_user2nicf)(dep, dep->de_sendq[queue].sq_sendpage, data, size);
|
||||
dep->bytes_Tx += (long) size;
|
||||
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.. */
|
||||
ns_start_xmit(dep, size, dep->de_sendq[queue].sq_sendpage);
|
||||
} 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;
|
||||
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.
|
||||
*/
|
||||
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_RBCR0, 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 */ ;
|
||||
outb_reg0(dep, DP_TCR, TCR_1EXTERNAL | TCR_OFST);
|
||||
outb_reg0(dep, DP_CR, CR_STA | CR_NO_DMA);
|
||||
outb_reg0(dep, DP_TCR, TCR_NORMAL | TCR_OFST);
|
||||
|
||||
/* 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 */ ;
|
||||
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;
|
||||
for (ix = 0; ix < dep->de_sendq_nr; ix++)
|
||||
dep->de_sendq[ix].sq_filled = FALSE;
|
||||
ns_send(dep, TRUE, dep->de_send_s);
|
||||
return;
|
||||
netdriver_send();
|
||||
}
|
||||
|
||||
/*
|
||||
** Name: void ns_recv(dpeth_t *dep, int fromint, int size)
|
||||
** Name: ns_recv
|
||||
** 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;
|
||||
unsigned pageno, curr, next;
|
||||
vir_bytes length;
|
||||
size_t length;
|
||||
int packet_processed = FALSE;
|
||||
#ifdef ETH_IGN_PROTO
|
||||
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);
|
||||
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
|
||||
(dep->de_getblockf) (dep, pageno * DP_PAGESIZE + sizeof(header) + 2 * sizeof(ether_addr_t), sizeof(eth_type), ð_type);
|
||||
(dep->de_getblockf)(dep, pageno * DP_PAGESIZE + sizeof(header) +
|
||||
2 * sizeof(ether_addr_t), sizeof(eth_type), ð_type);
|
||||
#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;
|
||||
|
||||
if (length < ETH_MIN_PACK_SIZE || length > ETH_MAX_PACK_SIZE) {
|
||||
printf("%s: packet with strange length arrived: %ld\n",
|
||||
if (length < ETH_MIN_PACK_SIZE || length > max) {
|
||||
printf("%s: packet with strange length arrived: %zu\n",
|
||||
dep->de_name, length);
|
||||
dep->de_stat.ets_recvErr += 1;
|
||||
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);
|
||||
dep->de_stat.ets_recvErr += 1;
|
||||
next = curr;
|
||||
|
||||
#ifdef ETH_IGN_PROTO
|
||||
} else if (eth_type == eth_ign_proto) {
|
||||
/* Hack: ignore packets of a given protocol */
|
||||
static int first = TRUE;
|
||||
if (first) {
|
||||
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;
|
||||
#endif
|
||||
} else if (header.dr_status & RSR_FO) {
|
||||
/* 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;
|
||||
next = curr;
|
||||
|
||||
} else if ((header.dr_status & RSR_PRX) && (dep->de_flags & DEF_ENABLED)) {
|
||||
|
||||
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);
|
||||
} else if (header.dr_status & RSR_PRX) {
|
||||
(dep->de_nic2userf)(dep, pageno, data, length);
|
||||
packet_processed = TRUE;
|
||||
}
|
||||
dep->bytes_Rx += (long) length;
|
||||
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;
|
||||
|
||||
} while (!packet_processed);
|
||||
#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
|
||||
return;
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
/*
|
||||
** Name: void ns_interrupt(dpeth_t * dep)
|
||||
** Name: ns_interrupt
|
||||
** Function: Handles interrupt.
|
||||
*/
|
||||
static void ns_interrupt(dpeth_t * dep)
|
||||
|
|
@ -487,13 +369,15 @@ static void ns_interrupt(dpeth_t * dep)
|
|||
dep->de_stat.ets_fifoUnder++;
|
||||
}
|
||||
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++;
|
||||
}
|
||||
queue = dep->de_sendq_tail;
|
||||
|
||||
if (!(dep->de_sendq[queue].sq_filled)) { /* Hardware bug? */
|
||||
printf("%s: transmit interrupt, but not sending\n", dep->de_name);
|
||||
if (!(dep->de_sendq[queue].sq_filled)) { /* Hardware bug? */
|
||||
printf("%s: transmit interrupt, but not sending\n",
|
||||
dep->de_name);
|
||||
continue;
|
||||
}
|
||||
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,
|
||||
dep->de_sendq[queue].sq_sendpage);
|
||||
}
|
||||
if (dep->de_flags & DEF_SENDING) {
|
||||
ns_send(dep, TRUE, dep->de_send_s);
|
||||
}
|
||||
netdriver_send();
|
||||
}
|
||||
if (isr & ISR_PRX) {
|
||||
ns_recv(dep, TRUE, 0);
|
||||
netdriver_recv();
|
||||
}
|
||||
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++;
|
||||
}
|
||||
if (isr & ISR_CNT) {
|
||||
|
|
@ -526,26 +409,21 @@ static void ns_interrupt(dpeth_t * dep)
|
|||
/* Nothing to do */
|
||||
}
|
||||
if (isr & ISR_RST) {
|
||||
/* This means we got an interrupt but the ethernet
|
||||
* chip is shutdown. We set the flag DEF_STOPPED, and
|
||||
* continue processing arrived packets. When the
|
||||
* receive buffer is empty, we reset the dp8390. */
|
||||
/* This means we got an interrupt but the ethernet chip is shut
|
||||
* down. We reset the chip right away, possibly losing received
|
||||
* packets in the process. There used to be a more elaborate
|
||||
* 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);
|
||||
dep->de_flags |= DEF_STOPPED;
|
||||
ns_reset(dep);
|
||||
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
|
||||
*/
|
||||
void ns_init(dpeth_t * dep)
|
||||
|
|
@ -555,12 +433,8 @@ void ns_init(dpeth_t * dep)
|
|||
|
||||
/* NS8390 initialization (as recommended in National Semiconductor specs) */
|
||||
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) |
|
||||
DCR_LTLENDIAN | DCR_8BYTES | DCR_BMS));
|
||||
#endif
|
||||
outb_reg0(dep, DP_RBCR0, 0);
|
||||
outb_reg0(dep, DP_RBCR1, 0);
|
||||
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_getblockf = mem_getblock;
|
||||
} else {
|
||||
#if PIO16 == 0
|
||||
dep->de_user2nicf = pio_user2nic;
|
||||
dep->de_nic2userf = pio_nic2user;
|
||||
dep->de_getblockf = pio_getblock;
|
||||
#else
|
||||
#error Missing I/O functions for pio 16 bits
|
||||
#endif
|
||||
}
|
||||
dep->de_recvf = ns_recv;
|
||||
dep->de_sendf = ns_send;
|
||||
|
|
@ -624,135 +494,8 @@ void ns_init(dpeth_t * dep)
|
|||
dep->de_getstatsf = ns_stats;
|
||||
dep->de_dumpstatsf = ns_dodump;
|
||||
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 */
|
||||
|
||||
/** end 8390.c **/
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
LDADD+= -lnetdriver -lsys
|
||||
|
||||
CPPFLAGS+= -Ddebug=0
|
||||
CPPFLAGS+= -DVERBOSE=0
|
||||
|
||||
.include <minix.service.mk>
|
||||
|
|
|
|||
|
|
@ -3,11 +3,12 @@
|
|||
**
|
||||
** 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.
|
||||
*/
|
||||
|
||||
#include <minix/drivers.h>
|
||||
#include <minix/netdriver.h>
|
||||
#include <net/gen/ether.h>
|
||||
#include <net/gen/eth_io.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);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
** Name: unsigned int inb(unsigned short int port);
|
||||
** Name: inb
|
||||
** Function: Reads a byte from specified i/o 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.
|
||||
*/
|
||||
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);
|
||||
** Function: Reads a sequence of bytes from specified i/o port to user space buffer.
|
||||
** Name: insb
|
||||
** Function: Reads a sequence of bytes from an i/o port.
|
||||
*/
|
||||
void insb(unsigned short int port, endpoint_t proc_nr,
|
||||
void *buffer, int count)
|
||||
void insb(unsigned short int port, void *buffer, int count)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if ((rc = sys_insb(port, proc_nr, buffer, count)) != OK)
|
||||
if ((rc = sys_insb(port, SELF, buffer, count)) != OK)
|
||||
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.
|
||||
*/
|
||||
void outb(unsigned short port, unsigned long value)
|
||||
|
|
@ -71,11 +80,10 @@ void outb(unsigned short port, unsigned long value)
|
|||
int 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.
|
||||
*/
|
||||
void outw(unsigned short port, unsigned long value)
|
||||
|
|
@ -83,20 +91,18 @@ void outw(unsigned short port, unsigned long value)
|
|||
int 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);
|
||||
** Function: Writes a sequence of bytes from user space to specified i/o port.
|
||||
** Name: outsb
|
||||
** 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;
|
||||
|
||||
if ((rc = sys_outsb(port, proc_nr, buffer, count)) != OK)
|
||||
if ((rc = sys_outsb(port, SELF, buffer, count)) != OK)
|
||||
warning("outsb", rc);
|
||||
return;
|
||||
}
|
||||
|
||||
#else
|
||||
|
|
|
|||
|
|
@ -14,9 +14,10 @@
|
|||
#include <minix/drivers.h>
|
||||
#include <minix/netdriver.h>
|
||||
#include <minix/endpoint.h>
|
||||
#include <minix/ds.h>
|
||||
#include <net/gen/ether.h>
|
||||
#include <net/gen/eth_io.h>
|
||||
#include <sys/mman.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "dp.h"
|
||||
|
||||
|
|
@ -24,7 +25,6 @@
|
|||
** Local data
|
||||
*/
|
||||
static dpeth_t de_state;
|
||||
static int de_instance;
|
||||
|
||||
typedef struct dp_conf { /* Configuration description structure */
|
||||
port_t dpc_port;
|
||||
|
|
@ -41,90 +41,43 @@ static dp_conf_t dp_conf[DP_CONF_NR] = {
|
|||
{ 0x000, 0, 0x00000, },
|
||||
};
|
||||
|
||||
static char CopyErrMsg[] = "unable to read/write user data";
|
||||
static char RecvErrMsg[] = "netdriver_receive failed";
|
||||
static char SendErrMsg[] = "send failed";
|
||||
static char SizeErrMsg[] = "illegal packet size";
|
||||
static char TypeErrMsg[] = "illegal message type";
|
||||
static char DevName[] = "eth#?";
|
||||
static int do_init(unsigned int instance, ether_addr_t *addr);
|
||||
static void do_stop(void);
|
||||
static void do_mode(unsigned int mode);
|
||||
static int do_send(struct netdriver_data *data, size_t size);
|
||||
static ssize_t do_recv(struct netdriver_data *data, size_t max);
|
||||
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)
|
||||
** 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)
|
||||
** Name: update_conf
|
||||
** Function: Gets the default settings from 'dp_conf' table and
|
||||
** 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";
|
||||
char ec_key[16];
|
||||
long val;
|
||||
|
||||
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 */
|
||||
switch (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;
|
||||
}
|
||||
env_parse(ec_key, dpc_fmt, 0, &val, 0x000L, 0x3FFL);
|
||||
dep->de_base_port = val;
|
||||
|
||||
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 */
|
||||
env_parse(ec_key, dpc_fmt, 2, &val, 0L, LONG_MAX);
|
||||
dep->de_linmem = val;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
** Name: void do_dump(message *mp)
|
||||
** Name: do_dump
|
||||
** Function: Displays statistics on screen (SFx key from console)
|
||||
*/
|
||||
static void do_dump(const message *mp)
|
||||
static void do_dump(void)
|
||||
{
|
||||
dpeth_t *dep;
|
||||
|
||||
|
|
@ -150,14 +101,12 @@ static void do_dump(const message *mp)
|
|||
|
||||
printf("\n\n");
|
||||
|
||||
if (dep->de_mode == DEM_DISABLED) return;
|
||||
|
||||
printf("%s statistics:\t\t", dep->de_name);
|
||||
|
||||
/* 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 */
|
||||
printf("Tx bytes:%10ld\t", dep->bytes_Tx);
|
||||
|
|
@ -178,40 +127,31 @@ static void do_dump(const message *mp)
|
|||
/* Transmit collisions/receive CRC errors */
|
||||
printf("Tx Coll: %8ld\t", dep->de_stat.ets_collision);
|
||||
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)
|
||||
** 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);
|
||||
** Name: do_first_init
|
||||
** Function: Init action to setup task
|
||||
*/
|
||||
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 */
|
||||
memset((void *) &(dep->de_stat), 0, sizeof(eth_stat_t));
|
||||
memset(&dep->de_stat, 0, sizeof(dep->de_stat));
|
||||
|
||||
/* 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
|
||||
* 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;
|
||||
if (sys_irqsetpolicy(dep->de_irq, 0 /*IRQ_REENABLE*/, &dep->de_hook) != OK)
|
||||
panic("unable to set IRQ policy");
|
||||
dep->de_int_pending = FALSE;
|
||||
sys_irqenable(&dep->de_hook);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
** Name: void do_init(message *mp)
|
||||
** Name: do_init
|
||||
** 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;
|
||||
dp_conf_t *dcp;
|
||||
message reply_mess;
|
||||
int r, confnr;
|
||||
int confnr, fkeys, sfkeys;
|
||||
|
||||
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. */
|
||||
confnr = MIN(de_instance, DP_CONF_NR-1);
|
||||
confnr = MIN(instance, DP_CONF_NR-1);
|
||||
|
||||
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 (dep->de_mode == DEM_ENABLED &&
|
||||
!el1_probe(dep) && /* Probe for 3c501 */
|
||||
!wdeth_probe(dep) && /* Probe for WD80x3 */
|
||||
!ne_probe(dep) && /* Probe for NEx000 */
|
||||
!el2_probe(dep) && /* Probe for 3c503 */
|
||||
!el3_probe(dep)) { /* Probe for 3c509 */
|
||||
printf("%s: warning no ethernet card found at 0x%04X\n",
|
||||
dep->de_name, dep->de_base_port);
|
||||
dep->de_mode = DEM_DISABLED;
|
||||
}
|
||||
if (!el1_probe(dep) && /* Probe for 3c501 */
|
||||
!wdeth_probe(dep) && /* Probe for WD80x3 */
|
||||
!ne_probe(dep) && /* Probe for NEx000 */
|
||||
!el2_probe(dep) && /* Probe for 3c503 */
|
||||
!el3_probe(dep)) { /* Probe for 3c509 */
|
||||
printf("%s: warning no ethernet card found at 0x%04X\n",
|
||||
dep->de_name, dep->de_base_port);
|
||||
return ENXIO;
|
||||
}
|
||||
|
||||
r = OK;
|
||||
do_first_init(dep, dcp);
|
||||
|
||||
/* 'de_mode' may change if probe routines fail, test again */
|
||||
switch (dep->de_mode) {
|
||||
/* Request function key for debug dumps */
|
||||
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:
|
||||
/* Device is configured OFF or hardware probe failed */
|
||||
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;
|
||||
memcpy(addr, dep->de_address.ea_addr, sizeof(*addr));
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Name: void dp_next_iovec(iovec_dat_t *iovp)
|
||||
** Function: Retrieves data from next iovec element.
|
||||
** Name: de_mode
|
||||
** 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;
|
||||
|
||||
dep = &de_state;
|
||||
|
||||
dep->de_client = mp->m_source;
|
||||
|
||||
if (dep->de_mode == DEM_ENABLED) {
|
||||
|
||||
if (dep->de_flags & DEF_SENDING) /* Is sending in progress? */
|
||||
panic("send already in progress ");
|
||||
|
||||
dep->de_write_iovec.iod_proc_nr = mp->m_source;
|
||||
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;
|
||||
dep->de_flags &= NOT(DEF_PROMISC | DEF_MULTI | DEF_BROAD);
|
||||
if (mode & NDEV_PROMISC)
|
||||
dep->de_flags |= DEF_PROMISC | DEF_MULTI | DEF_BROAD;
|
||||
if (mode & NDEV_MULTI)
|
||||
dep->de_flags |= DEF_MULTI;
|
||||
if (mode & NDEV_BROAD)
|
||||
dep->de_flags |= DEF_BROAD;
|
||||
(*dep->de_flagsf)(dep);
|
||||
}
|
||||
|
||||
/*
|
||||
** Name: void do_vread_s(message *mp, int vectored)
|
||||
** Function:
|
||||
** Name: do_send
|
||||
** 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;
|
||||
|
||||
dep = &de_state;
|
||||
|
||||
dep->de_client = mp->m_source;
|
||||
|
||||
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;
|
||||
return (*dep->de_sendf)(dep, data, size);
|
||||
}
|
||||
|
||||
/*
|
||||
** 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.
|
||||
*/
|
||||
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;
|
||||
|
||||
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;
|
||||
memcpy(stat, &de_state.de_stat, sizeof(*stat));
|
||||
}
|
||||
|
||||
/*
|
||||
** Name: void dp_stop(dpeth_t *dep)
|
||||
** Name: do_stop
|
||||
** 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 */
|
||||
(dep->de_stopf) (dep);
|
||||
dep->de_flags = DEF_EMPTY;
|
||||
dep->de_mode = DEM_DISABLED;
|
||||
}
|
||||
return;
|
||||
/* Stop device */
|
||||
(dep->de_stopf)(dep);
|
||||
}
|
||||
|
||||
static void do_watchdog(const void *UNUSED(message))
|
||||
{
|
||||
|
||||
DEBUG(printf("\t no reply"));
|
||||
return;
|
||||
}
|
||||
|
||||
static void handle_hw_intr(void)
|
||||
/*
|
||||
** Name: do_intr
|
||||
** Function; Handles interrupts.
|
||||
*/
|
||||
static void do_intr(unsigned int __unused mask)
|
||||
{
|
||||
dpeth_t *dep;
|
||||
|
||||
dep = &de_state;
|
||||
|
||||
/* If device is enabled and interrupt pending */
|
||||
if (dep->de_mode == DEM_ENABLED) {
|
||||
dep->de_int_pending = TRUE;
|
||||
(*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);
|
||||
}
|
||||
(*dep->de_interruptf)(dep);
|
||||
sys_irqenable(&dep->de_hook);
|
||||
}
|
||||
|
||||
/* SEF functions and variables. */
|
||||
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);
|
||||
/*
|
||||
** Name: do_other
|
||||
** Function: Processes miscellaneous messages.
|
||||
*/
|
||||
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
|
||||
*/
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
message m;
|
||||
int ipc_status;
|
||||
int rc;
|
||||
|
||||
/* SEF local startup. */
|
||||
env_setargs(argc, argv);
|
||||
sef_local_startup();
|
||||
|
||||
while (TRUE) {
|
||||
if ((rc = netdriver_receive(ANY, &m, &ipc_status)) != OK){
|
||||
panic(RecvErrMsg, rc);
|
||||
}
|
||||
netdriver_task(&dp_table);
|
||||
|
||||
DEBUG(printf("eth: got message %d, ", m.m_type));
|
||||
|
||||
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 */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* 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 **/
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@
|
|||
|
||||
#define NOT(x) (~(x))
|
||||
|
||||
#if debug == 1
|
||||
#if VERBOSE == 1
|
||||
# define DEBUG(statm) statm
|
||||
#else
|
||||
# define DEBUG(statm)
|
||||
|
|
@ -70,26 +70,19 @@ typedef struct _buff_t { /* Receive/Transmit buffer header */
|
|||
} buff_t;
|
||||
|
||||
struct dpeth;
|
||||
struct iovec_dat;
|
||||
typedef void (*dp_eth_t) (struct dpeth *);
|
||||
typedef void (*dp_send_recv_t) (struct dpeth *, int, int);
|
||||
typedef void (*dp_eth_t)(struct dpeth *);
|
||||
typedef int (*dp_send_t)(struct dpeth *, struct netdriver_data *, size_t);
|
||||
typedef ssize_t (*dp_recv_t)(struct dpeth *, struct netdriver_data *, size_t);
|
||||
|
||||
#if ENABLE_DP8390 == 1
|
||||
typedef void (*dp_user2nicf_t) (struct dpeth *, int, int);
|
||||
typedef void (*dp_nic2userf_t) (struct dpeth *, int, int);
|
||||
typedef void (*dp_getblock_t) (struct dpeth *, u16_t, int, void *);
|
||||
typedef void (*dp_user2nicf_t)(struct dpeth *, int, struct netdriver_data *,
|
||||
size_t);
|
||||
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
|
||||
|
||||
#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 {
|
||||
/* 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 */
|
||||
|
||||
int de_irq;
|
||||
int de_int_pending;
|
||||
int de_hook; /* interrupt hook at kernel */
|
||||
|
||||
char de_name[8];
|
||||
|
|
@ -117,7 +109,7 @@ typedef struct dpeth {
|
|||
#define DEI_DEFAULT 0x8000
|
||||
|
||||
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_offset_page; /* Offset of shared memory page */
|
||||
|
||||
|
|
@ -129,8 +121,8 @@ typedef struct dpeth {
|
|||
dp_eth_t de_getstatsf;
|
||||
dp_eth_t de_dumpstatsf;
|
||||
dp_eth_t de_interruptf;
|
||||
dp_send_recv_t de_recvf;
|
||||
dp_send_recv_t de_sendf;
|
||||
dp_recv_t de_recvf;
|
||||
dp_send_t de_sendf;
|
||||
|
||||
ether_addr_t de_address; /* Ethernet Address */
|
||||
eth_stat_t de_stat; /* Ethernet Statistics */
|
||||
|
|
@ -141,35 +133,12 @@ typedef struct dpeth {
|
|||
|
||||
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
|
||||
#define DEF_EMPTY 0x00
|
||||
#define DEF_XMIT_BUSY 0x01
|
||||
#define DEF_PROMISC 0x02
|
||||
#define DEF_MULTI 0x04
|
||||
#define DEF_BROAD 0x08
|
||||
|
||||
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
|
||||
/* For use by NS DP8390 driver */
|
||||
port_t de_dp8390_port;
|
||||
|
|
@ -203,8 +172,6 @@ typedef struct dpeth {
|
|||
/* For use by 3Com Etherlink (3c501 and 3c509) driver */
|
||||
buff_t *de_recvq_head;
|
||||
buff_t *de_recvq_tail;
|
||||
buff_t *de_xmitq_head;
|
||||
buff_t *de_xmitq_tail;
|
||||
u16_t de_recv_mode;
|
||||
clock_t de_xmit_start;
|
||||
#endif
|
||||
|
|
@ -215,29 +182,23 @@ typedef struct dpeth {
|
|||
* Function definitions
|
||||
*/
|
||||
|
||||
/* dp.c */
|
||||
void dp_next_iovec(iovec_dat_s_t * iovp);
|
||||
|
||||
/* devio.c */
|
||||
#if defined USE_IOPL
|
||||
#include <machine/portio.h>
|
||||
#else
|
||||
unsigned int inb(unsigned short int);
|
||||
unsigned int inw(unsigned short int);
|
||||
void insb(unsigned short int, endpoint_t, void *, int);
|
||||
void insw(unsigned short int, int, void *, int);
|
||||
void insb(unsigned short int, void *, int);
|
||||
void insw(unsigned short int, void *, int);
|
||||
void outb(unsigned short int, unsigned long);
|
||||
void outw(unsigned short int, unsigned long);
|
||||
void outsb(unsigned short int, endpoint_t, void *, int);
|
||||
void outsw(unsigned short int, int, void *, int);
|
||||
void outsb(unsigned short int, void *, int);
|
||||
#endif
|
||||
|
||||
/* netbuff.c */
|
||||
void *alloc_buff(dpeth_t *, int);
|
||||
void free_buff(dpeth_t *, void *);
|
||||
void init_buff(dpeth_t *, buff_t **);
|
||||
void mem2user(dpeth_t *, buff_t *);
|
||||
void user2mem(dpeth_t *, buff_t *);
|
||||
|
||||
/* 3c501.c */
|
||||
#if ENABLE_3C501 == 1
|
||||
|
|
@ -274,8 +235,4 @@ int wdeth_probe(dpeth_t * dep);
|
|||
#define wdeth_probe(x) (0)
|
||||
#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 **/
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
*/
|
||||
|
||||
#include <minix/drivers.h>
|
||||
#include <minix/netdriver.h>
|
||||
#include <net/gen/ether.h>
|
||||
#include <net/gen/eth_io.h>
|
||||
#include "dp.h"
|
||||
|
|
@ -23,7 +24,7 @@
|
|||
#include "ne.h"
|
||||
|
||||
/*
|
||||
** Name: void ne_reset(dpeth_t * dep);
|
||||
** Name: ne_reset
|
||||
** Function: Resets the board and checks if reset cycle completes
|
||||
*/
|
||||
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));
|
||||
do {
|
||||
if (++count > 10) return FALSE; /* 20 mSecs. timeout */
|
||||
milli_delay(2);
|
||||
micro_delay(2000);
|
||||
} while ((inb_ne(dep, DP_ISR) & ISR_RST) == 0);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
** Name: void ne_close(dpeth_t * dep);
|
||||
** Name: ne_close
|
||||
** Function: Stops the board by resetting it and masking interrupts.
|
||||
*/
|
||||
static void ne_close(dpeth_t * dep)
|
||||
|
|
@ -49,11 +50,10 @@ static void ne_close(dpeth_t * dep)
|
|||
(void)ne_reset(dep);
|
||||
outb_ne(dep, DP_ISR, 0xFF);
|
||||
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.
|
||||
*/
|
||||
static void ne_init(dpeth_t * dep)
|
||||
|
|
@ -90,12 +90,12 @@ static void ne_init(dpeth_t * dep)
|
|||
dep->de_ramsize / 1024,
|
||||
dep->de_base_port, dep->de_irq);
|
||||
for (ix = 0; ix < SA_ADDR_LEN; ix += 1)
|
||||
printf("%02X%c", dep->de_address.ea_addr[ix], ix < SA_ADDR_LEN - 1 ? ':' : '\n');
|
||||
return;
|
||||
printf("%02X%c", dep->de_address.ea_addr[ix],
|
||||
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
|
||||
** whether the board is reachable through the dp8390.
|
||||
** Note that the NE1000 is an 8bit card and has a memory
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
*/
|
||||
|
||||
#include <minix/drivers.h>
|
||||
#include <minix/netdriver.h>
|
||||
#include <net/gen/ether.h>
|
||||
#include <net/gen/eth_io.h>
|
||||
#include "dp.h"
|
||||
|
|
@ -18,7 +19,7 @@ static m_hdr_t *allocptr = NULL;
|
|||
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.
|
||||
*/
|
||||
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;
|
||||
int units = ((size + sizeof(m_hdr_t) - 1) / sizeof(m_hdr_t)) + 1;
|
||||
|
||||
lock();
|
||||
for (ptr = wrk->next;; wrk = ptr, ptr = ptr->next) {
|
||||
if (ptr->size >= units) {
|
||||
/* Memory is available, carve requested size from pool */
|
||||
|
|
@ -39,24 +39,22 @@ void *alloc_buff(dpeth_t *dep, int size)
|
|||
ptr->size = units;
|
||||
}
|
||||
allocptr = wrk;
|
||||
unlock();
|
||||
return ptr + 1;
|
||||
}
|
||||
if (ptr == allocptr) break;
|
||||
}
|
||||
unlock();
|
||||
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.
|
||||
*/
|
||||
void free_buff(dpeth_t *dep, void *blk)
|
||||
{
|
||||
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)
|
||||
if (wrk >= wrk->next && (ptr > wrk || ptr < wrk->next)) break;
|
||||
|
||||
|
|
@ -72,12 +70,10 @@ void free_buff(dpeth_t *dep, void *blk)
|
|||
} else
|
||||
wrk->next = ptr;
|
||||
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.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
||||
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 */
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
*/
|
||||
|
||||
#include <minix/drivers.h>
|
||||
#include <minix/netdriver.h>
|
||||
#include <net/gen/ether.h>
|
||||
#include <net/gen/eth_io.h>
|
||||
#include "dp.h"
|
||||
|
|
@ -43,8 +44,7 @@ static int we_ultra(dpeth_t * dep);
|
|||
/*===========================================================================*
|
||||
* wdeth_probe *
|
||||
*===========================================================================*/
|
||||
int wdeth_probe(dep)
|
||||
dpeth_t *dep;
|
||||
int wdeth_probe(dpeth_t *dep)
|
||||
{
|
||||
int sum;
|
||||
|
||||
|
|
@ -67,8 +67,7 @@ dpeth_t *dep;
|
|||
/*===========================================================================*
|
||||
* we_init *
|
||||
*===========================================================================*/
|
||||
static void we_init(dep)
|
||||
dpeth_t *dep;
|
||||
static void we_init(dpeth_t *dep)
|
||||
{
|
||||
int i, int_indx, int_nr;
|
||||
int tlb, rambit, revision;
|
||||
|
|
@ -212,8 +211,7 @@ dpeth_t *dep;
|
|||
/*===========================================================================*
|
||||
* we_stop *
|
||||
*===========================================================================*/
|
||||
static void we_stop(dep)
|
||||
dpeth_t *dep;
|
||||
static void we_stop(dpeth_t *dep)
|
||||
{
|
||||
|
||||
if (dep->de_16bit) outb_we(dep, EPL_LAAR, E_LAAR_A19 | E_LAAR_LAN16E);
|
||||
|
|
@ -226,8 +224,7 @@ dpeth_t *dep;
|
|||
/*===========================================================================*
|
||||
* we_aliasing *
|
||||
*===========================================================================*/
|
||||
static int we_aliasing(dep)
|
||||
dpeth_t *dep;
|
||||
static int we_aliasing(dpeth_t *dep)
|
||||
{
|
||||
/* Determine whether wd8003 hardware performs register aliasing. This implies
|
||||
* an old WD8003E board. */
|
||||
|
|
@ -243,8 +240,7 @@ dpeth_t *dep;
|
|||
/*===========================================================================*
|
||||
* we_interface_chip *
|
||||
*===========================================================================*/
|
||||
static int we_interface_chip(dep)
|
||||
dpeth_t *dep;
|
||||
static int we_interface_chip(dpeth_t *dep)
|
||||
{
|
||||
/* Determine if the board has an interface chip. */
|
||||
|
||||
|
|
@ -258,8 +254,7 @@ dpeth_t *dep;
|
|||
/*===========================================================================*
|
||||
* we_16bitboard *
|
||||
*===========================================================================*/
|
||||
static int we_16bitboard(dep)
|
||||
dpeth_t *dep;
|
||||
static int we_16bitboard(dpeth_t *dep)
|
||||
{
|
||||
/* 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
|
||||
|
|
@ -286,8 +281,7 @@ dpeth_t *dep;
|
|||
/*===========================================================================*
|
||||
* we_16bitslot *
|
||||
*===========================================================================*/
|
||||
static int we_16bitslot(dep)
|
||||
dpeth_t *dep;
|
||||
static int we_16bitslot(dpeth_t *dep)
|
||||
{
|
||||
/* Determine if the 16 bit board in plugged into a 16 bit slot. */
|
||||
|
||||
|
|
@ -297,8 +291,7 @@ dpeth_t *dep;
|
|||
/*===========================================================================*
|
||||
* we_ultra *
|
||||
*===========================================================================*/
|
||||
static int we_ultra(dep)
|
||||
dpeth_t *dep;
|
||||
static int we_ultra(dpeth_t *dep)
|
||||
{
|
||||
/* Determine if we has an '790 chip. */
|
||||
u8_t tlb;
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ FILES=$(PROG).conf
|
|||
FILESNAME=$(PROG)
|
||||
FILESDIR= /etc/system.conf.d
|
||||
|
||||
DPADD+= ${LIBNETDRIVER} ${LIBSYS} ${LIBTIMERS}
|
||||
LDADD+= -lnetdriver -lsys -ltimers
|
||||
DPADD+= ${LIBNETDRIVER} ${LIBSYS}
|
||||
LDADD+= -lnetdriver -lsys
|
||||
|
||||
.include <minix.service.mk>
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -18,13 +18,6 @@
|
|||
#ifndef __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"
|
||||
|
||||
/**
|
||||
|
|
@ -38,14 +31,11 @@
|
|||
/** Number of transmit descriptors per card. */
|
||||
#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. */
|
||||
#define E1000_IOBUF_SIZE 2048
|
||||
|
||||
/** Debug verbosity. */
|
||||
#define E1000_VERBOSE 1
|
||||
#define E1000_VERBOSE 0
|
||||
|
||||
/** MAC address override variable. */
|
||||
#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
|
||||
{
|
||||
char name[8]; /**< String containing the device name. */
|
||||
int status; /**< Describes the card's current state. */
|
||||
int irq; /**< Interrupt Request Vector. */
|
||||
int irq_hook; /**< Interrupt Request Vector Hook. */
|
||||
int revision; /**< Hardware Revision Number. */
|
||||
u8_t *regs; /**< Memory mapped hardware registers. */
|
||||
u8_t *flash; /**< Optional flash memory. */
|
||||
u32_t flash_base_addr; /**< Flash base address. */
|
||||
ether_addr_t address; /**< Ethernet MAC address. */
|
||||
u16_t (*eeprom_read)(void *, int reg); /**< Function to read
|
||||
the EEPROM. */
|
||||
u16_t (*eeprom_read)(struct e1000 *, int reg);
|
||||
/**< Function to read the EEPROM. */
|
||||
int eeprom_done_bit; /**< Offset of the EERD.DONE bit. */
|
||||
int eeprom_addr_off; /**< Offset of the EERD.ADDR field. */
|
||||
|
||||
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. */
|
||||
char *rx_buffer; /**< Receive buffer returned by malloc(). */
|
||||
int rx_buffer_size; /**< Size of the receive buffer. */
|
||||
|
||||
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. */
|
||||
char *tx_buffer; /**< Transmit buffer returned by malloc(). */
|
||||
int tx_buffer_size; /**< Size of the transmit buffer. */
|
||||
|
||||
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;
|
||||
} e1000_t;
|
||||
|
||||
#endif /* __E1000_H */
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ FILES=$(PROG).conf
|
|||
FILESNAME=$(PROG)
|
||||
FILESDIR= /etc/system.conf.d
|
||||
|
||||
DPADD+= ${LIBNETDRIVER} ${LIBSYS} ${LIBTIMERS}
|
||||
LDADD+= -lnetdriver -lsys -ltimers
|
||||
DPADD+= ${LIBNETDRIVER} ${LIBSYS}
|
||||
LDADD+= -lnetdriver -lsys
|
||||
|
||||
.include <minix.service.mk>
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -6,7 +6,7 @@ FILES=$(PROG).conf
|
|||
FILESNAME=$(PROG)
|
||||
FILESDIR= /etc/system.conf.d
|
||||
|
||||
DPADD+= ${LIBNETDRIVER} ${LIBSYS} ${LIBTIMERS}
|
||||
LDADD+= -lnetdriver -lsys -ltimers
|
||||
DPADD+= ${LIBNETDRIVER} ${LIBSYS}
|
||||
LDADD+= -lnetdriver -lsys
|
||||
|
||||
.include <minix.service.mk>
|
||||
|
|
|
|||
|
|
@ -1,31 +1,28 @@
|
|||
#include <minix/drivers.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 <sys/mman.h>
|
||||
#include "assert.h"
|
||||
#include "lan8710a.h"
|
||||
#include "lan8710a_reg.h"
|
||||
|
||||
/* Local functions */
|
||||
static void lan8710a_readv_s(message *m, int from_int);
|
||||
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 int lan8710a_init(unsigned int instance, ether_addr_t *addr);
|
||||
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_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_mdio(void);
|
||||
static int lan8710a_init_hw(void);
|
||||
static void lan8710a_reset_hw();
|
||||
static int lan8710a_init_hw(ether_addr_t *addr);
|
||||
static void lan8710a_reset_hw(void);
|
||||
|
||||
static void lan8710a_phy_write(u32_t reg, u32_t value);
|
||||
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_unset(volatile u32_t *reg, u32_t value);
|
||||
|
||||
static void mess_reply(message *req, message *reply);
|
||||
static void reply(lan8710a_t *e);
|
||||
|
||||
/* Local variables */
|
||||
static lan8710a_t lan8710a_state;
|
||||
|
||||
/* SEF functions and variables. */
|
||||
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 signal);
|
||||
static const struct netdriver lan8710a_table = {
|
||||
.ndr_init = lan8710a_init,
|
||||
.ndr_stop = lan8710a_stop,
|
||||
.ndr_recv = lan8710a_recv,
|
||||
.ndr_send = lan8710a_send,
|
||||
.ndr_stat = lan8710a_stat,
|
||||
.ndr_intr = lan8710a_intr
|
||||
};
|
||||
|
||||
/*============================================================================*
|
||||
* main *
|
||||
|
|
@ -52,122 +50,45 @@ static void sef_cb_signal_handler(int signal);
|
|||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
|
||||
/* Local variables */
|
||||
message m;
|
||||
int r;
|
||||
int ipc_status;
|
||||
struct machine machine ;
|
||||
struct machine machine;
|
||||
|
||||
env_setargs(argc, argv);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/*============================================================================*
|
||||
* 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 *
|
||||
* lan8710a_init *
|
||||
*============================================================================*/
|
||||
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. */
|
||||
long v = 0;
|
||||
|
||||
/* Clear 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. */
|
||||
lan8710a_init();
|
||||
lan8710a_map_regs();
|
||||
|
||||
/* Get instance of ethernet device */
|
||||
env_parse("instance", "d", 0, &v, 0, 255);
|
||||
lan8710a_state.instance = (int) v;
|
||||
|
||||
/* Announce we are up! */
|
||||
netdriver_announce();
|
||||
lan8710a_init_hw(addr);
|
||||
|
||||
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 *
|
||||
*============================================================================*/
|
||||
static void
|
||||
lan8710a_enable_interrupt(interrupt)
|
||||
u8_t interrupt;
|
||||
lan8710a_enable_interrupt(int interrupt)
|
||||
{
|
||||
int r;
|
||||
|
||||
|
|
@ -182,14 +103,13 @@ u8_t interrupt;
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*============================================================================*
|
||||
* lan8710a_interrupt *
|
||||
* lan8710a_intr *
|
||||
*============================================================================*/
|
||||
static void
|
||||
lan8710a_interrupt(m)
|
||||
message *m;
|
||||
lan8710a_intr(unsigned int mask)
|
||||
{
|
||||
lan8710a_t *e = &lan8710a_state;
|
||||
u32_t dma_status;
|
||||
|
||||
/* Check the card for interrupt reason(s). */
|
||||
|
|
@ -201,7 +121,7 @@ message *m;
|
|||
if (rx_stat) {
|
||||
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_EOI_VECTOR, RX_INT);
|
||||
|
|
@ -212,7 +132,7 @@ message *m;
|
|||
/* Disabling channels, where Tx interrupt occurred */
|
||||
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_EOI_VECTOR, TX_INT);
|
||||
|
|
@ -226,61 +146,19 @@ message *m;
|
|||
}
|
||||
|
||||
/* Re-enable Rx interrupt. */
|
||||
if(m->m_notify.interrupts & (1 << RX_INT))
|
||||
if (mask & (1 << RX_INT))
|
||||
lan8710a_enable_interrupt(RX_INT);
|
||||
|
||||
/* Re-enable Tx interrupt. */
|
||||
if(m->m_notify.interrupts & (1 << TX_INT))
|
||||
if (mask & (1 << 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 *
|
||||
*============================================================================*/
|
||||
static void
|
||||
lan8710a_init_addr(void)
|
||||
lan8710a_init_addr(ether_addr_t * addr)
|
||||
{
|
||||
static char eakey[]= LAN8710A_ENVVAR "#_EA";
|
||||
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)
|
||||
break;
|
||||
else
|
||||
lan8710a_state.address.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);
|
||||
addr->ea_addr[i] = v;
|
||||
}
|
||||
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
|
||||
lan8710a_getstat(mp)
|
||||
message *mp;
|
||||
lan8710a_stat(eth_stat_t * stat)
|
||||
{
|
||||
int r;
|
||||
eth_stat_t stats;
|
||||
|
||||
stats.ets_recvErr = lan8710a_reg_read(CPSW_STAT_RX_CRC_ERR)
|
||||
stat->ets_recvErr = lan8710a_reg_read(CPSW_STAT_RX_CRC_ERR)
|
||||
+ lan8710a_reg_read(CPSW_STAT_RX_AGNCD_ERR)
|
||||
+ lan8710a_reg_read(CPSW_STAT_RX_OVERSIZE);
|
||||
stats.ets_sendErr = 0;
|
||||
stats.ets_OVW = 0;
|
||||
stats.ets_CRCerr = lan8710a_reg_read(CPSW_STAT_RX_CRC_ERR);
|
||||
stats.ets_frameAll = lan8710a_reg_read(CPSW_STAT_RX_AGNCD_ERR);
|
||||
stats.ets_missedP = 0;
|
||||
stats.ets_packetR = lan8710a_reg_read(CPSW_STAT_RX_GOOD);
|
||||
stats.ets_packetT = lan8710a_reg_read(CPSW_STAT_TX_GOOD);
|
||||
stats.ets_collision = lan8710a_reg_read(CPSW_STAT_COLLISIONS);
|
||||
stats.ets_transAb = 0;
|
||||
stats.ets_carrSense = lan8710a_reg_read(CPSW_STAT_CARR_SENS_ERR);
|
||||
stats.ets_fifoUnder = lan8710a_reg_read(CPSW_STAT_TX_UNDERRUN);
|
||||
stats.ets_fifoOver = lan8710a_reg_read(CPSW_STAT_RX_OVERRUN);
|
||||
stats.ets_CDheartbeat = 0;
|
||||
stats.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);
|
||||
}
|
||||
stat->ets_sendErr = 0;
|
||||
stat->ets_OVW = 0;
|
||||
stat->ets_CRCerr = lan8710a_reg_read(CPSW_STAT_RX_CRC_ERR);
|
||||
stat->ets_frameAll = lan8710a_reg_read(CPSW_STAT_RX_AGNCD_ERR);
|
||||
stat->ets_missedP = 0;
|
||||
stat->ets_packetR = lan8710a_reg_read(CPSW_STAT_RX_GOOD);
|
||||
stat->ets_packetT = lan8710a_reg_read(CPSW_STAT_TX_GOOD);
|
||||
stat->ets_collision = lan8710a_reg_read(CPSW_STAT_COLLISIONS);
|
||||
stat->ets_transAb = 0;
|
||||
stat->ets_carrSense = lan8710a_reg_read(CPSW_STAT_CARR_SENS_ERR);
|
||||
stat->ets_fifoUnder = lan8710a_reg_read(CPSW_STAT_TX_UNDERRUN);
|
||||
stat->ets_fifoOver = lan8710a_reg_read(CPSW_STAT_RX_OVERRUN);
|
||||
stat->ets_CDheartbeat = 0;
|
||||
stat->ets_OWC = 0;
|
||||
}
|
||||
|
||||
/*============================================================================*
|
||||
|
|
@ -455,17 +319,13 @@ lan8710a_stop(void)
|
|||
{
|
||||
/* Reset hardware. */
|
||||
lan8710a_reset_hw();
|
||||
|
||||
/* Exit driver. */
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
/*============================================================================*
|
||||
* lan8710a_dma_config_tx *
|
||||
*============================================================================*/
|
||||
static void
|
||||
lan8710a_dma_config_tx(desc_idx)
|
||||
u8_t desc_idx;
|
||||
lan8710a_dma_config_tx(u8_t desc_idx)
|
||||
{
|
||||
phys_bytes phys_addr;
|
||||
int i;
|
||||
|
|
@ -585,12 +445,10 @@ lan8710a_init_desc(void)
|
|||
* lan8710a_init_hw *
|
||||
*============================================================================*/
|
||||
static int
|
||||
lan8710a_init_hw(void)
|
||||
lan8710a_init_hw(ether_addr_t * addr)
|
||||
{
|
||||
int r, i;
|
||||
|
||||
lan8710a_state.status |= LAN8710A_ENABLED;
|
||||
|
||||
/*
|
||||
* Set the interrupt handler and policy. Do not automatically
|
||||
* re-enable interrupts. Return the IRQ line number on interrupts.
|
||||
|
|
@ -757,7 +615,7 @@ lan8710a_init_hw(void)
|
|||
lan8710a_init_mdio();
|
||||
|
||||
/* Getting MAC Address */
|
||||
lan8710a_init_addr();
|
||||
lan8710a_init_addr(addr);
|
||||
|
||||
/* Initialize descriptors */
|
||||
lan8710a_init_desc();
|
||||
|
|
@ -825,244 +683,145 @@ lan8710a_init_mdio(void)
|
|||
}
|
||||
|
||||
/*============================================================================*
|
||||
* lan8710a_writev_s *
|
||||
* lan8710a_send *
|
||||
*============================================================================*/
|
||||
static void
|
||||
lan8710a_writev_s(mp, from_int)
|
||||
message *mp;
|
||||
int from_int;
|
||||
static int
|
||||
lan8710a_send(struct netdriver_data * data, size_t size)
|
||||
{
|
||||
iovec_s_t iovec[LAN8710A_IOVEC_NR];
|
||||
lan8710a_t *e = &lan8710a_state;
|
||||
lan8710a_desc_t *p_tx_desc;
|
||||
u8_t *p_buf;
|
||||
int r, size, buf_data_len, i;
|
||||
u8_t *buf;
|
||||
|
||||
/* Are we called from the interrupt handler? */
|
||||
if (!from_int) {
|
||||
/* We cannot write twice simultaneously. */
|
||||
assert(!(e->status & LAN8710A_WRITING));
|
||||
/* setup descriptors */
|
||||
p_tx_desc = &(e->tx_desc[e->tx_desc_idx]);
|
||||
|
||||
/* Copy write message. */
|
||||
e->tx_message = *mp;
|
||||
e->client = mp->m_source;
|
||||
e->status |= LAN8710A_WRITING;
|
||||
/*
|
||||
* Check if descriptor is available for host and suspend if not.
|
||||
*/
|
||||
if (LAN8710A_DESC_FLAG_OWN & p_tx_desc->pkt_len_flags)
|
||||
return SUSPEND;
|
||||
|
||||
/* verify vector count */
|
||||
assert(mp->m_net_netdrv_dl_writev_s.count > 0);
|
||||
assert(mp->m_net_netdrv_dl_writev_s.count < LAN8710A_IOVEC_NR);
|
||||
/* Drop packets that exceed the size of our transmission buffer. */
|
||||
if (size > LAN8710A_IOBUF_SIZE) {
|
||||
printf("%s: dropping large packet (%zu)\n", e->name, size);
|
||||
|
||||
/*
|
||||
* 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;
|
||||
return OK;
|
||||
}
|
||||
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
|
||||
lan8710a_readv_s(mp, from_int)
|
||||
message *mp;
|
||||
int from_int;
|
||||
static ssize_t
|
||||
lan8710a_recv(struct netdriver_data * data, size_t max)
|
||||
{
|
||||
iovec_s_t iovec[LAN8710A_IOVEC_NR];
|
||||
lan8710a_t *e = &lan8710a_state;
|
||||
lan8710a_desc_t *p_rx_desc;
|
||||
u32_t flags;
|
||||
u8_t *p_buf;
|
||||
u16_t pkt_data_len;
|
||||
u16_t buf_bytes, buf_len;
|
||||
int i, r, size;
|
||||
u32_t flags;
|
||||
u8_t *buf;
|
||||
size_t off, size, chunk;
|
||||
|
||||
/* Are we called from the interrupt handler? */
|
||||
if (!from_int) {
|
||||
e->rx_message = *mp;
|
||||
e->client = mp->m_source;
|
||||
e->status |= LAN8710A_READING;
|
||||
e->rx_size = 0;
|
||||
/*
|
||||
* Only handle one packet at a time.
|
||||
*/
|
||||
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;
|
||||
|
||||
assert(e->rx_message.m_net_netdrv_dl_readv_s.count > 0);
|
||||
assert(e->rx_message.m_net_netdrv_dl_readv_s.count < LAN8710A_IOVEC_NR);
|
||||
}
|
||||
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.
|
||||
*/
|
||||
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]);
|
||||
/* 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 *
|
||||
*============================================================================*/
|
||||
static void
|
||||
lan8710a_phy_write(reg, value)
|
||||
u32_t reg;
|
||||
u32_t value;
|
||||
lan8710a_phy_write(u32_t reg, u32_t value)
|
||||
{
|
||||
if (!(lan8710a_reg_read(MDIOUSERACCESS0) & MDIO_GO)) {
|
||||
/* Clearing MDIOUSERACCESS0 register */
|
||||
|
|
@ -1073,7 +832,8 @@ u32_t value;
|
|||
lan8710a_reg_set(MDIOUSERACCESS0,
|
||||
lan8710a_state.phy_address << MDIO_PHYADR);
|
||||
/* 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);
|
||||
|
||||
/* Waiting for writing completion */
|
||||
|
|
@ -1085,8 +845,7 @@ u32_t value;
|
|||
* lan8710a_phy_read *
|
||||
*============================================================================*/
|
||||
static u32_t
|
||||
lan8710a_phy_read(reg)
|
||||
u32_t reg;
|
||||
lan8710a_phy_read(u32_t reg)
|
||||
{
|
||||
u32_t value = 0xFFFFFFFF;
|
||||
|
||||
|
|
@ -1116,7 +875,7 @@ u32_t reg;
|
|||
* lan8710a_reset_hw *
|
||||
*============================================================================*/
|
||||
static void
|
||||
lan8710a_reset_hw()
|
||||
lan8710a_reset_hw(void)
|
||||
{
|
||||
/* Assert a Device Reset signal. */
|
||||
lan8710a_phy_write(LAN8710A_CTRL_REG, LAN8710A_SOFT_RESET);
|
||||
|
|
@ -1129,8 +888,7 @@ lan8710a_reset_hw()
|
|||
* lan8710a_reg_read *
|
||||
*============================================================================*/
|
||||
static u32_t
|
||||
lan8710a_reg_read(reg)
|
||||
volatile u32_t *reg;
|
||||
lan8710a_reg_read(volatile u32_t *reg)
|
||||
{
|
||||
u32_t value;
|
||||
|
||||
|
|
@ -1145,9 +903,7 @@ volatile u32_t *reg;
|
|||
* lan8710a_reg_write *
|
||||
*============================================================================*/
|
||||
static void
|
||||
lan8710a_reg_write(reg, value)
|
||||
volatile u32_t *reg;
|
||||
u32_t value;
|
||||
lan8710a_reg_write(volatile u32_t *reg, u32_t value)
|
||||
{
|
||||
/* Write to memory mapped register. */
|
||||
*reg = value;
|
||||
|
|
@ -1157,9 +913,7 @@ u32_t value;
|
|||
* lan8710a_reg_set *
|
||||
*============================================================================*/
|
||||
static void
|
||||
lan8710a_reg_set(reg, value)
|
||||
volatile u32_t *reg;
|
||||
u32_t value;
|
||||
lan8710a_reg_set(volatile u32_t *reg, u32_t value)
|
||||
{
|
||||
u32_t data;
|
||||
|
||||
|
|
@ -1174,9 +928,7 @@ u32_t value;
|
|||
* lan8710a_reg_unset *
|
||||
*============================================================================*/
|
||||
static void
|
||||
lan8710a_reg_unset(reg, value)
|
||||
volatile u32_t *reg;
|
||||
u32_t value;
|
||||
lan8710a_reg_unset(volatile u32_t *reg, u32_t value)
|
||||
{
|
||||
u32_t data;
|
||||
|
||||
|
|
@ -1186,61 +938,3 @@ u32_t value;
|
|||
/* Unset value, and write back. */
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,26 +16,9 @@
|
|||
#define LAN8710A_DEBUG_PRINT(args)
|
||||
#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 */
|
||||
#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 */
|
||||
#define LAN8710A_DESC_FLAG_OWN (1 << 29) /* ownership flag */
|
||||
#define LAN8710A_DESC_FLAG_SOP (1 << 31) /* start of packet flag */
|
||||
|
|
@ -58,9 +41,6 @@
|
|||
/** Number of receive descriptors */
|
||||
#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. */
|
||||
#define LAN8710A_IOBUF_SIZE (1520)
|
||||
|
||||
|
|
@ -89,11 +69,9 @@ typedef struct lan8710a_t
|
|||
phys_bytes rx_desc_phy;
|
||||
phys_bytes tx_desc_phy;
|
||||
char name[LAN8710A_NAME_LEN];
|
||||
int status;
|
||||
int irq_rx_hook; /* Rx interrupt Request Vector Hook. */
|
||||
int irq_tx_hook; /* Tx interrupt Request Vector Hook. */
|
||||
int instance;
|
||||
ether_addr_t address; /* Ethernet MAC address. */
|
||||
u8_t *regs;
|
||||
u32_t phy_address;
|
||||
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 rx_desc_idx; /* index of the next receive desciptor */
|
||||
int client;
|
||||
message tx_message;
|
||||
message rx_message;
|
||||
unsigned int rx_size;
|
||||
|
||||
/* register mapping */
|
||||
vir_bytes regs_cp_per;
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,39 +1,8 @@
|
|||
|
||||
/* macros for 'mode' */
|
||||
#define EC_DISABLED 0x0
|
||||
#define EC_SINK 0x1
|
||||
#define EC_ENABLED 0x2
|
||||
|
||||
/* macros for 'flags' */
|
||||
#define ECF_EMPTY 0x000
|
||||
#define ECF_PACK_SEND 0x001
|
||||
#define ECF_PACK_RECV 0x002
|
||||
#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;
|
||||
#define ECF_PROMISC 0x01
|
||||
#define ECF_MULTI 0x02
|
||||
#define ECF_BROAD 0x04
|
||||
|
||||
/* ====== ethernet card info. ====== */
|
||||
typedef struct ether_card
|
||||
|
|
@ -41,35 +10,14 @@ typedef struct ether_card
|
|||
/* ####### MINIX style ####### */
|
||||
char port_name[sizeof("lance#n")];
|
||||
int flags;
|
||||
int mode;
|
||||
int transfer_mode;
|
||||
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. ####### */
|
||||
port_t ec_port;
|
||||
phys_bytes ec_linmem;
|
||||
int ec_irq;
|
||||
int ec_int_pending;
|
||||
int ec_hook;
|
||||
|
||||
int ec_ramsize;
|
||||
|
||||
/* Addrassing */
|
||||
u16_t ec_memseg;
|
||||
vir_bytes ec_memoff;
|
||||
|
||||
ether_addr_t mac_address;
|
||||
} ether_card_t;
|
||||
|
||||
#define DEI_DEFAULT 0x8000
|
||||
|
||||
/*
|
||||
* NOTE: Not all the CSRs are defined. Just the ones that were deemed
|
||||
* necessary or potentially useful.
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@
|
|||
PROG= orinoco
|
||||
SRCS= orinoco.c hermes.c
|
||||
|
||||
DPADD+= ${LIBNETDRIVER} ${LIBSYS} ${LIBTIMERS}
|
||||
LDADD+= -lnetdriver -lsys -ltimers
|
||||
DPADD+= ${LIBNETDRIVER} ${LIBSYS}
|
||||
LDADD+= -lnetdriver -lsys
|
||||
|
||||
CPPFLAGS.orinoco.c+= -I${NETBSDSRCDIR}/minix
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -26,74 +26,39 @@ typedef struct s_or
|
|||
{
|
||||
int or_irq;
|
||||
int or_hook_id;
|
||||
int or_mode;
|
||||
int or_flags;
|
||||
char *or_model;
|
||||
int or_client;
|
||||
int or_link_up;
|
||||
int or_got_int;
|
||||
int or_tx_alive;
|
||||
int or_send_int;
|
||||
int or_clear_rx;
|
||||
u32_t or_base_port;
|
||||
int or_need_reset;
|
||||
int or_report_link;
|
||||
|
||||
/* Events */
|
||||
int or_ev_rx;
|
||||
int or_ev_tx;
|
||||
int or_ev_info;
|
||||
int or_ev_txexc;
|
||||
int or_ev_alloc;
|
||||
int connected;
|
||||
u16_t channel_mask;
|
||||
u16_t channel;
|
||||
u16_t ap_density;
|
||||
u16_t rts_thresh;
|
||||
int bitratemode;
|
||||
int last_linkstatus;
|
||||
int max_data_len;
|
||||
int port_type;
|
||||
|
||||
/* Rx */
|
||||
phys_bytes or_rx_buf;
|
||||
vir_bytes or_read_s;
|
||||
u16_t rxfid[NR_RX_BUFS];
|
||||
int rx_length[NR_RX_BUFS];
|
||||
u8_t rx_buf[NR_RX_BUFS][IEEE802_11_FRAME_LEN];
|
||||
u8_t rx_offset[NR_RX_BUFS];
|
||||
int rx_first;
|
||||
int rx_last;
|
||||
int rx_current;
|
||||
|
||||
/* Tx */
|
||||
u16_t or_nicbuf_size;
|
||||
vir_bytes or_transm_s;
|
||||
int or_tx_head;
|
||||
int or_tx_tail;
|
||||
int or_tx_busy;
|
||||
|
||||
struct
|
||||
{
|
||||
int ret_busy;
|
||||
u16_t or_txfid;
|
||||
} 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;
|
||||
message or_rx_mess;
|
||||
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)];
|
||||
char or_name[sizeof(OR_NAME)];
|
||||
hermes_t hw;
|
||||
char nick[IW_ESSID_MAX_SIZE + 1];
|
||||
|
||||
|
||||
} t_or;
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
# Makefile for the Realtek RTL8139 ethernet driver (RTL8139)
|
||||
PROG= rtl8139
|
||||
SRCS= rtl8139.c liveupdate.c
|
||||
SRCS= rtl8139.c
|
||||
|
||||
FILES=$(PROG).conf
|
||||
FILESNAME=$(PROG)
|
||||
FILESDIR= /etc/system.conf.d
|
||||
|
||||
DPADD+= ${LIBNETDRIVER} ${LIBSYS} ${LIBTIMERS}
|
||||
LDADD+= -lnetdriver -lsys -ltimers
|
||||
DPADD+= ${LIBNETDRIVER} ${LIBSYS}
|
||||
LDADD+= -lnetdriver -lsys
|
||||
|
||||
CPPFLAGS+= -I${NETBSDSRCDIR}/minix
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
/* Code left here for historical purposes only. TODO: move into libnetdriver */
|
||||
|
||||
#include "rtl8139.h"
|
||||
|
||||
/* State management variables. */
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -6,32 +6,9 @@ Created: Aug 2003 by Philip Homburg <philip@cs.vu.nl>
|
|||
|
||||
#include <minix/drivers.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 <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#include <minix/ds.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
|
||||
* Note: RL_9346CR_EEM_CONFIG mode is
|
||||
|
|
@ -453,18 +430,12 @@ d8 R/W Config5 Configuration register 5
|
|||
d9-ff reserved
|
||||
#endif
|
||||
|
||||
#define Proc_number(p) proc_number(p)
|
||||
#define debug 0
|
||||
#define printW() ((void)0)
|
||||
#define vm_1phys2bus(p) (p)
|
||||
|
||||
#define RX_BUFSIZE RL_RCR_RBLEN_64K_SIZE
|
||||
#define RX_BUFBITS RL_RCR_RBLEN_64K
|
||||
#define N_TX_BUF RL_N_TX
|
||||
|
||||
/* I/O vectors are handled IOVEC_NR entries at a time. */
|
||||
#define IOVEC_NR 16
|
||||
|
||||
/* Configuration */
|
||||
#define RL_ENVVAR "RTLETH"
|
||||
|
||||
|
|
@ -473,8 +444,6 @@ typedef struct re
|
|||
port_t re_base_port;
|
||||
int re_irq;
|
||||
int re_mode;
|
||||
int re_flags;
|
||||
int re_client;
|
||||
int re_link_up;
|
||||
int re_got_int;
|
||||
int re_send_int;
|
||||
|
|
@ -482,12 +451,12 @@ typedef struct re
|
|||
int re_clear_rx;
|
||||
int re_need_reset;
|
||||
int re_tx_alive;
|
||||
char *re_model;
|
||||
int re_tx_busy;
|
||||
const char *re_model;
|
||||
|
||||
/* Rx */
|
||||
phys_bytes re_rx_buf;
|
||||
char *v_re_rx_buf;
|
||||
vir_bytes re_read_s;
|
||||
|
||||
/* Tx */
|
||||
int re_tx_head;
|
||||
|
|
@ -500,33 +469,10 @@ typedef struct re
|
|||
} re_tx[N_TX_BUF];
|
||||
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 */
|
||||
eth_stat_t re_stat;
|
||||
ether_addr_t re_address;
|
||||
message re_rx_mess;
|
||||
message re_tx_mess;
|
||||
char re_name[sizeof("rtl8139#n")];
|
||||
iovec_t re_iovec[IOVEC_NR];
|
||||
iovec_s_t re_iovec_s[IOVEC_NR];
|
||||
}
|
||||
re_t;
|
||||
|
||||
#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
|
||||
} re_t;
|
||||
|
||||
/*
|
||||
* $PchId: rtl8139.h,v 1.1 2003/09/05 10:58:50 philip Exp $
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@ FILES=$(PROG).conf
|
|||
FILESNAME=$(PROG)
|
||||
FILESDIR= /etc/system.conf.d
|
||||
|
||||
DPADD+= ${LIBNETDRIVER} ${LIBSYS} ${LIBTIMERS}
|
||||
LDADD+= -lnetdriver -lsys -ltimers
|
||||
DPADD+= ${LIBNETDRIVER} ${LIBSYS}
|
||||
LDADD+= -lnetdriver -lsys
|
||||
|
||||
CPPFLAGS+= -I${NETBSDSRCDIR}/minix
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -22,11 +22,18 @@
|
|||
|
||||
#include "virtio_net.h"
|
||||
|
||||
#define VERBOSE 0
|
||||
|
||||
#if VERBOSE
|
||||
#define dput(s) do { dprintf(s); printf("\n"); } while (0)
|
||||
#define dprintf(s) do { \
|
||||
printf("%s: ", name); \
|
||||
printf s; \
|
||||
} while (0)
|
||||
#else
|
||||
#define dput(s)
|
||||
#define dprintf(s)
|
||||
#endif
|
||||
|
||||
static struct virtio_device *net_dev;
|
||||
|
||||
|
|
@ -50,6 +57,7 @@ struct packet {
|
|||
phys_bytes phdr;
|
||||
char *vdata;
|
||||
phys_bytes pdata;
|
||||
size_t len;
|
||||
STAILQ_ENTRY(packet) next;
|
||||
};
|
||||
|
||||
|
|
@ -60,7 +68,6 @@ static struct virtio_net_hdr *hdrs_vir;
|
|||
static phys_bytes hdrs_phys;
|
||||
static struct packet *packets;
|
||||
static int in_rx;
|
||||
static int started;
|
||||
|
||||
/* Packets on this list can be given to the host */
|
||||
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 */
|
||||
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 */
|
||||
static u8_t virtio_net_mac[6];
|
||||
static eth_stat_t virtio_net_stats;
|
||||
static int spurious_interrupt;
|
||||
|
||||
|
||||
/* Prototypes */
|
||||
static int virtio_net_probe(int skip);
|
||||
static int virtio_net_config(void);
|
||||
static int virtio_net_probe(unsigned int skip);
|
||||
static void virtio_net_config(ether_addr_t *addr);
|
||||
static int virtio_net_alloc_bufs(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_pending(void);
|
||||
|
||||
static void virtio_net_fetch_iovec(iovec_s_t *iov, message *m,
|
||||
cp_grant_id_t grant, size_t count);
|
||||
static int virtio_net_cpy_to_user(message *m);
|
||||
static int virtio_net_cpy_from_user(message *m);
|
||||
|
||||
static void virtio_net_intr(message *m);
|
||||
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 int virtio_net_init(unsigned int instance, ether_addr_t *addr);
|
||||
static void virtio_net_stop(void);
|
||||
static int virtio_net_send(struct netdriver_data *data, size_t len);
|
||||
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(unsigned int mask);
|
||||
|
||||
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 */
|
||||
struct virtio_feature netf[] = {
|
||||
static struct virtio_feature netf[] = {
|
||||
{ "partial csum", VIRTIO_NET_F_CSUM, 0, 0 },
|
||||
{ "given mac", VIRTIO_NET_F_MAC, 0, 1 },
|
||||
{ "status ", VIRTIO_NET_F_STATUS, 0, 0 },
|
||||
|
|
@ -120,7 +115,7 @@ struct virtio_feature netf[] = {
|
|||
};
|
||||
|
||||
static int
|
||||
virtio_net_probe(int skip)
|
||||
virtio_net_probe(unsigned int skip)
|
||||
{
|
||||
/* virtio-net has at least 2 queues */
|
||||
int queues = 2;
|
||||
|
|
@ -142,8 +137,8 @@ virtio_net_probe(int skip)
|
|||
return OK;
|
||||
}
|
||||
|
||||
static int
|
||||
virtio_net_config(void)
|
||||
static void
|
||||
virtio_net_config(ether_addr_t * addr)
|
||||
{
|
||||
u32_t mac14;
|
||||
u32_t mac56;
|
||||
|
|
@ -153,12 +148,12 @@ virtio_net_config(void)
|
|||
dprintf(("Mac set by host: "));
|
||||
mac14 = virtio_sread32(net_dev, 0);
|
||||
mac56 = virtio_sread32(net_dev, 4);
|
||||
*(u32_t*)virtio_net_mac = mac14;
|
||||
*(u16_t*)(virtio_net_mac + 4) = mac56;
|
||||
memcpy(&addr->ea_addr[0], &mac14, 4);
|
||||
memcpy(&addr->ea_addr[4], &mac56, 2);
|
||||
|
||||
for (i = 0; i < 6; i++)
|
||||
printf("%02x%s", virtio_net_mac[i],
|
||||
i == 5 ? "\n" : ":");
|
||||
dprintf(("%02x%s", addr->ea_addr[i],
|
||||
i == 5 ? "\n" : ":"));
|
||||
} else {
|
||||
dput(("No mac"));
|
||||
}
|
||||
|
|
@ -174,8 +169,6 @@ virtio_net_config(void)
|
|||
|
||||
if (virtio_host_supports(net_dev, VIRTIO_NET_F_CTRL_RX))
|
||||
dput(("Host supports control channel for RX"));
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
@ -233,7 +226,6 @@ virtio_net_refill_rx_queue(void)
|
|||
struct packet *p;
|
||||
|
||||
while ((in_rx < BUF_PACKETS / 2) && !STAILQ_EMPTY(&free_list)) {
|
||||
|
||||
/* peek */
|
||||
p = STAILQ_FIRST(&free_list);
|
||||
/* remove */
|
||||
|
|
@ -253,7 +245,6 @@ virtio_net_refill_rx_queue(void)
|
|||
|
||||
virtio_to_queue(net_dev, RX_Q, phys, 2, p);
|
||||
in_rx++;
|
||||
|
||||
}
|
||||
|
||||
if (in_rx == 0 && STAILQ_EMPTY(&free_list)) {
|
||||
|
|
@ -266,18 +257,21 @@ static void
|
|||
virtio_net_check_queues(void)
|
||||
{
|
||||
struct packet *p;
|
||||
size_t len;
|
||||
|
||||
/* 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);
|
||||
in_rx--;
|
||||
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.
|
||||
*/
|
||||
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->vdata, 0, MAX_PACK_SIZE);
|
||||
STAILQ_INSERT_HEAD(&free_list, p, next);
|
||||
|
|
@ -288,173 +282,19 @@ virtio_net_check_queues(void)
|
|||
static 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? */
|
||||
if (!STAILQ_EMPTY(&recv_list) && rx_pending) {
|
||||
dst = pending_rx_msg.m_source;
|
||||
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(&recv_list))
|
||||
netdriver_recv();
|
||||
|
||||
if (!STAILQ_EMPTY(&free_list) && tx_pending) {
|
||||
dst = pending_tx_msg.m_source;
|
||||
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);
|
||||
if (!STAILQ_EMPTY(&free_list))
|
||||
netdriver_send();
|
||||
}
|
||||
|
||||
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 */
|
||||
if (virtio_had_irq(net_dev)) {
|
||||
virtio_net_check_queues();
|
||||
|
|
@ -468,202 +308,131 @@ virtio_net_intr(message *m)
|
|||
virtio_net_check_pending();
|
||||
|
||||
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)
|
||||
{
|
||||
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();
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
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;
|
||||
env_parse("instance", "d", 0, &instance, 0, 255);
|
||||
struct vumap_phys phys[2];
|
||||
struct packet *p;
|
||||
|
||||
if (virtio_net_probe((int)instance) != OK)
|
||||
panic("%s: No device found", name);
|
||||
if (STAILQ_EMPTY(&free_list))
|
||||
return SUSPEND;
|
||||
|
||||
if (virtio_net_config() != OK)
|
||||
panic("%s: No device found", name);
|
||||
p = STAILQ_FIRST(&free_list);
|
||||
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)
|
||||
panic("%s: Buffer allocation failed", name);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
* The driver is terminating. Clean up.
|
||||
*/
|
||||
static void
|
||||
sef_cb_signal_handler(int signo)
|
||||
virtio_net_stop(void)
|
||||
{
|
||||
if (signo != SIGTERM)
|
||||
return;
|
||||
|
||||
dput(("Terminating"));
|
||||
|
||||
|
|
@ -675,6 +444,18 @@ sef_cb_signal_handler(int signo)
|
|||
virtio_free_queues(net_dev);
|
||||
virtio_free_device(net_dev);
|
||||
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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -439,7 +439,7 @@ virtio_blk_device_intr(void)
|
|||
thread_id_t *tid;
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,9 +5,63 @@
|
|||
|
||||
#include <minix/endpoint.h>
|
||||
#include <minix/ipc.h>
|
||||
#include <minix/com.h>
|
||||
|
||||
/* Functions defined by netdriver.c: */
|
||||
void netdriver_announce(void);
|
||||
int netdriver_receive(endpoint_t src, message *m_ptr, int *status_ptr);
|
||||
/* The flags that make up the requested receive mode. */
|
||||
#define NDEV_NOMODE DL_NOMODE /* targeted packets only */
|
||||
#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 */
|
||||
|
|
|
|||
|
|
@ -98,11 +98,12 @@ int virtio_to_queue(struct virtio_device *dev, int qidx,
|
|||
struct vumap_phys *bufs, size_t num, void *data);
|
||||
|
||||
/*
|
||||
* If the host used a chain of descriptors, return 0 and set data
|
||||
* as was given to virtio_to_queue(). If the host has not processed
|
||||
* any element returns -1.
|
||||
* If the host used a chain of descriptors, return 0, set data as was given to
|
||||
* virtio_to_queue(), and if len is not NULL, set it to the resulting length.
|
||||
* 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 */
|
||||
void virtio_irq_enable(struct virtio_device *dev);
|
||||
|
|
|
|||
|
|
@ -6,6 +6,6 @@ CPPFLAGS+= -D_MINIX_SYSTEM
|
|||
|
||||
LIB= netdriver
|
||||
|
||||
SRCS= netdriver.c
|
||||
SRCS= netdriver.c portio.c
|
||||
|
||||
.include <bsd.lib.mk>
|
||||
|
|
|
|||
|
|
@ -1,82 +1,620 @@
|
|||
/* This file contains device independent network device driver interface.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
/* The device-independent network driver framework. */
|
||||
|
||||
#include <minix/drivers.h>
|
||||
#include <minix/endpoint.h>
|
||||
#include <minix/netdriver.h>
|
||||
#include <minix/ds.h>
|
||||
#include <assert.h>
|
||||
|
||||
static int conf_expected = TRUE;
|
||||
#include "netdriver.h"
|
||||
|
||||
/*===========================================================================*
|
||||
* netdriver_announce *
|
||||
*===========================================================================*/
|
||||
void netdriver_announce()
|
||||
static const struct netdriver *netdriver_table = NULL;
|
||||
|
||||
static int running;
|
||||
|
||||
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. */
|
||||
int r;
|
||||
char key[DS_MAX_KEYLEN];
|
||||
char label[DS_MAX_KEYLEN];
|
||||
const char *driver_prefix = "drv.net.";
|
||||
const char *driver_prefix = "drv.net.";
|
||||
char label[DS_MAX_KEYLEN];
|
||||
char key[DS_MAX_KEYLEN];
|
||||
int r;
|
||||
|
||||
/* Publish a driver up event. */
|
||||
r = ds_retrieve_label_name(label, sef_self());
|
||||
if (r != OK) {
|
||||
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);
|
||||
}
|
||||
/* Publish a driver up event. */
|
||||
if ((r = ds_retrieve_label_name(label, sef_self())) != OK)
|
||||
panic("netdriver: unable to get own label: %d", 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 *
|
||||
*===========================================================================*/
|
||||
int netdriver_receive(src, m_ptr, status_ptr)
|
||||
endpoint_t src;
|
||||
message *m_ptr;
|
||||
int *status_ptr;
|
||||
/*
|
||||
* 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
|
||||
* entirely within the vector.
|
||||
*/
|
||||
size_t
|
||||
netdriver_prepare_copy(struct netdriver_data * data, size_t off, size_t size,
|
||||
unsigned int * indexp)
|
||||
{
|
||||
/* receive() interface for drivers. */
|
||||
int r;
|
||||
unsigned int i;
|
||||
|
||||
while (TRUE) {
|
||||
/* Wait for a request. */
|
||||
r = sef_receive_status(src, m_ptr, status_ptr);
|
||||
if (r != OK) {
|
||||
return r;
|
||||
assert(data->size > 0);
|
||||
|
||||
/*
|
||||
* In theory we could truncate when copying out, but this creates a
|
||||
* 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. */
|
||||
if (!IS_DL_RQ(m_ptr->m_type)) {
|
||||
return r;
|
||||
}
|
||||
assert(i < data->count);
|
||||
|
||||
/* See if only DL_CONF is to be expected. */
|
||||
if(conf_expected) {
|
||||
if(m_ptr->m_type == DL_CONF) {
|
||||
conf_expected = FALSE;
|
||||
}
|
||||
else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return OK;
|
||||
*indexp = i;
|
||||
return off;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
15
minix/lib/libnetdriver/netdriver.h
Normal file
15
minix/lib/libnetdriver/netdriver.h
Normal 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 */
|
||||
193
minix/lib/libnetdriver/portio.c
Normal file
193
minix/lib/libnetdriver/portio.c
Normal 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);
|
||||
}
|
||||
}
|
||||
|
|
@ -639,7 +639,8 @@ virtio_to_queue(struct virtio_device *dev, int qidx, struct vumap_phys *bufs,
|
|||
}
|
||||
|
||||
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 vring *vring;
|
||||
|
|
@ -718,6 +719,9 @@ virtio_from_queue(struct virtio_device *dev, int qidx, void **data)
|
|||
*data = q->data[uel->id];
|
||||
q->data[uel->id] = NULL;
|
||||
|
||||
if (len != NULL)
|
||||
*len = uel->len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ SUBDIR+= inet
|
|||
. if ${MKLWIP} == "yes"
|
||||
SUBDIR+= lwip
|
||||
. endif # ${MKLWIP} == "yes"
|
||||
|
||||
SUBDIR+= uds
|
||||
.endif # ${MKIMAGEONLY} == "no"
|
||||
|
||||
.include <bsd.subdir.mk>
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user