From 3570bf6aa842ed54904d9832bd728e3fb223bca8 Mon Sep 17 00:00:00 2001 From: David van Moolenbroek Date: Wed, 3 Dec 2014 10:27:47 +0000 Subject: [PATCH] netdriver branch - JENKINS TESTING ONLY Squashed commit of the following: commit c1f8bd0351773f101b887beebf1bf8faea047d65 Author: David van Moolenbroek Date: Tue Dec 2 14:08:24 2014 +0000 virtio_net: use new libnetdriver Change-Id: Id06bdb67da12477984b42bbd46623bd8f25c0ab9 commit 70b92b94eb2ebd23fe4f0e39708f273fd23df6e9 Author: David van Moolenbroek Date: Tue Dec 2 14:06:15 2014 +0000 rtl8169: use new libnetdriver Change-Id: Ia26b6c440a1525f1d2bb9e7592e357dac0ba602c commit 553a4151f85d4a51a368c1abbc7384f981c25a1d Author: David van Moolenbroek Date: Tue Dec 2 14:07:16 2014 +0000 rtl8139: use new libnetdriver Change-Id: Iba941653b7c052375694bcec2561957c1979feb0 commit 0d5784cf27ba95190c09c885fda1c6c563e87f29 Author: David van Moolenbroek Date: Tue Dec 2 14:05:26 2014 +0000 orinoco: use new libnetdriver Change-Id: I003590539dd76f4be8e067f986bb1f17b151490d commit 84a2c824ace788d3d014a3b4ee0f2d90321eeb8e Author: David van Moolenbroek Date: Tue Dec 2 14:05:09 2014 +0000 lance: use new libnetdriver Change-Id: If3414088e66407c688c4960f99a165b0ee1ebc83 commit b3097036029c3d88a3964362a1fea0d76c4dfa00 Author: David van Moolenbroek Date: Tue Dec 2 14:04:33 2014 +0000 lan8710a: use new libnetdriver Change-Id: Iaee4d75a5dfafc72d94f0b02681f9aea1c9da535 commit bed92519b0c5015bac88400f2b13c7836539642d Author: David van Moolenbroek Date: Tue Dec 2 14:04:01 2014 +0000 fxp: use new libnetdriver Change-Id: I03268655a5daff3d109ae52e64673911ef096a3f commit ba868da1e91b1f8c64dbf918f0572000956f86e2 Author: David van Moolenbroek Date: Tue Dec 2 14:03:14 2014 +0000 e1000: use new libnetdriver Change-Id: I111750d2ca27f01039d0b427b1314aea861e2074 commit 668777f3f727722b73654253a66a0fd1ac3e1bbd Author: David van Moolenbroek Date: Tue Dec 2 14:02:46 2014 +0000 dpeth: use new libnetdriver Change-Id: Ic389e54817c5b241dad851c89ef1cf16c015a79b commit edf59ab3cb55219a93a060fceb8f59b713d75dcd Author: David van Moolenbroek Date: Tue Dec 2 14:02:02 2014 +0000 dp8390: use new libnetdriver Change-Id: Ieaf6d605832d475f95fd9b06026b349dce7ee025 commit d8f11c1f66daaae7d50fe240d216e625472100b0 Author: David van Moolenbroek Date: Tue Dec 2 14:01:20 2014 +0000 dec21140A: use new libnetdriver Change-Id: I54be3b770e4d1fd320200c30e9e9073a7c1b405b commit cc851f55f60ffcaa8cd61df269bd399c3159a78c Author: David van Moolenbroek Date: Tue Dec 2 14:00:04 2014 +0000 atl2: use new libnetdriver Change-Id: I65de5d29a75d5f3101b2c5ab16a4b0d79bd77cc3 commit a50e5606a8cf503c024825ebe56d4b1a3dfd2670 Author: David van Moolenbroek 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 Date: Mon Dec 1 17:00:04 2014 +0000 e1000: convert to KNF Change-Id: Ibd156c2e0a58fed70895080d4b230b26c500fa11 commit 400925dd615afbf0ed720779085ee02db65abeab Author: David van Moolenbroek Date: Thu Nov 27 12:59:57 2014 +0000 atl2: convert to KNF Change-Id: Ie4b979aab3127a91a12b8086326da0eb1f9a860b commit 15e2247939858c826a6395cedac95632e3a8637f Author: David van Moolenbroek 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 Date: Mon Dec 1 17:21:17 2014 +0000 orinoco: restore register memory mapping Untested. Change-Id: I439f0e711e16ba478dadf57ffc8ad74ec19ea1b9 commit d388e231194b9334da2319175383aa9ee7c9e49d Author: David van Moolenbroek 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 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 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 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 Date: Mon Dec 1 17:58:20 2014 +0000 UDS: move from drivers/net/ to net/ Change-Id: I53992b205e767a77c7b3c868a38c7f3d772a4ed3 Change-Id: I45f13cf627c0bce0d0d53b2e0e6aab51312106d9 --- etc/system.conf | 5 +- etc/usr/rc | 2 +- minix/commands/netconf/netconf.sh | 7 +- minix/drivers/net/Makefile | 2 - minix/drivers/net/atl2/atl2.c | 931 ++++----- minix/drivers/net/atl2/atl2.h | 2 - minix/drivers/net/dec21140A/dec21140A.c | 784 ++------ minix/drivers/net/dec21140A/dec21140A.h | 55 +- minix/drivers/net/dp8390/3c503.c | 1 + minix/drivers/net/dp8390/Makefile | 4 +- minix/drivers/net/dp8390/dp8390.c | 1187 ++--------- minix/drivers/net/dp8390/dp8390.h | 73 +- minix/drivers/net/dp8390/local.h | 1 - minix/drivers/net/dp8390/ne2000.c | 4 +- minix/drivers/net/dp8390/rtl8029.c | 5 +- minix/drivers/net/dp8390/wdeth.c | 4 +- minix/drivers/net/dpeth/3c501.c | 187 +- minix/drivers/net/dpeth/3c503.c | 13 +- minix/drivers/net/dpeth/3c509.c | 200 +- minix/drivers/net/dpeth/8390.c | 493 ++--- minix/drivers/net/dpeth/Makefile | 2 +- minix/drivers/net/dpeth/devio.c | 44 +- minix/drivers/net/dpeth/dp.c | 552 ++---- minix/drivers/net/dpeth/dp.h | 83 +- minix/drivers/net/dpeth/ne.c | 16 +- minix/drivers/net/dpeth/netbuff.c | 77 +- minix/drivers/net/dpeth/wd.c | 25 +- minix/drivers/net/e1000/Makefile | 4 +- minix/drivers/net/e1000/e1000.c | 1731 +++++++---------- minix/drivers/net/e1000/e1000.h | 47 +- minix/drivers/net/fxp/Makefile | 4 +- minix/drivers/net/fxp/fxp.c | 891 +++------ minix/drivers/net/lan8710a/Makefile | 4 +- minix/drivers/net/lan8710a/lan8710a.c | 698 ++----- minix/drivers/net/lan8710a/lan8710a.h | 26 - minix/drivers/net/lance/lance.c | 1141 +++-------- minix/drivers/net/lance/lance.h | 58 +- minix/drivers/net/orinoco/Makefile | 4 +- minix/drivers/net/orinoco/orinoco.c | 1199 ++++-------- minix/drivers/net/orinoco/orinoco.h | 39 +- minix/drivers/net/rtl8139/Makefile | 6 +- minix/drivers/net/rtl8139/liveupdate.c | 2 + minix/drivers/net/rtl8139/rtl8139.c | 1207 +++--------- minix/drivers/net/rtl8139/rtl8139.h | 62 +- minix/drivers/net/rtl8169/Makefile | 4 +- minix/drivers/net/rtl8169/rtl8169.c | 880 ++------- minix/drivers/net/virtio_net/virtio_net.c | 547 ++---- minix/drivers/storage/virtio_blk/virtio_blk.c | 2 +- minix/include/minix/netdriver.h | 60 +- minix/include/minix/virtio.h | 9 +- minix/lib/libnetdriver/Makefile | 2 +- minix/lib/libnetdriver/netdriver.c | 664 ++++++- minix/lib/libnetdriver/netdriver.h | 15 + minix/lib/libnetdriver/portio.c | 193 ++ minix/lib/libvirtio/virtio.c | 6 +- minix/net/Makefile | 2 + minix/{drivers => }/net/uds/Makefile | 0 minix/{drivers => }/net/uds/ioc_uds.c | 0 minix/{drivers => }/net/uds/uds.c | 0 minix/{drivers => }/net/uds/uds.h | 0 60 files changed, 4394 insertions(+), 9872 deletions(-) create mode 100644 minix/lib/libnetdriver/netdriver.h create mode 100644 minix/lib/libnetdriver/portio.c rename minix/{drivers => }/net/uds/Makefile (100%) rename minix/{drivers => }/net/uds/ioc_uds.c (100%) rename minix/{drivers => }/net/uds/uds.c (100%) rename minix/{drivers => }/net/uds/uds.h (100%) diff --git a/etc/system.conf b/etc/system.conf index 6f09d66f4..adb6b4d4d 100644 --- a/etc/system.conf +++ b/etc/system.conf @@ -255,7 +255,10 @@ service dp8390 SDEVIO # 22 ; pci device 10ec:8029; - uid 0; + io + 300:20 + ; + irq 9; }; service dpeth diff --git a/etc/usr/rc b/etc/usr/rc index f540bdf97..16d8b1a8e 100644 --- a/etc/usr/rc +++ b/etc/usr/rc @@ -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 diff --git a/minix/commands/netconf/netconf.sh b/minix/commands/netconf/netconf.sh index c9f75ad9f..80f2b3776 100644 --- a/minix/commands/netconf/netconf.sh +++ b/minix/commands/netconf/netconf.sh @@ -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"; ;; diff --git a/minix/drivers/net/Makefile b/minix/drivers/net/Makefile index 069ab5c19..7cd278f2e 100644 --- a/minix/drivers/net/Makefile +++ b/minix/drivers/net/Makefile @@ -18,6 +18,4 @@ SUBDIR+= virtio_net SUBDIR+= lan8710a .endif # ${MACHINE_ARCH} == "earm" -SUBDIR+= uds - .include diff --git a/minix/drivers/net/atl2/atl2.c b/minix/drivers/net/atl2/atl2.c index b07e3536c..e9f332fbd 100644 --- a/minix/drivers/net/atl2/atl2.c +++ b/minix/drivers/net/atl2/atl2.c @@ -1,24 +1,20 @@ /* Attansic/Atheros L2 FastEthernet driver, by D.C. van Moolenbroek */ - -/* No documentation is available for this card. The FreeBSD driver is based +/* + * No documentation is available for this card. The FreeBSD driver is based * heavily on the official Linux driver; this driver is based heavily on both. */ #include #include -#include -#include -#include #include -#include -#include +#include #include #include "atl2.h" #define VERBOSE 0 /* Verbose debugging output */ -#define ATL2_FKEY 1 /* Register Shift+F11 for dumping statistics */ +#define ATL2_FKEY 11 /* Use Shift+Fn to dump statistics (0=off) */ #if VERBOSE #define ATL2_DEBUG(x) printf x @@ -27,24 +23,23 @@ #endif typedef struct { - u32_t hdr; - u32_t vtag; - u8_t data[ATL2_RXD_SIZE - sizeof(u32_t) * 2]; + uint32_t hdr; + uint32_t vtag; + uint8_t data[ATL2_RXD_SIZE - sizeof(uint32_t) * 2]; } rxd_t; static struct { int devind; /* PCI device index */ int irq; /* IRQ number */ int hook_id; /* IRQ hook ID */ - int mode; /* datalink mode */ - volatile u8_t *base; /* base address of memory-mapped registers */ - u32_t size; /* size of memory-mapped area */ - u32_t hwaddr[2]; /* MAC address, in register representation */ + uint8_t *base; /* base address of memory-mapped registers */ + uint32_t size; /* size of memory-mapped area */ + uint32_t hwaddr[2]; /* MAC address, in register representation */ - u8_t *txd_base; /* local address of TxD ring buffer base */ - u32_t *txs_base; /* local address of TxS ring buffer base */ - u8_t *rxd_base_u; /* unaligned base address of RxD ring buffer */ - rxd_t *rxd_base; /* local address of RxD ring buffer base */ + uint8_t *txd_base; /* local address of TxD ring buffer base */ + uint32_t *txs_base; /* local address of TxS ring buffer base */ + uint8_t *rxd_base_u; /* unaligned base address of RxD ring buffer */ + rxd_t *rxd_base; /* local address of RxD ring buffer base */ int rxd_align; /* alignment offset of RxD ring buffer */ @@ -58,50 +53,58 @@ static struct { int txs_num; /* head-tail offset into TxS, in elements */ int rxd_tail; /* tail index into RxD, in elements */ - int flags; /* state flags (ATL2_FLAG_) */ - message read_msg; /* suspended read request (READ_PEND) */ - message write_msg; /* suspended write request (WRITE_PEND) */ - endpoint_t task_endpt; /* requester endpoint (PACK_RCVD|PACK_SENT) */ - size_t recv_count; /* packet size (PACK_RCVD) */ + int rx_avail; /* is there a packet available for receipt? */ eth_stat_t stat; /* statistics */ } state; -#define ATL2_FLAG_RX_AVAIL 0x01 /* packet available for receipt */ -#define ATL2_FLAG_READ_PEND 0x02 /* read request pending */ -#define ATL2_FLAG_WRITE_PEND 0x04 /* write request pending */ -#define ATL2_FLAG_PACK_RCVD 0x08 /* packet received */ -#define ATL2_FLAG_PACK_SENT 0x10 /* packet transmitted */ - -#define ATL2_READ_U8(off) (* (u8_t *) (state.base + (off))) -#define ATL2_READ_U16(off) (* (u16_t *) (state.base + (off))) -#define ATL2_READ_U32(off) (* (u32_t *) (state.base + (off))) -#define ATL2_WRITE_U8(off, val) * (u8_t *) (state.base + (off)) = (val); -#define ATL2_WRITE_U16(off, val) * (u16_t *) (state.base + (off)) = (val); -#define ATL2_WRITE_U32(off, val) * (u32_t *) (state.base + (off)) = (val); +#define ATL2_READ_U8(off) (*(volatile uint8_t *)(state.base + (off))) +#define ATL2_READ_U16(off) (*(volatile uint16_t *)(state.base + (off))) +#define ATL2_READ_U32(off) (*(volatile uint32_t *)(state.base + (off))) +#define ATL2_WRITE_U8(off, val) \ + *(volatile uint8_t *)(state.base + (off)) = (val) +#define ATL2_WRITE_U16(off, val) \ + *(volatile uint16_t *)(state.base + (off)) = (val) +#define ATL2_WRITE_U32(off, val) \ + *(volatile uint32_t *)(state.base + (off)) = (val) #define ATL2_ALIGN_32(n) (((n) + 3) & ~3) -static iovec_s_t iovec[NR_IOREQS]; +static int atl2_init(unsigned int instance, ether_addr_t *addr); +static void atl2_stop(void); +static void atl2_mode(unsigned int mode); +static int atl2_send(struct netdriver_data *data, size_t size); +static ssize_t atl2_recv(struct netdriver_data *data, size_t max); +static void atl2_stat(eth_stat_t *stat); +static void atl2_intr(unsigned int mask); +static void atl2_other(const message *m_ptr, int ipc_status); -static int instance; +static const struct netdriver atl2_table = { + .ndr_init = atl2_init, + .ndr_stop = atl2_stop, + .ndr_mode = atl2_mode, + .ndr_recv = atl2_recv, + .ndr_send = atl2_send, + .ndr_stat = atl2_stat, + .ndr_intr = atl2_intr, + .ndr_other = atl2_other +}; -/*===========================================================================* - * atl2_read_vpd * - *===========================================================================*/ -static int atl2_read_vpd(int index, u32_t *res) +/* + * Read a value from the VPD register area. + */ +static int +atl2_read_vpd(int index, uint32_t * res) { - /* Read a value from the VPD register area. - */ - u32_t off, val; + uint32_t off, val; int i; ATL2_WRITE_U32(ATL2_VPD_DATA_REG, 0); - off = ATL2_VPD_REGBASE + index * sizeof(u32_t); + off = ATL2_VPD_REGBASE + index * sizeof(uint32_t); ATL2_WRITE_U32(ATL2_VPD_CAP_REG, - (off << ATL2_VPD_CAP_ADDR_SHIFT) & ATL2_VPD_CAP_ADDR_MASK); + (off << ATL2_VPD_CAP_ADDR_SHIFT) & ATL2_VPD_CAP_ADDR_MASK); for (i = 0; i < ATL2_VPD_NTRIES; i++) { micro_delay(ATL2_VPD_DELAY); @@ -120,15 +123,14 @@ static int atl2_read_vpd(int index, u32_t *res) return TRUE; } -/*===========================================================================* - * atl2_get_vpd_hwaddr * - *===========================================================================*/ -static int atl2_get_vpd_hwaddr(void) +/* + * Read the MAC address from the EEPROM, using the Vital Product Data register + * interface. + */ +static int +atl2_get_vpd_hwaddr(void) { - /* Read the MAC address from the EEPROM, using the Vital Product Data - * register interface. - */ - u32_t key, val; + uint32_t key, val; int i, n, found[2]; /* No idea, copied from FreeBSD which copied it from Linux. */ @@ -144,7 +146,8 @@ static int atl2_get_vpd_hwaddr(void) return FALSE; #endif - /* Read out the set of key/value pairs. Look for the two parts that + /* + * Read out the set of key/value pairs. Look for the two parts that * make up the MAC address. */ found[0] = found[1] = FALSE; @@ -173,14 +176,13 @@ static int atl2_get_vpd_hwaddr(void) return found[0] && found[1]; } -/*===========================================================================* - * atl2_get_hwaddr * - *===========================================================================*/ -static void atl2_get_hwaddr(void) +/* + * Get the MAC address of the card. First try the EEPROM; if that fails, just + * use whatever the card was already set to. + */ +static void +atl2_get_hwaddr(ether_addr_t * addr) { - /* Get the MAC address of the card. First try the EEPROM; if that - * fails, just use whatever the card was already set to. - */ if (!atl2_get_vpd_hwaddr()) { printf("ATL2: unable to read from VPD\n"); @@ -189,23 +191,29 @@ static void atl2_get_hwaddr(void) state.hwaddr[1] = ATL2_READ_U32(ATL2_HWADDR1_REG) & 0xffff; } - ATL2_DEBUG(("ATL2: MAC address %04lx%08lx\n", - state.hwaddr[1], state.hwaddr[0])); + ATL2_DEBUG(("ATL2: MAC address %04x%08x\n", + state.hwaddr[1], state.hwaddr[0])); + + addr->ea_addr[0] = state.hwaddr[1] >> 8; + addr->ea_addr[1] = state.hwaddr[1] & 0xff; + addr->ea_addr[2] = state.hwaddr[0] >> 24; + addr->ea_addr[3] = (state.hwaddr[0] >> 16) & 0xff; + addr->ea_addr[4] = (state.hwaddr[0] >> 8) & 0xff; + addr->ea_addr[5] = state.hwaddr[0] & 0xff; } -/*===========================================================================* - * atl2_read_mdio * - *===========================================================================*/ -static int atl2_read_mdio(int addr, u16_t *res) +/* + * Read a MII PHY register using MDIO. + */ +static int +atl2_read_mdio(int addr, uint16_t * res) { - /* Read a MII PHY register using MDIO. - */ - u32_t rval; + uint32_t rval; int i; rval = ((addr << ATL2_MDIO_ADDR_SHIFT) & ATL2_MDIO_ADDR_MASK) | - ATL2_MDIO_START | ATL2_MDIO_READ | ATL2_MDIO_SUP_PREAMBLE | - ATL2_MDIO_CLK_25_4; + ATL2_MDIO_START | ATL2_MDIO_READ | ATL2_MDIO_SUP_PREAMBLE | + ATL2_MDIO_CLK_25_4; ATL2_WRITE_U32(ATL2_MDIO_REG, rval); @@ -220,54 +228,52 @@ static int atl2_read_mdio(int addr, u16_t *res) if (i == ATL2_MDIO_NTRIES) return FALSE; - *res = (u16_t) (rval & ATL2_MDIO_DATA_MASK); + *res = (uint16_t)(rval & ATL2_MDIO_DATA_MASK); return TRUE; } -/*===========================================================================* - * atl2_alloc_dma * - *===========================================================================*/ -static int atl2_alloc_dma(void) +/* + * Allocate DMA ring buffers. + */ +static int +atl2_alloc_dma(void) { - /* Allocate DMA ring buffers. - */ - state.txd_base = alloc_contig(ATL2_TXD_BUFSIZE, - AC_ALIGN4K, &state.txd_phys); - state.txs_base = alloc_contig(ATL2_TXS_COUNT * sizeof(u32_t), - AC_ALIGN4K, &state.txs_phys); + state.txd_base = alloc_contig(ATL2_TXD_BUFSIZE, AC_ALIGN4K, + &state.txd_phys); + state.txs_base = alloc_contig(ATL2_TXS_COUNT * sizeof(uint32_t), + AC_ALIGN4K, &state.txs_phys); - /* The data buffer in each RxD descriptor must be 128-byte aligned. + /* + * The data buffer in each RxD descriptor must be 128-byte aligned. * The two Tx buffers merely require a 4-byte start alignment. */ state.rxd_align = 128 - offsetof(rxd_t, data); - state.rxd_base_u = - alloc_contig(state.rxd_align + ATL2_RXD_COUNT * ATL2_RXD_SIZE, - AC_ALIGN4K, &state.rxd_phys); + state.rxd_base_u = alloc_contig(state.rxd_align + + ATL2_RXD_COUNT * ATL2_RXD_SIZE, AC_ALIGN4K, &state.rxd_phys); /* Unlike mmap, alloc_contig returns NULL on failure. */ if (!state.txd_base || !state.txs_base || !state.rxd_base_u) return ENOMEM; - state.rxd_base = (rxd_t *) (state.rxd_base_u + state.rxd_align); + state.rxd_base = (rxd_t *)(state.rxd_base_u + state.rxd_align); state.rxd_phys += state.rxd_align; /* Zero out just in case. */ memset(state.txd_base, 0, ATL2_TXD_BUFSIZE); - memset(state.txs_base, 0, ATL2_TXS_COUNT * sizeof(u32_t)); + memset(state.txs_base, 0, ATL2_TXS_COUNT * sizeof(uint32_t)); memset(state.rxd_base, 0, ATL2_RXD_COUNT * ATL2_RXD_SIZE); return OK; } -/*===========================================================================* - * atl2_stop * - *===========================================================================*/ -static int atl2_stop(void) +/* + * Stop the device. + */ +static void +atl2_stop(void) { - /* Stop the device. - */ - u32_t val; + uint32_t val; int i; /* Clear and disable interrupts. */ @@ -292,18 +298,16 @@ static int atl2_stop(void) micro_delay(ATL2_IDLE_DELAY); } - /* The caller will generally ignore this return value. */ - return (i < ATL2_IDLE_NTRIES); + assert(i < ATL2_IDLE_NTRIES); } -/*===========================================================================* - * atl2_reset * - *===========================================================================*/ -static int atl2_reset(void) +/* + * Reset the device to a known good state. + */ +static int +atl2_reset(void) { - /* Reset the device to a known good state. - */ - u32_t val; + uint32_t val; int i; /* Issue a soft reset, and wait for the device to respond. */ @@ -331,44 +335,42 @@ static int atl2_reset(void) return (i < ATL2_IDLE_NTRIES); } -/*===========================================================================* - * atl2_set_mode * - *===========================================================================*/ -static void atl2_set_mode(void) +/* + * Reconfigure the device's promiscuity, multicast, and broadcast mode + * settings. + */ +static void +atl2_mode(unsigned int mode) { - /* Reconfigure the device's promiscuity, multicast, and broadcast mode - * settings. - */ - u32_t val; + uint32_t val; val = ATL2_READ_U32(ATL2_MAC_REG); val &= ~(ATL2_MAC_PROMISC_EN | ATL2_MAC_MCAST_EN | ATL2_MAC_BCAST_EN); - if (state.mode & DL_PROMISC_REQ) + if (mode & NDEV_PROMISC) val |= ATL2_MAC_PROMISC_EN; - if (state.mode & DL_MULTI_REQ) + if (mode & NDEV_MULTI) val |= ATL2_MAC_MCAST_EN; - if (state.mode & DL_BROAD_REQ) + if (mode & NDEV_BROAD) val |= ATL2_MAC_BCAST_EN; ATL2_WRITE_U32(ATL2_MAC_REG, val); } -/*===========================================================================* - * atl2_setup * - *===========================================================================*/ -static int atl2_setup(void) +/* + * Set up the device for normal operation. + */ +static int +atl2_setup(void) { - /* Set up the device for normal operation. - */ - u32_t val; + uint32_t val; atl2_stop(); if (!atl2_reset()) return FALSE; - /* Initialize PCIE module. Magic. */ + /* Initialize PCIe module. Magic. */ ATL2_WRITE_U32(ATL2_LTSSM_TESTMODE_REG, ATL2_LTSSM_TESTMODE_DEFAULT); ATL2_WRITE_U32(ATL2_DLL_TX_CTRL_REG, ATL2_DLL_TX_CTRL_DEFAULT); @@ -390,7 +392,8 @@ static int atl2_setup(void) ATL2_WRITE_U32(ATL2_RXD_ADDR_LO_REG, state.rxd_phys); ATL2_WRITE_U16(ATL2_RXD_COUNT_REG, ATL2_RXD_COUNT); - ATL2_WRITE_U16(ATL2_TXD_BUFSIZE_REG, ATL2_TXD_BUFSIZE / sizeof(u32_t)); + ATL2_WRITE_U16(ATL2_TXD_BUFSIZE_REG, + ATL2_TXD_BUFSIZE / sizeof(uint32_t)); ATL2_WRITE_U16(ATL2_TXS_COUNT_REG, ATL2_TXS_COUNT); /* A whole lot of other initialization copied from Linux/FreeBSD. */ @@ -415,7 +418,7 @@ static int atl2_setup(void) /* Reset descriptors, and enable DMA. */ state.txd_tail = state.txs_tail = state.rxd_tail = 0; state.txd_num = state.txs_num = 0; - state.flags &= ~ATL2_FLAG_RX_AVAIL; + state.rx_avail = FALSE; ATL2_WRITE_U16(ATL2_TXD_IDX_REG, 0); ATL2_WRITE_U16(ATL2_RXD_IDX_REG, 0); @@ -439,13 +442,14 @@ static int atl2_setup(void) /* Configure MAC. */ ATL2_WRITE_U32(ATL2_MAC_REG, ATL2_MAC_DEFAULT); - /* Inet does not tell us about the multicast addresses that it is + /* + * Inet does not tell us about the multicast addresses that it is * interested in, so we have to simply accept all multicast packets. */ ATL2_WRITE_U32(ATL2_MHT0_REG, 0xffffffff); ATL2_WRITE_U32(ATL2_MHT1_REG, 0xffffffff); - atl2_set_mode(); + atl2_mode(NDEV_NOMODE); /* Enable Tx/Rx. */ val = ATL2_READ_U32(ATL2_MAC_REG); @@ -454,14 +458,13 @@ static int atl2_setup(void) return TRUE; } -/*===========================================================================* - * atl2_probe * - *===========================================================================*/ -static int atl2_probe(int skip) +/* + * Find a matching PCI device. + */ +static int +atl2_probe(int skip) { - /* Find a matching PCI device. - */ - u16_t vid, did; + uint16_t vid, did; #if VERBOSE char *dname; #endif @@ -482,8 +485,7 @@ static int atl2_probe(int skip) #if VERBOSE dname = pci_dev_name(vid, did); ATL2_DEBUG(("ATL2: found %s (%x/%x) at %s\n", - dname ? dname : "", vid, did, - pci_slot_name(devind))); + dname ? dname : "", vid, did, pci_slot_name(devind))); #endif pci_reserve(devind); @@ -491,23 +493,17 @@ static int atl2_probe(int skip) return devind; } -/*===========================================================================* - * atl2_init * - *===========================================================================*/ -static void atl2_init(int devind) +/* + * Initialize the device. + */ +static void +atl2_init_hw(int devind, ether_addr_t * addr) { - /* Initialize the device. - */ - u32_t bar; + uint32_t bar; int r, flag; /* Initialize global state. */ state.devind = devind; - state.mode = DL_NOMODE; - state.flags = 0; - state.recv_count = 0; - - memset(&state.stat, 0, sizeof(state.stat)); if ((r = pci_get_bar(devind, PCI_BAR, &bar, &state.size, &flag)) != OK) panic("unable to retrieve bar: %d", r); @@ -515,7 +511,7 @@ static void atl2_init(int devind) if (state.size < ATL2_MIN_MMAP_SIZE || flag) panic("invalid register bar"); - state.base = vm_map_phys(SELF, (void *) bar, state.size); + state.base = vm_map_phys(SELF, (void *)bar, state.size); if (state.base == MAP_FAILED) panic("unable to map in registers"); @@ -534,18 +530,17 @@ static void atl2_init(int devind) if ((r = sys_irqenable(&state.hook_id)) != OK) panic("unable to enable IRQ: %d", r); - atl2_get_hwaddr(); + atl2_get_hwaddr(addr); atl2_setup(); } -/*===========================================================================* - * atl2_tx_stat * - *===========================================================================*/ -static void atl2_tx_stat(u32_t stat) +/* + * Update statistics for packet transmission. + */ +static void +atl2_tx_stat(uint32_t stat) { - /* Update statistics for packet transmission. - */ if (stat & ATL2_TXS_SUCCESS) state.stat.ets_packetT++; @@ -566,13 +561,12 @@ static void atl2_tx_stat(u32_t stat) state.stat.ets_fifoUnder++; } -/*===========================================================================* - * atl2_rx_stat * - *===========================================================================*/ -static void atl2_rx_stat(u32_t stat) +/* + * Update statistics for packet receipt. + */ +static void +atl2_rx_stat(uint32_t stat) { - /* Update statistics for packet receipt. - */ if (stat & ATL2_RXD_SUCCESS) state.stat.ets_packetR++; @@ -589,14 +583,13 @@ static void atl2_rx_stat(u32_t stat) state.stat.ets_frameAll++; } -/*===========================================================================* - * atl2_tx_advance * - *===========================================================================*/ -static int atl2_tx_advance(void) +/* + * Advance the TxD/TxS tails by as many sent packets as found. + */ +static int +atl2_tx_advance(void) { - /* Advance the TxD/TxS tails by as many sent packets as found. - */ - u32_t stat, size, dsize; + uint32_t stat, size, dsize; int advanced; advanced = FALSE; @@ -608,32 +601,33 @@ static int atl2_tx_advance(void) if (!(stat & ATL2_TXS_UPDATE)) break; - /* The packet size from the status must match the packet size - * we put in. If they don't, there's not much we can do.. + /* + * The packet size from the status must match the packet size + * we put in. If they don't, there's not much we can do.. */ size = stat & ATL2_TXS_SIZE_MASK; - assert((u32_t) state.txd_tail <= - ATL2_TXD_BUFSIZE - sizeof(u32_t)); - dsize = * (u32_t *) (state.txd_base + state.txd_tail); + assert((uint32_t)state.txd_tail <= + ATL2_TXD_BUFSIZE - sizeof(uint32_t)); + dsize = + *(volatile uint32_t *)(state.txd_base + state.txd_tail); if (size != dsize) printf("ATL2: TxD/TxS size mismatch (%x vs %x)\n", - size, dsize); + size, dsize); /* Advance tails accordingly. */ - size = sizeof(u32_t) + ATL2_ALIGN_32(dsize); - assert((u32_t) state.txd_num >= size); + size = sizeof(uint32_t) + ATL2_ALIGN_32(dsize); + assert((uint32_t)state.txd_num >= size); state.txd_tail = (state.txd_tail + size) % ATL2_TXD_BUFSIZE; state.txd_num -= size; state.txs_tail = (state.txs_tail + 1) % ATL2_TXS_COUNT; state.txs_num--; - if (stat & ATL2_TXS_SUCCESS) { + if (stat & ATL2_TXS_SUCCESS) ATL2_DEBUG(("ATL2: successfully sent packet\n")); - } else { + else ATL2_DEBUG(("ATL2: failed to send packet\n")); - } /* Update statistics. */ atl2_tx_stat(stat); @@ -644,18 +638,18 @@ static int atl2_tx_advance(void) return advanced; } -/*===========================================================================* - * atl2_rx_advance * - *===========================================================================*/ -static void atl2_rx_advance(int next) +/* + * Advance the RxD tail by as many failed receipts as possible, and see if + * there is an actual packet left to receive. If 'next' is set, the packet at + * the current tail has been processed. + */ +static void +atl2_rx_advance(int next) { - /* Advance the RxD tail by as many failed receipts as possible, and - * see if there is an actual packet left to receive. If 'next' is set, - * the packet at the current tail has been processed. - */ int update_tail; rxd_t *rxd; - u32_t hdr, size; + uint32_t hdr; + size_t size; update_tail = FALSE; @@ -665,10 +659,10 @@ static void atl2_rx_advance(int next) ATL2_DEBUG(("ATL2: successfully received packet\n")); - state.flags &= ~ATL2_FLAG_RX_AVAIL; + state.rx_avail = FALSE; } - assert(!(state.flags & ATL2_FLAG_RX_AVAIL)); + assert(!state.rx_avail); for (;;) { /* Check the RxD tail for updates. */ @@ -679,21 +673,23 @@ static void atl2_rx_advance(int next) if (!(hdr & ATL2_RXD_UPDATE)) break; - rxd->hdr = hdr & ~(ATL2_RXD_UPDATE); + rxd->hdr = hdr & ~ATL2_RXD_UPDATE; /* Update statistics. */ atl2_rx_stat(hdr); - /* Stop at the first successful receipt. The packet will be + /* + * Stop at the first successful receipt. The packet will be * picked up by Inet later. */ size = hdr & ATL2_RXD_SIZE_MASK; - if ((hdr & ATL2_RXD_SUCCESS) && size >= ETH_MIN_PACK_SIZE) { - ATL2_DEBUG(("ATL2: packet available, size %ld\n", - size)); + if ((hdr & ATL2_RXD_SUCCESS) && + size >= ETH_MIN_PACK_SIZE + ETH_CRC_SIZE) { + ATL2_DEBUG(("ATL2: packet available, size %zu\n", + size)); - state.flags |= ATL2_FLAG_RX_AVAIL; + state.rx_avail = TRUE; break; } @@ -712,223 +708,81 @@ static void atl2_rx_advance(int next) } } -/*===========================================================================* - * atl2_reply * - *===========================================================================*/ -static void atl2_reply(void) +/* + * Receive a packet. + */ +static ssize_t +atl2_recv(struct netdriver_data * data, size_t max) { - /* Send a task reply to Inet. - */ - message m; - int r, flags; - - flags = DL_NOFLAGS; - if (state.flags & ATL2_FLAG_PACK_SENT) - flags |= DL_PACK_SEND; - if (state.flags & ATL2_FLAG_PACK_RCVD) - flags |= DL_PACK_RECV; - - m.m_type = DL_TASK_REPLY; - m.m_netdrv_net_dl_task.flags = flags; - m.m_netdrv_net_dl_task.count = state.recv_count; - - ATL2_DEBUG(("ATL2: sending reply, flags %x count %d\n", flags, - m.m_netdrv_net_dl_task.count)); - - if ((r = ipc_send(state.task_endpt, &m)) != OK) - panic("unable to reply: %d", r); - - state.flags &= ~(ATL2_FLAG_PACK_SENT | ATL2_FLAG_PACK_RCVD); - state.recv_count = 0; -} - -/*===========================================================================* - * atl2_readv * - *===========================================================================*/ -static void atl2_readv(const message *m, int from_int) -{ - /* Read packet data. - */ rxd_t *rxd; - iovec_s_t *iovp; - size_t count, off, left, size; - u8_t *pos; - int i, j, r, batch; - - /* We can deal with only one read request from Inet at a time. */ - assert(from_int || !(state.flags & ATL2_FLAG_READ_PEND)); - - state.task_endpt = m->m_source; + size_t size; /* Are there any packets available at all? */ - if (!(state.flags & ATL2_FLAG_RX_AVAIL)) - goto suspend; + if (!state.rx_avail) + return SUSPEND; - /* Get the first available packet's size. Cut off the CRC. */ + /* Get the first available packet's size. Cut off the CRC. */ rxd = &state.rxd_base[state.rxd_tail]; - count = rxd->hdr & ATL2_RXD_SIZE_MASK; - count -= ETH_CRC_SIZE; + size = rxd->hdr & ATL2_RXD_SIZE_MASK; + size -= ETH_CRC_SIZE; - ATL2_DEBUG(("ATL2: readv: found packet with length %d\n", count)); + ATL2_DEBUG(("ATL2: receiving packet with length %zu\n", size)); + + /* Truncate large packets. */ + if (size > max) + size = max; /* Copy out the packet. */ - off = 0; - left = count; - pos = rxd->data; + netdriver_copyout(data, 0, rxd->data, size); - for (i = 0; i < m->m_net_netdrv_dl_readv_s.count && left > 0; i += batch) { - /* Copy in the next batch. */ - batch = MIN(m->m_net_netdrv_dl_readv_s.count - i, NR_IOREQS); - - r = sys_safecopyfrom(m->m_source, - m->m_net_netdrv_dl_readv_s.grant, off, (vir_bytes) iovec, - batch * sizeof(iovec[0])); - if (r != OK) - panic("vector copy failed: %d", r); - - /* Copy out each element in the batch, until we run out. */ - for (j = 0, iovp = iovec; j < batch && left > 0; j++, iovp++) { - size = MIN(iovp->iov_size, left); - - r = sys_safecopyto(m->m_source, iovp->iov_grant, 0, - (vir_bytes) pos, size); - if (r != OK) - panic("safe copy failed: %d", r); - - pos += size; - left -= size; - } - - off += batch * sizeof(iovec[0]); - } - - /* Not sure what to do here. Inet shouldn't mess this up anyway. */ - if (left > 0) { - printf("ATL2: truncated packet of %d bytes by %d bytes\n", - count, left); - count -= left; - } - - /* We are done with this packet. Move on to the next. */ + /* We are done with this packet. Move on to the next. */ atl2_rx_advance(TRUE /*next*/); - /* We have now successfully received a packet. */ - state.flags &= ~ATL2_FLAG_READ_PEND; - state.flags |= ATL2_FLAG_PACK_RCVD; - state.recv_count = count; - - /* If called from the interrupt handler, the caller will reply. */ - if (!from_int) - atl2_reply(); - - return; - -suspend: - /* No packets are available at this time. If we were not already - * trying to resume receipt, save the read request for later, and tell - * Inet that the request has been suspended. - */ - if (from_int) - return; - - state.flags |= ATL2_FLAG_READ_PEND; - state.read_msg = *m; - - atl2_reply(); + return size; } -/*===========================================================================* - * atl2_writev * - *===========================================================================*/ -static void atl2_writev(const message *m, int from_int) +/* + * Send a packet. + */ +static int +atl2_send(struct netdriver_data * data, size_t size) { - /* Write packet data. - */ - iovec_s_t *iovp; - size_t off, count, left, pos, skip; - vir_bytes size; - u8_t *sizep; - int i, j, r, batch, maxnum; + size_t pos, chunk; + uint8_t *sizep; - /* We can deal with only one write request from Inet at a time. */ - assert(from_int || !(state.flags & ATL2_FLAG_WRITE_PEND)); - - state.task_endpt = m->m_source; - - /* If we are already certain that the packet won't fit, bail out. - * Keep at least some space between TxD head and tail, as it is not - * clear whether the device deals well with the case that they collide. + /* + * If the packet won't fit, bail out. Keep at least some space between + * TxD head and tail, as it is not clear whether the device deals well + * with the case that they collide. */ if (state.txs_num >= ATL2_TXS_COUNT) - goto suspend; - maxnum = ATL2_TXD_BUFSIZE - ETH_MIN_PACK_SIZE - sizeof(u32_t); - if (state.txd_num >= maxnum) - goto suspend; + return SUSPEND; - /* Optimistically try to copy in the data; suspend if it turns out - * that it does not fit. - */ - off = 0; - count = 0; - left = state.txd_num - sizeof(u32_t); + if (state.txd_num + sizeof(uint32_t) + ATL2_ALIGN_32(size) >= + ATL2_TXD_BUFSIZE) + return SUSPEND; + + /* Copy in the packet. */ pos = (state.txd_tail + state.txd_num + - sizeof(u32_t)) % ATL2_TXD_BUFSIZE; - - for (i = 0; i < m->m_net_netdrv_dl_writev_s.count; i += batch) { - /* Copy in the next batch. */ - batch = MIN(m->m_net_netdrv_dl_writev_s.count - i, NR_IOREQS); - - r = sys_safecopyfrom(m->m_source, - m->m_net_netdrv_dl_writev_s.grant, off, (vir_bytes) iovec, - batch * sizeof(iovec[0])); - if (r != OK) - panic("vector copy failed: %d", r); - - /* Copy in each element in the batch. */ - for (j = 0, iovp = iovec; j < batch; j++, iovp++) { - size = iovp->iov_size; - if (size > left) - goto suspend; - - skip = 0; - if (size > ATL2_TXD_BUFSIZE - pos) { - skip = ATL2_TXD_BUFSIZE - pos; - r = sys_safecopyfrom(m->m_source, - iovp->iov_grant, 0, - (vir_bytes) (state.txd_base + pos), - skip); - if (r != OK) - panic("safe copy failed: %d", r); - pos = 0; - } - - r = sys_safecopyfrom(m->m_source, iovp->iov_grant, - skip, (vir_bytes) (state.txd_base + pos), - size - skip); - if (r != OK) - panic("safe copy failed: %d", r); - - pos = (pos + size - skip) % ATL2_TXD_BUFSIZE; - left -= size; - count += size; - } - - off += batch * sizeof(iovec[0]); - } - - assert(count <= ETH_MAX_PACK_SIZE_TAGGED); + sizeof(uint32_t)) % ATL2_TXD_BUFSIZE; + chunk = ATL2_TXD_BUFSIZE - pos; + if (size > chunk) { + netdriver_copyin(data, 0, state.txd_base + pos, chunk); + netdriver_copyin(data, chunk, state.txd_base, size - chunk); + } else + netdriver_copyin(data, 0, state.txd_base + pos, size); /* Write the length to the DWORD right before the packet. */ sizep = state.txd_base + - (state.txd_tail + state.txd_num) % ATL2_TXD_BUFSIZE; - * (u32_t *) sizep = count; + (state.txd_tail + state.txd_num) % ATL2_TXD_BUFSIZE; + *(volatile uint32_t *)sizep = size; /* Update the TxD head. */ - state.txd_num += sizeof(u32_t) + ATL2_ALIGN_32(count); - pos = ATL2_ALIGN_32(pos) % ATL2_TXD_BUFSIZE; - assert((int) pos == - (state.txd_tail + state.txd_num) % ATL2_TXD_BUFSIZE); + state.txd_num += sizeof(uint32_t) + ATL2_ALIGN_32(size); + pos = ATL2_ALIGN_32(pos + size) % ATL2_TXD_BUFSIZE; + assert((int)pos == + (state.txd_tail + state.txd_num) % ATL2_TXD_BUFSIZE); /* Initialize and update the TxS head. */ state.txs_base[(state.txs_tail + state.txs_num) % ATL2_TXS_COUNT] = 0; @@ -937,69 +791,46 @@ static void atl2_writev(const message *m, int from_int) /* Tell the device about our new position. */ __insn_barrier(); - ATL2_WRITE_U32(ATL2_TXD_IDX_REG, pos / sizeof(u32_t)); + ATL2_WRITE_U32(ATL2_TXD_IDX_REG, pos / sizeof(uint32_t)); - /* We have now successfully set up the transmission of a packet. */ - state.flags &= ~ATL2_FLAG_WRITE_PEND; - state.flags |= ATL2_FLAG_PACK_SENT; - - /* If called from the interrupt handler, the caller will reply. */ - if (!from_int) - atl2_reply(); - - return; - -suspend: - /* We cannot transmit the packet at this time. If we were not already - * trying to resume transmission, save the write request for later, - * and tell Inet that the request has been suspended. - */ - if (from_int) - return; - - state.flags |= ATL2_FLAG_WRITE_PEND; - state.write_msg = *m; - - atl2_reply(); + return OK; } -/*===========================================================================* - * atl2_intr * - *===========================================================================*/ -static void atl2_intr(const message *UNUSED(m)) +/* + * Process an interrupt. + */ +static void +atl2_intr(unsigned int __unused mask) { - /* Interrupt received. - */ - u32_t val; - int r, try_write, try_read; + uint32_t val; + int r, try_send, try_recv; /* Clear and disable interrupts. */ val = ATL2_READ_U32(ATL2_ISR_REG); ATL2_WRITE_U32(ATL2_ISR_REG, val | ATL2_ISR_DISABLE); - ATL2_DEBUG(("ATL2: interrupt (0x%08lx)\n", val)); + ATL2_DEBUG(("ATL2: interrupt (0x%08x)\n", val)); /* If an error occurred, reset the card. */ if (val & (ATL2_ISR_DMAR_TIMEOUT | ATL2_ISR_DMAW_TIMEOUT | - ATL2_ISR_PHY_LINKDOWN)) { + ATL2_ISR_PHY_LINKDOWN)) atl2_setup(); - } - try_write = try_read = FALSE; + try_send = try_recv = FALSE; /* Process sent data, and possibly send pending data. */ if (val & ATL2_ISR_TX_EVENT) { if (atl2_tx_advance()) - try_write = (state.flags & ATL2_FLAG_WRITE_PEND); + try_send = TRUE; } /* Receive new data, and possible satisfy a pending receive request. */ if (val & ATL2_ISR_RX_EVENT) { - if (!(state.flags & ATL2_FLAG_RX_AVAIL)) { + if (!state.rx_avail) { atl2_rx_advance(FALSE /*next*/); - try_read = (state.flags & ATL2_FLAG_READ_PEND); + try_recv = TRUE; } } @@ -1009,75 +840,33 @@ static void atl2_intr(const message *UNUSED(m)) if ((r = sys_irqenable(&state.hook_id)) != OK) panic("unable to enable IRQ: %d", r); - /* Attempt to satisfy pending write and read requests. */ - if (try_write) - atl2_writev(&state.write_msg, TRUE /*from_int*/); - if (try_read) - atl2_readv(&state.read_msg, TRUE /*from_int*/); - if (state.flags & (ATL2_FLAG_PACK_SENT | ATL2_FLAG_PACK_RCVD)) - atl2_reply(); + /* Attempt to satisfy pending send and receive requests. */ + if (try_send) + netdriver_send(); + if (try_recv) + netdriver_recv(); } -/*===========================================================================* - * atl2_conf * - *===========================================================================*/ -static void atl2_conf(message *m) +/* + * Copy out statistics. + */ +static void +atl2_stat(eth_stat_t * stat) { - /* Configure the mode of the card. - */ - ether_addr_t addr; - int r; - state.mode = m->m_net_netdrv_dl_conf.mode; - - atl2_set_mode(); - - addr.ea_addr[0] = state.hwaddr[1] >> 8; - addr.ea_addr[1] = state.hwaddr[1] & 0xff; - addr.ea_addr[2] = state.hwaddr[0] >> 24; - addr.ea_addr[3] = (state.hwaddr[0] >> 16) & 0xff; - addr.ea_addr[4] = (state.hwaddr[0] >> 8) & 0xff; - addr.ea_addr[5] = state.hwaddr[0] & 0xff; - - memcpy(m->m_netdrv_net_dl_conf.hw_addr, &addr, - sizeof(m->m_netdrv_net_dl_conf.hw_addr)); - - m->m_type = DL_CONF_REPLY; - m->m_netdrv_net_dl_conf.stat = OK; - - if ((r = ipc_send(m->m_source, m)) != OK) - printf("ATL2: unable to send reply (%d)\n", r); + memcpy(stat, &state.stat, sizeof(*stat)); } -/*===========================================================================* - * atl2_getstat * - *===========================================================================*/ -static void atl2_getstat(message *m) +/* + * Dump link status. + */ +static void +atl2_dump_link(void) { - /* Copy out statistics. - */ - int r; - - sys_safecopyto(m->m_source, m->m_net_netdrv_dl_getstat_s.grant, 0, - (vir_bytes) &state.stat, sizeof(state.stat)); - - m->m_type = DL_STAT_REPLY; - - if ((r = ipc_send(m->m_source, m)) != OK) - printf("ATL2: unable to send reply (%d)\n", r); -} - -/*===========================================================================* - * atl2_dump_link * - *===========================================================================*/ -static void atl2_dump_link(void) -{ - /* Dump link status. - */ - u16_t val; + uint16_t val; int link_up; - /* The link status bit is latched. Read the status register twice. */ + /* The link status bit is latched. Read the status register twice. */ atl2_read_mdio(ATL2_MII_BMSR, &val); if (!atl2_read_mdio(ATL2_MII_BMSR, &val)) return; @@ -1104,13 +893,12 @@ static void atl2_dump_link(void) printf("%s duplex)", (val & ATL2_MII_PSSR_DUPLEX) ? "full" : "half"); } -/*===========================================================================* - * atl2_dump * - *===========================================================================*/ -static void atl2_dump(void) +/* + * Dump statistics. + */ +static void +atl2_dump(void) { - /* Dump statistics. - */ printf("\n"); printf("Attansic L2 statistics:\n"); @@ -1143,151 +931,94 @@ static void atl2_dump(void) printf("TxS tail: %8d\t", state.txs_tail); printf("TxS count: %8d\n", state.txs_num); - printf("flags: 0x%04x\t", state.flags); atl2_dump_link(); printf("\n"); } -/*===========================================================================* - * sef_cb_init_fresh * - *===========================================================================*/ -static int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *UNUSED(info)) +/* + * Process miscellaneous messages. + */ +static void +atl2_other(const message * m_ptr, int ipc_status) { - /* Initialize the atl2 driver. - */ - int r, devind; - long v; #if ATL2_FKEY - int fkeys, sfkeys; + int sfkeys; + + if (!is_ipc_notify(ipc_status) || m_ptr->m_source != TTY_PROC_NR) + return; + + if (fkey_events(NULL, &sfkeys) == OK && bit_isset(sfkeys, ATL2_FKEY)) + atl2_dump(); +#endif +} + +/* + * Initialize the atl2 driver. + */ +static int +atl2_init(unsigned int instance, ether_addr_t * addr) +{ + int devind; +#if ATL2_FKEY + int r, fkeys, sfkeys; #endif - /* How many matching devices should we skip? */ - v = 0; - (void) env_parse("instance", "d", 0, &v, 0, 255); - instance = (int) v; + memset(&state, 0, sizeof(state)); /* Try to find a recognized device. */ devind = atl2_probe(instance); if (devind < 0) - panic("no matching device found"); + return ENXIO; /* Initialize the device. */ - atl2_init(devind); - - /* Announce we are up! */ - netdriver_announce(); + atl2_init_hw(devind, addr); #if ATL2_FKEY /* Register debug dump function key. */ fkeys = sfkeys = 0; - bit_set(sfkeys, 11); + bit_set(sfkeys, ATL2_FKEY); if ((r = fkey_map(&fkeys, &sfkeys)) != OK) - printf("ATL2: warning, could not map Shift+F11 key (%d)\n", r); + printf("ATL2: warning, could not map Shift+F%u key (%d)\n", + r, ATL2_FKEY); #endif - return(OK); + return OK; } -/*===========================================================================* - * sef_cb_signal_handler * - *===========================================================================*/ -static void sef_cb_signal_handler(int signo) +#if 0 +/* + * Deallocate resources as proof of concept. Currently unused. + */ +static void +atl2_cleanup(void) { - /* In case of a termination signal, shut down this driver. - * Stop the device, and deallocate resources as proof of concept. - */ int r; - /* Only check for termination signal, ignore anything else. */ - if (signo != SIGTERM) return; - - atl2_stop(); - if ((r = sys_irqrmpolicy(&state.hook_id)) != OK) panic("unable to deregister IRQ: %d", r); free_contig(state.txd_base, ATL2_TXD_BUFSIZE); - free_contig(state.txs_base, ATL2_TXS_COUNT * sizeof(u32_t)); + free_contig(state.txs_base, ATL2_TXS_COUNT * sizeof(uint32_t)); free_contig(state.rxd_base_u, - state.rxd_align + ATL2_RXD_COUNT * ATL2_RXD_SIZE); + state.rxd_align + ATL2_RXD_COUNT * ATL2_RXD_SIZE); - vm_unmap_phys(SELF, (void *) state.base, state.size); + vm_unmap_phys(SELF, (void *)state.base, state.size); /* We cannot free the PCI device at this time. */ - - exit(0); } +#endif -/*===========================================================================* - * sef_local_startup * - *===========================================================================*/ -static void sef_local_startup(void) +/* + * The ATL2 ethernet driver. + */ +int +main(int argc, char ** argv) { - /* 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(); -} - -/*===========================================================================* - * main * - *===========================================================================*/ -int main(int argc, char **argv) -{ - /* Driver task. - */ - message m; - int ipc_status; - int r; - - /* Initialize SEF. */ env_setargs(argc, argv); - sef_local_startup(); - while (TRUE) { - if ((r = netdriver_receive(ANY, &m, &ipc_status)) != OK) - panic("netdriver_receive failed: %d", r); + netdriver_task(&atl2_table); - if (is_ipc_notify(ipc_status)) { - switch (m.m_source) { - case HARDWARE: /* interrupt */ - atl2_intr(&m); - - break; - - case TTY_PROC_NR: /* function key */ - atl2_dump(); - - break; - - default: - printf("ATL2: illegal notify from %d\n", - m.m_source); - } - - continue; - } - - /* Process requests from Inet. */ - switch (m.m_type) { - case DL_CONF: atl2_conf(&m); break; - case DL_GETSTAT_S: atl2_getstat(&m); break; - case DL_WRITEV_S: atl2_writev(&m, FALSE); break; - case DL_READV_S: atl2_readv(&m, FALSE); break; - default: - printf("ATL2: illegal message %d from %d\n", - m.m_type, m.m_source); - } - } + return EXIT_SUCCESS; } diff --git a/minix/drivers/net/atl2/atl2.h b/minix/drivers/net/atl2/atl2.h index 85c5e4362..7d53c4741 100644 --- a/minix/drivers/net/atl2/atl2.h +++ b/minix/drivers/net/atl2/atl2.h @@ -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 */ - - diff --git a/minix/drivers/net/dec21140A/dec21140A.c b/minix/drivers/net/dec21140A/dec21140A.c index 4ab0d5e40..5d9eec3b5 100644 --- a/minix/drivers/net/dec21140A/dec21140A.c +++ b/minix/drivers/net/dec21140A/dec21140A.c @@ -2,7 +2,7 @@ * dec21041.c * * This file contains an ethernet device driver for DEC 21140A - * fast ethernet controllers as emulated by VirtualPC 2007. It is not + * fast ethernet controllers as emulated by VirtualPC 2007. It is not * intended to support the real card, as much more error checking * and testing would be needed. It supports both bridged and NAT mode. * @@ -12,288 +12,105 @@ #include #include -#include #include -#include -#include -#include -#include -#include -#include -#include -#include +#include #include "dec21140A.h" - static u32_t io_inl(u16_t); static void io_outl(u16_t, u32_t); -static void do_conf(const message *); -static void do_get_stat_s(message *); -static void do_interrupt(const dpeth_t *); -static void do_reply(dpeth_t *); -static void do_vread_s(const message *, int); -static void do_watchdog(void *); -static void de_update_conf(dpeth_t *); -static int de_probe(dpeth_t *, int skip); -static void de_conf_addr(dpeth_t *); -static void de_first_init(dpeth_t *); +static int do_init(unsigned int, ether_addr_t *); +static void do_stop(void); +static int do_send(struct netdriver_data *, size_t); +static ssize_t do_recv(struct netdriver_data *, size_t); +static void do_stat(eth_stat_t *); +static void do_intr(unsigned int); + +static int de_probe(dpeth_t *, unsigned int skip); +static void de_conf_addr(dpeth_t *, ether_addr_t *); +static void de_init_buf(dpeth_t *); static void de_reset(const dpeth_t *); static void de_hw_conf(const dpeth_t *); static void de_start(const dpeth_t *); -static void de_setup_frame(const dpeth_t *); +static void de_setup_frame(const dpeth_t *, const ether_addr_t *); static u16_t de_read_rom(const dpeth_t *, u8_t, u8_t); -static int de_calc_iov_size(iovec_dat_s_t *); -static void de_next_iov(iovec_dat_s_t *); -static void do_vwrite_s(const message *, int); -static void de_get_userdata_s(int, cp_grant_id_t, vir_bytes, int, void - *); - -/* Error messages */ -static char str_CopyErrMsg[] = "unable to read/write user data"; -static char str_SendErrMsg[] = "send failed"; -static char str_SizeErrMsg[] = "illegal packet size"; -static char str_UmapErrMsg[] = "Unable to sys_umap"; -static char str_BusyErrMsg[] = "Send/Recv failed: busy"; -static char str_StatErrMsg[] = "Unable to send stats"; -static char str_AlignErrMsg[] = "Bad align of buffer/descriptor"; -static char str_DevName[] = "dec21140A:eth#?"; static dpeth_t de_state; static int de_instance; -/* SEF functions and variables. */ -static void sef_local_startup(void); -static int sef_cb_init_fresh(int type, sef_init_info_t *info); +static const struct netdriver de_table = { + .ndr_init = do_init, + .ndr_stop = do_stop, + .ndr_recv = do_recv, + .ndr_send = do_send, + .ndr_stat = do_stat, + .ndr_intr = do_intr +}; -/*===========================================================================* - * main * - *===========================================================================*/ int main(int argc, char *argv[]) { - dpeth_t *dep; - message m; - int ipc_status; - int r; - - /* SEF local startup. */ env_setargs(argc, argv); - sef_local_startup(); - - while (TRUE) - { - if ((r= netdriver_receive(ANY, &m, &ipc_status)) != OK) - panic("netdriver_receive failed: %d", r); - if(is_ipc_notify(ipc_status)) { - switch(_ENDPOINT_P(m.m_source)) { - case CLOCK: - do_watchdog(&m); - break; + netdriver_task(&de_table); - case HARDWARE: - dep = &de_state; - if (dep->de_mode == DEM_ENABLED) { - do_interrupt(dep); - if (dep->de_flags & (DEF_ACK_SEND | DEF_ACK_RECV)) - do_reply(dep); - sys_irqenable(&dep->de_hook); - } - break; - default: - printf("ignoring notify from %d\n", m.m_source); - break; - } - continue; - } - - switch (m.m_type) - { - case DL_WRITEV_S: do_vwrite_s(&m, FALSE); break; - case DL_READV_S: do_vread_s(&m, FALSE); break; - case DL_CONF: do_conf(&m); break; - case DL_GETSTAT_S: do_get_stat_s(&m); break; - - default: - printf("message 0x%x; %d from %d\n", - m.m_type, m.m_type-DL_RQ_BASE, m.m_source); - panic("illegal message: %d", m.m_type); - } - } + return 0; } -/*===========================================================================* - * sef_local_startup * - *===========================================================================*/ -static void sef_local_startup() +static void de_init_hw(dpeth_t *dep, ether_addr_t *addr) { - /* Register init callbacks. */ - sef_setcb_init_fresh(sef_cb_init_fresh); - sef_setcb_init_lu(sef_cb_init_fresh); - sef_setcb_init_restart(sef_cb_init_fresh); + de_reset(dep); + de_conf_addr(dep, addr); + de_init_buf(dep); - /* Register live update callbacks. */ - sef_setcb_lu_prepare(sef_cb_lu_prepare_always_ready); - sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid_workfree); + /* Set the interrupt handler policy. Request interrupts not to be reenabled + * automatically. Return the IRQ line number when an interrupt occurs. + */ + dep->de_hook = dep->de_irq; + sys_irqsetpolicy(dep->de_irq, 0, &dep->de_hook); + sys_irqenable(&dep->de_hook); - /* Register signal callbacks. */ - sef_setcb_signal_handler(sef_cb_signal_handler_term); - - /* Let SEF perform startup. */ - sef_startup(); + de_reset(dep); + de_hw_conf(dep); + de_setup_frame(dep, addr); + de_start(dep); } -/*===========================================================================* - * sef_cb_init_fresh * - *===========================================================================*/ -static int sef_cb_init_fresh(int type, sef_init_info_t *UNUSED(info)) +static int do_init(unsigned int instance, ether_addr_t *addr) { /* Initialize the DEC 21140A driver. */ - int fkeys, sfkeys; - long v; + dpeth_t *dep; - v = 0; - (void) env_parse("instance", "d", 0, &v, 0, 255); - de_instance = (int) v; + dep = &de_state; + memset(dep, 0, sizeof(*dep)); - /* Request function key for debug dumps */ - fkeys = sfkeys = 0; - bit_set(sfkeys, DE_FKEY); - if ((fkey_map(&fkeys, &sfkeys)) != OK) - printf("%s: error using Shift+F%d key(%d)\n", str_DevName, DE_FKEY, errno); + strlcpy(dep->de_name, "dec21140A:?", sizeof(dep->de_name)); + dep->de_name[strlen(dep->de_name)-1] = '0' + instance; - /* Announce we are up! */ - netdriver_announce(); + de_instance = instance; + + if (!de_probe(dep, instance)) + return ENXIO; + + de_init_hw(dep, addr); return OK; } -static void do_get_stat_s(message * mp) +static void do_stat(eth_stat_t *stat) { - int rc; - dpeth_t *dep; - - dep = &de_state; - - if ((rc = sys_safecopyto(mp->m_source, mp->m_net_netdrv_dl_getstat_s.grant, - 0, (vir_bytes)&dep->de_stat, sizeof(dep->de_stat))) != OK) - panic("%s %d", str_CopyErrMsg, rc); - - mp->m_type = DL_STAT_REPLY; - rc = ipc_send(mp->m_source, mp); - if( rc != OK ) - panic("%s %d", str_StatErrMsg, rc); - return; + memcpy(stat, &de_state.de_stat, sizeof(*stat)); } -static void do_conf(const message * mp) +static int de_probe(dpeth_t *dep, unsigned int skip) { - int r; - dpeth_t *dep; - message reply_mess; - - dep = &de_state; - - strncpy(dep->de_name, str_DevName, strlen(str_DevName)); - dep->de_name[strlen(dep->de_name)-1] = '0' + de_instance; - - if (dep->de_mode == DEM_DISABLED) { - de_update_conf(dep); - pci_init(); - if (dep->de_mode == DEM_ENABLED && !de_probe(dep, de_instance)) { - printf("%s: warning no ethernet card found at 0x%04X\n", - dep->de_name, dep->de_base_port); - dep->de_mode = DEM_DISABLED; - } - } - - r = OK; - - /* 'de_mode' may change if probe routines fail, test again */ - switch (dep->de_mode) { - - case DEM_DISABLED: - r = ENXIO; /* Device is OFF or hardware probe failed */ - break; - - case DEM_ENABLED: - if (dep->de_flags == DEF_EMPTY) { - de_first_init(dep); - dep->de_flags |= DEF_ENABLED; - de_reset(dep); - de_hw_conf(dep); - de_setup_frame(dep); - de_start(dep); - } - - /* TODO CHECK PROMISC AND MULTI */ - dep->de_flags &= NOT(DEF_PROMISC | DEF_MULTI | DEF_BROAD); - if (mp->m_net_netdrv_dl_conf.mode & DL_PROMISC_REQ) - dep->de_flags |= DEF_PROMISC | DEF_MULTI | DEF_BROAD; - if (mp->m_net_netdrv_dl_conf.mode & DL_MULTI_REQ) - dep->de_flags |= DEF_MULTI; - if (mp->m_net_netdrv_dl_conf.mode & DL_BROAD_REQ) - dep->de_flags |= DEF_BROAD; - break; - - case DEM_SINK: - DEBUG(printf("%s running in sink mode\n", str_DevName)); - memset(dep->de_address.ea_addr, 0, sizeof(ether_addr_t)); - de_conf_addr(dep); - break; - - default: break; - } - - reply_mess.m_type = DL_CONF_REPLY; - reply_mess.m_netdrv_net_dl_conf.stat = r; - if(r == OK){ - memcpy(reply_mess.m_netdrv_net_dl_conf.hw_addr, dep->de_address.ea_addr, - sizeof(reply_mess.m_netdrv_net_dl_conf.hw_addr)); - } - - if (ipc_send(mp->m_source, &reply_mess) != OK) - panic("%s %d", str_SendErrMsg, mp->m_source); - - return; -} - -static void do_reply(dpeth_t * dep) -{ - message reply; - int r, flags = DL_NOFLAGS; - - if (dep->de_flags & DEF_ACK_SEND) flags |= DL_PACK_SEND; - if (dep->de_flags & DEF_ACK_RECV) flags |= DL_PACK_RECV; - - reply.m_type = DL_TASK_REPLY; - reply.m_netdrv_net_dl_task.flags = flags; - reply.m_netdrv_net_dl_task.count = dep->de_read_s; - - r = ipc_send(dep->de_client, &reply); - - if(r < 0) - panic("%s %d", str_SendErrMsg, r); - - dep->de_read_s = 0; - dep->de_flags &= NOT(DEF_ACK_SEND | DEF_ACK_RECV); - return; -} - -static void do_watchdog(void *UNUSED(message)) -{ - /* nothing here yet */ - return; -} - -static int de_probe(dpeth_t *dep, int skip) -{ - int i, r, devind; - u16_t vid, did, temp16; + int r, devind; + u16_t vid, did; DEBUG(printf("PROBING...")); - + + pci_init(); + r= pci_first_dev(&devind, &vid, &did); if (r == 0) return FALSE; @@ -314,40 +131,22 @@ static int de_probe(dpeth_t *dep, int skip) panic("de_probe: base address invalid: %d", dep->de_base_port); DEBUG(printf("%s: using I/O address 0x%lx, IRQ %d\n", - dep->de_name, (unsigned long)dep->de_base_port, + dep->de_name, (unsigned long)dep->de_base_port, dep->de_irq)); dep->de_type = pci_attr_r8(devind, PCI_REV); /* device validation. We support only the DEC21140A */ if(dep->de_type != DEC_21140A){ - dep->de_type = DE_TYPE_UNKNOWN; - printf("%s: unsupported device\n", str_DevName); + printf("%s: unsupported card type %x\n", dep->de_name, dep->de_type); return FALSE; } - de_reset(dep); - - DEBUG(printf("Reading SROM...\n")); - - for(i=0;i<(1<srom[i*2] = temp16 & 0xFF; - dep->srom[i*2+1] = temp16 >> 8; - } - - /* TODO: validate SROM content */ - /* acquire MAC addr */ - DEBUG(printf("Using MAC addr= ")); - for(i=0;i<6;i++){ - dep->de_address.ea_addr[i] = dep->srom[i+DE_SROM_EA_OFFSET]; - DEBUG(printf("%02X%c",dep->de_address.ea_addr[i],i!=5?'-':'\n')); - } - DEBUG(printf("probe success\n")); return TRUE; } -static u16_t de_read_rom(const dpeth_t *dep, u8_t addr, u8_t nbAddrBits){ +static u16_t de_read_rom(const dpeth_t *dep, u8_t addr, u8_t nbAddrBits) +{ u16_t retVal = 0; int i; u32_t csr = 0; @@ -356,7 +155,11 @@ static u16_t de_read_rom(const dpeth_t *dep, u8_t addr, u8_t nbAddrBits){ more readable, the following macro is also just to clear up the code a little.*/ - #define EMIT do { io_outl(CSR_ADDR(dep, CSR9), csr | csr2); io_outl(CSR_ADDR(dep, CSR1), 0);} while(0) +#define EMIT \ + do { \ + io_outl(CSR_ADDR(dep, CSR9), csr | csr2); \ + io_outl(CSR_ADDR(dep, CSR1), 0); \ + } while(0) /* init */ csr = 0; EMIT; @@ -404,180 +207,87 @@ static u16_t de_read_rom(const dpeth_t *dep, u8_t addr, u8_t nbAddrBits){ return retVal; } -static void de_update_conf(dpeth_t * dep) +static ssize_t do_recv(struct netdriver_data *data, size_t max) { - static char dpc_fmt[] = "x:d:x"; - char ec_key[16]; - long val; - - strlcpy(ec_key, "DEETH0", sizeof(ec_key)); - ec_key[5] += de_instance; - - dep->de_mode = DEM_ENABLED; - switch (env_parse(ec_key, dpc_fmt, 0, &val, 0x000L, 0x3FFL)) { - case EP_OFF: dep->de_mode = DEM_DISABLED; break; - case EP_ON: dep->de_mode = DEM_SINK; break; - } - dep->de_base_port = 0; - - return; -} - -static void do_vread_s(const message * mp, int from_int) -{ - u8_t *buffer; u32_t size; - int r, ix = 0; - vir_bytes bytes; - dpeth_t *dep = NULL; - de_loc_descr_t *descr = NULL; - iovec_dat_s_t *iovp = NULL; + dpeth_t *dep; + de_loc_descr_t *descr; dep = &de_state; - dep->de_client = mp->m_source; + descr = &dep->descr[DESCR_RECV][dep->cur_descr[DESCR_RECV]]; - if (dep->de_mode == DEM_ENABLED) { + /* check if packet is in the current descr and only there */ + if ((descr->descr->des[DES0] & DES0_OWN) || + !(descr->descr->des[DES0] & DES0_FS) || + !(descr->descr->des[DES0] & DES0_LS)) + return SUSPEND; - descr = &dep->descr[DESCR_RECV][dep->cur_descr[DESCR_RECV]]; + /*TODO: multi-descr msgs...*/ + /* We only support packets contained in a single descriptor. + Setting the descriptor buffer size to less then + ETH_MAX_PACK_SIZE will result in multi-descriptor + packets that we won't be able to handle + */ - /* check if packet is in the current descr and only there */ - if( !( !(descr->descr->des[DES0] & DES0_OWN) && - (descr->descr->des[DES0] & DES0_FS) && - (descr->descr->des[DES0] & DES0_LS) )) - goto suspend; + /* Check for abnormal messages. We assert here + because this driver is for a virtualized + envrionment where we will not get bad packets + */ + assert(!(descr->descr->des[DES0]&DES0_ES)); + assert(!(descr->descr->des[DES0]&DES0_RE)); + /* Copy buffer to user area and clear ownage */ + size = (descr->descr->des[DES0]&DES0_FL)>>DES0_FL_SHIFT; - /*TODO: multi-descr msgs...*/ - /* We only support packets contained in a single descriptor. - Setting the descriptor buffer size to less then - ETH_MAX_PACK_SIZE will result in multi-descriptor - packets that we won't be able to handle - */ - assert(!(descr->descr->des[DES0]&DES0_OWN)); - assert(descr->descr->des[DES0]&DES0_FS); - assert(descr->descr->des[DES0]&DES0_LS); - - /* Check for abnormal messages. We assert here - because this driver is for a virtualized - envrionment where we will not get bad packets - */ - assert(!(descr->descr->des[DES0]&DES0_ES)); - assert(!(descr->descr->des[DES0]&DES0_RE)); - - - /* Setup the iovec entry to allow copying into - client layer - */ - dep->de_read_iovec.iod_proc_nr = mp->m_source; - de_get_userdata_s(mp->m_source, mp->m_net_netdrv_dl_readv_s.grant, 0, - mp->m_net_netdrv_dl_readv_s.count, - dep->de_read_iovec.iod_iovec); - dep->de_read_iovec.iod_iovec_s = mp->m_net_netdrv_dl_readv_s.count; - dep->de_read_iovec.iod_grant = mp->m_net_netdrv_dl_readv_s.grant; - dep->de_read_iovec.iod_iovec_offset = 0; - size = de_calc_iov_size(&dep->de_read_iovec); - if (size < ETH_MAX_PACK_SIZE) - panic("%s %d", str_SizeErrMsg, size); - - /* Copy buffer to user area and clear ownage */ - size = (descr->descr->des[DES0]&DES0_FL)>>DES0_FL_SHIFT; - - /*TODO: Complain to MS */ - /*HACK: VPC2007 returns packet of invalid size. Ethernet standard - specify 46 bytes as the minimum for valid payload. However, this is - artificial in so far as for certain packet types, notably ARP, less - then 46 bytes are needed to contain the full information. In a non - virtualized environment the 46 bytes rule is enforced in order to give - guarantee in the collison detection scheme. Of course, this being a - driver for a VPC2007, we won't have collisions and I can only suppose - MS decided to cut packet size to true minimum, regardless of the - 46 bytes payload standard. Note that this seems to not happen in - bridged mode. Note also, that the card does not return runt or - incomplete frames to us, so this hack is safe - */ - if(size<60){ - memset(&descr->buf1[size], 0, 60-size); - size=60; - } - /* End ugly hack */ - - iovp = &dep->de_read_iovec; - buffer = descr->buf1; - dep->bytes_rx += size; - dep->de_stat.ets_packetR++; - dep->de_read_s = size; - - do { - bytes = iovp->iod_iovec[ix].iov_size; /* Size of buffer */ - if (bytes >= size) - bytes = size; - - r= sys_safecopyto(iovp->iod_proc_nr, iovp->iod_iovec[ix].iov_grant, 0, - (vir_bytes)buffer, bytes); - if (r != OK) - panic("%s %d", str_CopyErrMsg, r); - buffer += bytes; - - if (++ix >= IOVEC_NR) { /* Next buffer of IO vector */ - de_next_iov(iovp); - ix = 0; - } - } while ((size -= bytes) > 0); - - descr->descr->des[DES0]=DES0_OWN; - dep->cur_descr[DESCR_RECV]++; - if(dep->cur_descr[DESCR_RECV] >= DE_NB_RECV_DESCR) - dep->cur_descr[DESCR_RECV] = 0; - - DEBUG(printf("Read returned size = %d\n", size)); - - /* Reply information */ - dep->de_flags |= DEF_ACK_RECV; - dep->de_flags &= NOT(DEF_READING); + /* HACK: VPC2007 sends short-sized packets, pad to minimum ethernet length */ + if(size<60){ + memset(&descr->buf1[size], 0, 60-size); + size=60; } - if(!from_int){ - do_reply(dep); - } - return; + /* Truncate large packets */ + if (size > max) + size = max; - suspend: - if(from_int){ - assert(dep->de_flags & DEF_READING); - return; - } + netdriver_copyout(data, 0, descr->buf1, size); - assert(!(dep->de_flags & DEF_READING)); - dep->rx_return_msg = *mp; - dep->de_flags |= DEF_READING; - do_reply(dep); - return; + dep->de_stat.ets_packetR++; + + descr->descr->des[DES0]=DES0_OWN; + dep->cur_descr[DESCR_RECV]++; + if(dep->cur_descr[DESCR_RECV] >= DE_NB_RECV_DESCR) + dep->cur_descr[DESCR_RECV] = 0; + + DEBUG(printf("Read returned size = %d\n", size)); + + return size; } -static void de_conf_addr(dpeth_t * dep) +static void de_conf_addr(dpeth_t *dep, ether_addr_t *addr) { - static char ea_fmt[] = "x:x:x:x:x:x"; - char ea_key[16]; - int ix; - long val; + u16_t temp16; + int i; - strlcpy(ea_key, "DEETH0_EA", sizeof(ea_key)); - ea_key[5] += de_instance; + DEBUG(printf("Reading SROM...\n")); - for (ix = 0; ix < SA_ADDR_LEN; ix++) { - val = dep->de_address.ea_addr[ix]; - if (env_parse(ea_key, ea_fmt, ix, &val, 0x00L, 0xFFL) != EP_SET) - break; - dep->de_address.ea_addr[ix] = val; + for(i=0;i<(1<srom[i*2] = temp16 & 0xFF; + dep->srom[i*2+1] = temp16 >> 8; } - if (ix != 0 && ix != SA_ADDR_LEN) - env_parse(ea_key, "?", 0, &val, 0L, 0L); - return; + /* TODO: validate SROM content */ + /* acquire MAC addr */ + DEBUG(printf("Using MAC addr= ")); + for(i=0;i<6;i++){ + addr->ea_addr[i] = dep->srom[i+DE_SROM_EA_OFFSET]; + DEBUG(printf("%02X%c", addr->ea_addr[i],i!=5?'-':'\n')); + } + DEBUG(printf("probe success\n")); } -static void de_first_init(dpeth_t *dep) +static void de_init_buf(dpeth_t *dep) { int i,j,r; vir_bytes descr_vir = (vir_bytes)dep->sendrecv_descr_buf; @@ -585,7 +295,6 @@ static void de_first_init(dpeth_t *dep) de_loc_descr_t *loc_descr; phys_bytes temp; - for(i=0;i<2;i++){ loc_descr = &dep->descr[i][0]; for(j=0; j < (i==DESCR_RECV ? DE_NB_RECV_DESCR : DE_NB_SEND_DESCR); j++){ @@ -595,7 +304,7 @@ static void de_first_init(dpeth_t *dep) descr_vir += sizeof(de_descr_t); /* assign space for buffer */ - loc_descr->buf1 = (u8_t*)buffer_vir; + loc_descr->buf1 = (u8_t*)buffer_vir; buffer_vir += (i==DESCR_RECV ? DE_RECV_BUF_SIZE : DE_SEND_BUF_SIZE); loc_descr->buf2 = 0; loc_descr++; @@ -610,9 +319,9 @@ static void de_first_init(dpeth_t *dep) temp = (i==DESCR_RECV ? DE_RECV_BUF_SIZE : DE_SEND_BUF_SIZE); for(j=0; j < (i==DESCR_RECV ? DE_NB_RECV_DESCR : DE_NB_SEND_DESCR); j++){ /* translate buffers physical address */ - r = sys_umap(SELF, VM_D, (vir_bytes)loc_descr->buf1, temp, + r = sys_umap(SELF, VM_D, (vir_bytes)loc_descr->buf1, temp, (phys_bytes *) &(loc_descr->descr->des[DES_BUF1])); - if(r != OK) panic("umap failed: %d", r); + if(r != OK) panic("umap failed: %d", r); loc_descr->descr->des[DES_BUF2] = 0; memset(&loc_descr->descr->des[DES0],0,sizeof(u32_t)); loc_descr->descr->des[DES1] = temp; @@ -623,15 +332,15 @@ static void de_first_init(dpeth_t *dep) loc_descr++; } } - + /* record physical location of two first descriptor */ - r = sys_umap(SELF, VM_D, (vir_bytes)dep->descr[DESCR_RECV][0].descr, + r = sys_umap(SELF, VM_D, (vir_bytes)dep->descr[DESCR_RECV][0].descr, sizeof(de_descr_t), &dep->sendrecv_descr_phys_addr[DESCR_RECV]); - if(r != OK) panic("%s %d", str_UmapErrMsg, r); + if(r != OK) panic("sys_umap failed: %d", r); r = sys_umap(SELF, VM_D, (vir_bytes)dep->descr[DESCR_TRAN][0].descr, sizeof(de_descr_t), &dep->sendrecv_descr_phys_addr[DESCR_TRAN]); - if(r != OK) panic("%s %d", str_UmapErrMsg, r); + if(r != OK) panic("sys_umap failed: %d", r); DEBUG(printf("Descr: head tran=[%08X] head recv=[%08X]\n", dep->sendrecv_descr_phys_addr[DESCR_TRAN], @@ -643,58 +352,59 @@ static void de_first_init(dpeth_t *dep) for(j=0;j< (i==DESCR_RECV?DE_NB_RECV_DESCR:DE_NB_SEND_DESCR);j++){ r = sys_umap(SELF, VM_D, (vir_bytes)&(loc_descr->descr), sizeof(de_descr_t), &temp); - if(r != OK) - panic("%s %d", str_UmapErrMsg, r); + if(r != OK) panic("sys_umap failed: %d", r); if( ((loc_descr->descr->des[DES_BUF1] & 0x3) != 0) || ((loc_descr->descr->des[DES_BUF2] & 0x3) != 0) || ((temp&0x3)!=0) ) - panic("%s 0x%lx", str_AlignErrMsg, temp); + panic("alignment error: 0x%lx", temp); loc_descr++; } } - + /* Init default values */ dep->cur_descr[DESCR_TRAN]=1; dep->cur_descr[DESCR_RECV]=0; - dep->bytes_rx = 0; - dep->bytes_tx = 0; - - /* Set the interrupt handler policy. Request interrupts not to be reenabled - * automatically. Return the IRQ line number when an interrupt occurs. - */ - dep->de_hook = dep->de_irq; - sys_irqsetpolicy(dep->de_irq, 0, &dep->de_hook); - sys_irqenable(&dep->de_hook); } -static void do_interrupt(const dpeth_t *dep){ +static void do_intr(unsigned int __unused mask) +{ + dpeth_t *dep; u32_t val; + + dep = &de_state; + val = io_inl(CSR_ADDR(dep, CSR5)); if(val & CSR5_AIS){ panic("Abnormal Int CSR5=: %d", val); } - if( (dep->de_flags & DEF_READING) && (val & CSR5_RI) ){ - do_vread_s(&dep->rx_return_msg, TRUE); - } - - if( (dep->de_flags & DEF_SENDING) && (val & CSR5_TI) ){ - do_vwrite_s(&dep->tx_return_msg, TRUE); - } - + if (val & CSR5_RI) + netdriver_recv(); + + if (val & CSR5_TI) + netdriver_send(); + /* ack and reset interrupts */ io_outl(CSR_ADDR(dep, CSR5), 0xFFFFFFFF); - return; + + sys_irqenable(&dep->de_hook); } -static void de_reset(const dpeth_t *dep){ +static void de_reset(const dpeth_t *dep) +{ io_outl(CSR_ADDR(dep, CSR0), CSR0_SWR); } -static void de_hw_conf(const dpeth_t *dep){ +static void do_stop(void) +{ + de_reset(&de_state); +} + +static void de_hw_conf(const dpeth_t *dep) +{ u32_t val; /* CSR0 - global host bus prop */ @@ -714,18 +424,20 @@ static void de_hw_conf(const dpeth_t *dep){ io_outl(CSR_ADDR(dep, CSR7), val); /* CSR6 - operating mode register */ - val = CSR6_MBO | CSR6_PS | CSR6_FD | CSR6_HBD | + val = CSR6_MBO | CSR6_PS | CSR6_FD | CSR6_HBD | CSR6_PCS | CSR6_SCR | CSR6_TR_00; io_outl(CSR_ADDR(dep, CSR6), val); } -static void de_start(const dpeth_t *dep){ +static void de_start(const dpeth_t *dep) +{ u32_t val; val = io_inl(CSR_ADDR(dep, CSR6)) | CSR6_ST | CSR6_SR; io_outl(CSR_ADDR(dep, CSR6), val); } -static void de_setup_frame(const dpeth_t *dep){ +static void de_setup_frame(const dpeth_t *dep, const ether_addr_t *addr) +{ int i; u32_t val; @@ -739,165 +451,71 @@ static void de_setup_frame(const dpeth_t *dep){ dep->descr[DESCR_TRAN][0].buf1[9] = 0xFF; for(i=1;i<16;i++){ memset(&(dep->descr[DESCR_TRAN][0].buf1[12*i]), 0, 12); - dep->descr[DESCR_TRAN][0].buf1[12*i+0] = dep->de_address.ea_addr[0]; - dep->descr[DESCR_TRAN][0].buf1[12*i+1] = dep->de_address.ea_addr[1]; - dep->descr[DESCR_TRAN][0].buf1[12*i+4] = dep->de_address.ea_addr[2]; - dep->descr[DESCR_TRAN][0].buf1[12*i+5] = dep->de_address.ea_addr[3]; - dep->descr[DESCR_TRAN][0].buf1[12*i+8] = dep->de_address.ea_addr[4]; - dep->descr[DESCR_TRAN][0].buf1[12*i+9] = dep->de_address.ea_addr[5]; + dep->descr[DESCR_TRAN][0].buf1[12*i+0] = addr->ea_addr[0]; + dep->descr[DESCR_TRAN][0].buf1[12*i+1] = addr->ea_addr[1]; + dep->descr[DESCR_TRAN][0].buf1[12*i+4] = addr->ea_addr[2]; + dep->descr[DESCR_TRAN][0].buf1[12*i+5] = addr->ea_addr[3]; + dep->descr[DESCR_TRAN][0].buf1[12*i+8] = addr->ea_addr[4]; + dep->descr[DESCR_TRAN][0].buf1[12*i+9] = addr->ea_addr[5]; } dep->descr[DESCR_TRAN][0].descr->des[DES0] = DES0_OWN; - dep->descr[DESCR_TRAN][0].descr->des[DES1] = DES1_SET | + dep->descr[DESCR_TRAN][0].descr->des[DES1] = DES1_SET | DE_SETUP_FRAME_SIZE | DES1_IC; /* start transmit process to process setup frame */ val = io_inl(CSR_ADDR(dep, CSR6)) | CSR6_ST; - io_outl(CSR_ADDR(dep, CSR6), val); + io_outl(CSR_ADDR(dep, CSR6), val); io_outl(CSR_ADDR(dep, CSR1), 0xFFFFFFFF); - - return; } -static int de_calc_iov_size(iovec_dat_s_t * iovp){ - int size, ix; - size = ix = 0; - - do{ - size += iovp->iod_iovec[ix].iov_size; - if (++ix >= IOVEC_NR) { - de_next_iov(iovp); - ix = 0; - } - } while (ix < iovp->iod_iovec_s); - return size; -} - -static void de_get_userdata_s(int user_proc, cp_grant_id_t grant, - vir_bytes offset, int count, void *loc_addr){ - int rc; - vir_bytes len; - - len = (count > IOVEC_NR ? IOVEC_NR : count) * sizeof(iovec_t); - rc = sys_safecopyfrom(user_proc, grant, 0, (vir_bytes)loc_addr, len); - if (rc != OK) - panic("%s %d", str_CopyErrMsg, rc); - return; -} - -static void de_next_iov(iovec_dat_s_t * iovp){ - - iovp->iod_iovec_s -= IOVEC_NR; - iovp->iod_iovec_offset += IOVEC_NR * sizeof(iovec_t); - de_get_userdata_s(iovp->iod_proc_nr, iovp->iod_grant, iovp->iod_iovec_offset, - iovp->iod_iovec_s, iovp->iod_iovec); - return; -} - -static void do_vwrite_s(const message * mp, int from_int){ - static u8_t setupDone = 0; - int size, r, bytes, ix, totalsize; +static int do_send(struct netdriver_data *data, size_t size) +{ + static int setup_done = 0; dpeth_t *dep; - iovec_dat_s_t *iovp = NULL; de_loc_descr_t *descr = NULL; - u8_t *buffer = NULL; dep = &de_state; - dep->de_client = mp->m_source; + descr = &dep->descr[DESCR_TRAN][dep->cur_descr[DESCR_TRAN]]; - if (dep->de_mode == DEM_ENABLED) { - - if (!from_int && (dep->de_flags & DEF_SENDING)) - panic("%s", str_BusyErrMsg); + if(( descr->descr->des[DES0] & DES0_OWN)!=0) + return SUSPEND; - descr = &dep->descr[DESCR_TRAN][dep->cur_descr[DESCR_TRAN]]; - - if(( descr->descr->des[DES0] & DES0_OWN)!=0) - goto suspend; - - if(!setupDone && (dep->cur_descr[DESCR_TRAN] == 0) ){ - dep->descr[DESCR_TRAN][0].descr->des[DES0] = 0; - setupDone=1; - } - - buffer = descr->buf1; - iovp = &dep->de_write_iovec; - iovp->iod_proc_nr = mp->m_source; - de_get_userdata_s(mp->m_source, mp->m_net_netdrv_dl_writev_s.grant, 0, - mp->m_net_netdrv_dl_writev_s.count, iovp->iod_iovec); - iovp->iod_iovec_s = mp->m_net_netdrv_dl_writev_s.count; - iovp->iod_grant = mp->m_net_netdrv_dl_writev_s.grant; - iovp->iod_iovec_offset = 0; - totalsize = size = de_calc_iov_size(iovp); - if (size < ETH_MIN_PACK_SIZE || size > ETH_MAX_PACK_SIZE) - panic("%s %d", str_SizeErrMsg, size); - - dep->bytes_tx += size; - dep->de_stat.ets_packetT++; - - ix=0; - do { - bytes = iovp->iod_iovec[ix].iov_size; - if (bytes >= size) - bytes = size; - - r= sys_safecopyfrom(iovp->iod_proc_nr, iovp->iod_iovec[ix].iov_grant, - 0, (vir_bytes)buffer, bytes); - if (r != OK) - panic("%s %d", str_CopyErrMsg, r); - buffer += bytes; - - if (++ix >= IOVEC_NR) { - de_next_iov(iovp); - ix = 0; - } - } while ((size -= bytes) > 0); - - descr->descr->des[DES1] = (descr->descr->des[DES1]&DES1_ER) | - DES1_FS | DES1_LS | DES1_IC | totalsize; - descr->descr->des[DES0] = DES0_OWN; - - dep->cur_descr[DESCR_TRAN]++; - if(dep->cur_descr[DESCR_TRAN] >= DE_NB_SEND_DESCR) - dep->cur_descr[DESCR_TRAN] = 0; - - io_outl(CSR_ADDR(dep, CSR1), 0xFFFFFFFF); + if(!setup_done && (dep->cur_descr[DESCR_TRAN] == 0) ){ + dep->descr[DESCR_TRAN][0].descr->des[DES0] = 0; + setup_done=1; } - - dep->de_flags |= DEF_ACK_SEND; - if(from_int){ - dep->de_flags &= NOT(DEF_SENDING); - return; - } - do_reply(dep); - return; - suspend: - if(from_int) - panic("should not happen: %d", 0); + netdriver_copyin(data, 0, descr->buf1, size); - dep->de_stat.ets_transDef++; - dep->de_flags |= DEF_SENDING; - dep->de_stat.ets_transDef++; - dep->tx_return_msg = *mp; - do_reply(dep); + descr->descr->des[DES1] = (descr->descr->des[DES1]&DES1_ER) | + DES1_FS | DES1_LS | DES1_IC | size; + descr->descr->des[DES0] = DES0_OWN; + + dep->cur_descr[DESCR_TRAN]++; + if(dep->cur_descr[DESCR_TRAN] >= DE_NB_SEND_DESCR) + dep->cur_descr[DESCR_TRAN] = 0; + + io_outl(CSR_ADDR(dep, CSR1), 0xFFFFFFFF); + + dep->de_stat.ets_packetT++; + + return OK; } -static void warning(const char *type, int err){ - printf("Warning: %s sys_%s failed (%d)\n", str_DevName, type, err); - return; -} - -static u32_t io_inl(u16_t port){ +static u32_t io_inl(u16_t port) +{ u32_t value; int rc; - if ((rc = sys_inl(port, &value)) != OK) warning("inl", rc); + if ((rc = sys_inl(port, &value)) != OK) + panic("sys_inl failed: %d", rc); return value; } -static void io_outl(u16_t port, u32_t value){ +static void io_outl(u16_t port, u32_t value) +{ int rc; - if ((rc = sys_outl(port, value)) != OK) warning("outl", rc); - return; + if ((rc = sys_outl(port, value)) != OK) + panic("sys_outl failed: %d", rc); } diff --git a/minix/drivers/net/dec21140A/dec21140A.h b/minix/drivers/net/dec21140A/dec21140A.h index 6a8b4ea95..74f8af910 100644 --- a/minix/drivers/net/dec21140A/dec21140A.h +++ b/minix/drivers/net/dec21140A/dec21140A.h @@ -11,37 +11,21 @@ Created: 09/01/2009 Nicolas Tittley (first.last @ gmail DOT com) #include -#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< +#include #include #include diff --git a/minix/drivers/net/dp8390/Makefile b/minix/drivers/net/dp8390/Makefile index 0fcbcc86d..d48227ef7 100644 --- a/minix/drivers/net/dp8390/Makefile +++ b/minix/drivers/net/dp8390/Makefile @@ -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 diff --git a/minix/drivers/net/dp8390/dp8390.c b/minix/drivers/net/dp8390/dp8390.c index 3d23db40b..c68d634cb 100644 --- a/minix/drivers/net/dp8390/dp8390.c +++ b/minix/drivers/net/dp8390/dp8390.c @@ -16,14 +16,7 @@ #include #include -#include -#include -#include -#include #include -#include -#include -#include #include #include "assert.h" @@ -70,203 +63,100 @@ static dp_conf_t dp_conf[DP_CONF_NR]= /* Card addresses */ */ #define CR_EXTRA CR_STA -#if ENABLE_PCI +static int do_init(unsigned int instance, ether_addr_t *addr); static void pci_conf(void); -#endif -static void do_vwrite_s(message *mp, int from_int); -static void do_vread_s(message *mp); -static void do_init(message *mp); -static void do_int(dpeth_t *dep); -static void do_getstat_s(message *mp); -static void dp_stop(dpeth_t *dep); +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_mode(unsigned int mode); +static void do_stat(eth_stat_t *stat); +static void do_stop(void); static void dp_init(dpeth_t *dep); static void dp_confaddr(dpeth_t *dep); -static void dp_reinit(dpeth_t *dep); static void dp_reset(dpeth_t *dep); -static void dp_check_ints(dpeth_t *dep); -static void dp_recv(dpeth_t *dep); -static void dp_send(dpeth_t *dep); +static void do_intr(unsigned int mask); static void dp_getblock(dpeth_t *dep, int page, size_t offset, size_t size, void *dst); static void dp_pio8_getblock(dpeth_t *dep, int page, size_t offset, size_t size, void *dst); static void dp_pio16_getblock(dpeth_t *dep, int page, size_t offset, size_t size, void *dst); -static int dp_pkt2user_s(dpeth_t *dep, int page, vir_bytes length); -static void dp_user2nic_s(dpeth_t *dep, iovec_dat_s_t *iovp, vir_bytes - offset, int nic_addr, vir_bytes count); -static void dp_pio8_user2nic_s(dpeth_t *dep, iovec_dat_s_t *iovp, - vir_bytes offset, int nic_addr, vir_bytes count); -static void dp_pio16_user2nic_s(dpeth_t *dep, iovec_dat_s_t *iovp, - vir_bytes offset, int nic_addr, vir_bytes count); -static void dp_nic2user_s(dpeth_t *dep, int nic_addr, iovec_dat_s_t - *iovp, vir_bytes offset, vir_bytes count); -static void dp_pio8_nic2user_s(dpeth_t *dep, int nic_addr, iovec_dat_s_t - *iovp, vir_bytes offset, vir_bytes count); -static void dp_pio16_nic2user_s(dpeth_t *dep, int nic_addr, - iovec_dat_s_t *iovp, vir_bytes offset, vir_bytes count); -static void dp_next_iovec_s(iovec_dat_s_t *iovp); +static void dp_pkt2user_s(dpeth_t *dep, struct netdriver_data *data, int page, + size_t length); +static void dp_user2nic_s(dpeth_t *dep, struct netdriver_data *data, + int nic_addr, size_t offset, size_t count); +static void dp_pio8_user2nic_s(dpeth_t *dep, struct netdriver_data *data, + int nic_addr, size_t offset, size_t count); +static void dp_pio16_user2nic_s(dpeth_t *dep, struct netdriver_data *data, + int nic_addr, size_t offset, size_t count); +static void dp_nic2user_s(dpeth_t *dep, struct netdriver_data *data, + int nic_addr, size_t offset, size_t count); +static void dp_pio8_nic2user_s(dpeth_t *dep, struct netdriver_data *data, + int nic_addr, size_t offset, size_t count); +static void dp_pio16_nic2user_s(dpeth_t *dep, struct netdriver_data *data, + int nic_addr, size_t offset, size_t count); static void conf_hw(dpeth_t *dep); static void update_conf(dpeth_t *dep, dp_conf_t *dcp); static void map_hw_buffer(dpeth_t *dep); -static int calc_iovec_size_s(iovec_dat_s_t *iovp); -static void reply(dpeth_t *dep); -static void mess_reply(message *req, message *reply); -static void get_userdata_s(int user_proc, cp_grant_id_t grant, vir_bytes - offset, vir_bytes count, void *loc_addr); -static void put_userdata_s(int user_proc, cp_grant_id_t grant, size_t - count, void *loc_addr); static void insb(port_t port, void *buf, size_t size); static void insw(port_t port, void *buf, size_t size); -static void do_vir_insb(port_t port, int proc, vir_bytes buf, size_t - size); -static void do_vir_insw(port_t port, int proc, vir_bytes buf, size_t - size); -/* 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); - -static void handle_hw_intr(void) -{ - int r, irq; - dpeth_t *dep; - - dep = &de_state; - - if (dep->de_mode != DEM_ENABLED) - return; - assert(dep->de_flags & DEF_ENABLED); - irq= dep->de_irq; - assert(irq >= 0 && irq < NR_IRQ_VECTORS); - if (dep->de_int_pending || 1) - { - dep->de_int_pending= 0; - dp_check_ints(dep); - do_int(dep); - r= sys_irqenable(&dep->de_hook); - if (r != OK) { - panic("unable enable interrupts: %d", r); - } - } -} +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 +}; /*===========================================================================* - * dpeth_task * + * main * *===========================================================================*/ int main(int argc, char *argv[]) { - message m; - int ipc_status; - int r; - - /* SEF local startup. */ env_setargs(argc, argv); - sef_local_startup(); - while (TRUE) - { - if ((r= netdriver_receive(ANY, &m, &ipc_status)) != OK) - panic("dp8390: netdriver_receive failed: %d", r); + netdriver_task(&dp_table); - if (is_ipc_notify(ipc_status)) { - switch (_ENDPOINT_P(m.m_source)) { - case HARDWARE: - handle_hw_intr(); - break; - case CLOCK: - printf("dp8390: notify from CLOCK\n"); - break; - default: - panic("dp8390: illegal notify from: %d", - m.m_source); - } - - /* done, get a new message */ - continue; - } - - switch (m.m_type) - { - case DL_WRITEV_S: do_vwrite_s(&m, FALSE); break; - case DL_READV_S: do_vread_s(&m); break; - case DL_CONF: do_init(&m); break; - case DL_GETSTAT_S: do_getstat_s(&m); break; - default: - panic("dp8390: illegal message: %d", m.m_type); - } - } + return 0; } /*===========================================================================* - * sef_local_startup * + * do_init * *===========================================================================*/ -static void sef_local_startup() -{ - /* Register init callbacks. */ - sef_setcb_init_fresh(sef_cb_init_fresh); - sef_setcb_init_lu(sef_cb_init_fresh); - sef_setcb_init_restart(sef_cb_init_fresh); - - /* Register live update callbacks. */ - sef_setcb_lu_prepare(sef_cb_lu_prepare_always_ready); - sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid_workfree); - - /* Register signal callbacks. */ - sef_setcb_signal_handler(sef_cb_signal_handler); - - /* Let SEF perform startup. */ - sef_startup(); -} - -/*===========================================================================* - * sef_cb_init_fresh * - *===========================================================================*/ -static int sef_cb_init_fresh(int type, sef_init_info_t *UNUSED(info)) +static int do_init(unsigned int instance, ether_addr_t *addr) { /* Initialize the dp8390 driver. */ dpeth_t *dep; - long v; system_hz = sys_hz(); - if (env_argc < 1) { - panic("A head which at this time has no name"); - } - - v = 0; - (void) env_parse("instance", "d", 0, &v, 0, 255); - de_instance = (int) v; + de_instance = instance; dep = &de_state; + memset(dep, 0, sizeof(*dep)); strlcpy(dep->de_name, "dp8390#0", sizeof(dep->de_name)); dep->de_name[7] += de_instance; - /* Announce we are up! */ - netdriver_announce(); + pci_conf(); /* Configure PCI devices. */ - return(OK); -} + /* This is the default, try to (re)locate the device. */ + conf_hw(dep); -/*===========================================================================* - * sef_cb_signal_handler * - *===========================================================================*/ -static void sef_cb_signal_handler(int signo) -{ - /* Only check for termination signal, ignore anything else. */ - if (signo != SIGTERM) return; + dp_init(dep); - if (de_state.de_mode == DEM_ENABLED) - dp_stop(&de_state); + memcpy(addr, dep->de_address.ea_addr, sizeof(*addr)); + + return OK; } #if 0 /*===========================================================================* * dp8390_dump * *===========================================================================*/ -void dp8390_dump() +void dp8390_dump(void) { dpeth_t *dep; int isr; @@ -274,16 +164,6 @@ void dp8390_dump() dep = &de_state; printf("\n"); -#if XXX - if (dep->de_mode == DEM_DISABLED) - printf("dp8390 instance %d is disabled\n", de_instance); - else if (dep->de_mode == DEM_SINK) - printf("dp8390 instance %d is in sink mode\n", de_instance); -#endif - - if (dep->de_mode != DEM_ENABLED) - return; - printf("dp8390 statistics of instance %d:\n", de_instance); printf("recvErr :%8ld\t", dep->de_stat.ets_recvErr); @@ -314,20 +194,14 @@ void dp8390_dump() } #endif -#if ENABLE_PCI /*===========================================================================* * pci_conf * *===========================================================================*/ -static void pci_conf() +static void pci_conf(void) { char envvar[16]; struct dpeth *dep; int i, pci_instance; - static int first_time= 1; - - if (!first_time) - return; - first_time= 0; dep= &de_state; @@ -347,69 +221,26 @@ static void pci_conf() } if (!rtl_probe(dep, pci_instance)) - dep->de_pci= -1; + panic("no matching PCI device found"); } -#endif /* ENABLE_PCI */ /*===========================================================================* - * do_vwrite_s * + * do_send * *===========================================================================*/ -static void do_vwrite_s(mp, from_int) -message *mp; -int from_int; +static int do_send(struct netdriver_data *data, size_t size) { - int count, size; int sendq_head; dpeth_t *dep; dep= &de_state; - count = mp->m_net_netdrv_dl_writev_s.count; - dep->de_client= mp->m_source; - - if (dep->de_mode == DEM_SINK) - { - assert(!from_int); - dep->de_flags |= DEF_PACK_SEND; - reply(dep); - return; - } - assert(dep->de_mode == DEM_ENABLED); - assert(dep->de_flags & DEF_ENABLED); - if (dep->de_flags & DEF_SEND_AVAIL) - panic("dp8390: send already in progress"); - sendq_head= dep->de_sendq_head; if (dep->de_sendq[sendq_head].sq_filled) - { - if (from_int) - panic("dp8390: should not be sending"); - dep->de_sendmsg= *mp; - dep->de_flags |= DEF_SEND_AVAIL; - reply(dep); - return; - } - assert(!(dep->de_flags & DEF_PACK_SEND)); + return SUSPEND; - get_userdata_s(mp->m_source, mp->m_net_netdrv_dl_writev_s.grant, 0, - (count > IOVEC_NR ? IOVEC_NR : count) * - sizeof(dep->de_write_iovec_s.iod_iovec[0]), - dep->de_write_iovec_s.iod_iovec); - dep->de_write_iovec_s.iod_iovec_s = count; - dep->de_write_iovec_s.iod_proc_nr = mp->m_source; - dep->de_write_iovec_s.iod_grant = mp->m_net_netdrv_dl_writev_s.grant; - dep->de_write_iovec_s.iod_iovec_offset = 0; + (dep->de_user2nicf_s)(dep, data, + dep->de_sendq[sendq_head].sq_sendpage * DP_PAGESIZE, 0, size); - dep->de_tmp_iovec_s = dep->de_write_iovec_s; - size = calc_iovec_size_s(&dep->de_tmp_iovec_s); - - if (size < ETH_MIN_PACK_SIZE || size > ETH_MAX_PACK_SIZE_TAGGED) - { - panic("dp8390: invalid packet size: %d", size); - } - (dep->de_user2nicf_s)(dep, &dep->de_write_iovec_s, 0, - dep->de_sendq[sendq_head].sq_sendpage * DP_PAGESIZE, - size); dep->de_sendq[sendq_head].sq_filled= TRUE; if (dep->de_sendq_tail == sendq_head) { @@ -426,215 +257,65 @@ int from_int; assert(sendq_head < SENDQ_NR); dep->de_sendq_head= sendq_head; - dep->de_flags |= DEF_PACK_SEND; - - /* If the interrupt handler called, don't send a reply. The reply - * will be sent after all interrupts are handled. - */ - if (from_int) - return; - reply(dep); - - assert(dep->de_mode == DEM_ENABLED); - assert(dep->de_flags & DEF_ENABLED); + return OK; } /*===========================================================================* - * do_vread_s * + * do_mode * *===========================================================================*/ -static void do_vread_s(mp) -message *mp; +static void do_mode(unsigned int mode) +{ + dpeth_t *dep; + int dp_rcr_reg; + + dep = &de_state; + + outb_reg0(dep, DP_CR, CR_PS_P0 | CR_EXTRA); + + dp_rcr_reg = 0; + if (mode & NDEV_PROMISC) + dp_rcr_reg |= RCR_AB | RCR_PRO | RCR_AM; + if (mode & NDEV_BROAD) + dp_rcr_reg |= RCR_AB; + if (mode & NDEV_MULTI) + dp_rcr_reg |= RCR_AM; + outb_reg0(dep, DP_RCR, dp_rcr_reg); +} + +/*===========================================================================* + * do_stat * + *===========================================================================*/ +static void do_stat(eth_stat_t *stat) { - int count; - int size; dpeth_t *dep; dep= &de_state; - count = mp->m_net_netdrv_dl_readv_s.count; - dep->de_client= mp->m_source; - if (dep->de_mode == DEM_SINK) - { - reply(dep); - return; - } - assert(dep->de_mode == DEM_ENABLED); - assert(dep->de_flags & DEF_ENABLED); - - if(dep->de_flags & DEF_READING) - panic("dp8390: read already in progress"); - - get_userdata_s(mp->m_source, mp->m_net_netdrv_dl_readv_s.grant, 0, - (count > IOVEC_NR ? IOVEC_NR : count) * - sizeof(dep->de_read_iovec_s.iod_iovec[0]), - dep->de_read_iovec_s.iod_iovec); - dep->de_read_iovec_s.iod_iovec_s = count; - dep->de_read_iovec_s.iod_proc_nr = mp->m_source; - dep->de_read_iovec_s.iod_grant = mp->m_net_netdrv_dl_readv_s.grant; - dep->de_read_iovec_s.iod_iovec_offset = 0; - - dep->de_tmp_iovec_s = dep->de_read_iovec_s; - size= calc_iovec_size_s(&dep->de_tmp_iovec_s); - - if (size < ETH_MAX_PACK_SIZE_TAGGED) - panic("dp8390: wrong packet size: %d", size); - dep->de_flags |= DEF_READING; - - dp_recv(dep); - - if ((dep->de_flags & (DEF_READING|DEF_STOPPED)) == - (DEF_READING|DEF_STOPPED)) - { - /* The chip is stopped, and all arrived packets are - * delivered. - */ - dp_reset(dep); - } - reply(dep); -} - -/*===========================================================================* - * do_init * - *===========================================================================*/ -static void do_init(message *mp) -{ - dpeth_t *dep; - message reply_mess; - -#if ENABLE_PCI - pci_conf(); /* Configure PCI devices. */ -#endif - - dep= &de_state; - - if (dep->de_mode == DEM_DISABLED) - { - /* This is the default, try to (re)locate the device. */ - conf_hw(dep); - if (dep->de_mode == DEM_DISABLED) - { - /* Probe failed, or the device is configured off. */ - reply_mess.m_type = DL_CONF_REPLY; - reply_mess.m_netdrv_net_dl_conf.stat = ENXIO; - mess_reply(mp, &reply_mess); - return; - } - if (dep->de_mode == DEM_ENABLED) - dp_init(dep); - } - - if (dep->de_mode == DEM_SINK) - { - strncpy((char *) dep->de_address.ea_addr, "ZDP", 6); - dep->de_address.ea_addr[5] = de_instance; - dp_confaddr(dep); - reply_mess.m_type = DL_CONF_REPLY; - reply_mess.m_netdrv_net_dl_conf.stat = 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)); - mess_reply(mp, &reply_mess); - return; - } - assert(dep->de_mode == DEM_ENABLED); - assert(dep->de_flags & DEF_ENABLED); - - dep->de_flags &= ~(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; - - dp_reinit(dep); - - reply_mess.m_type = DL_CONF_REPLY; - reply_mess.m_netdrv_net_dl_conf.stat = 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)); - - mess_reply(mp, &reply_mess); -} - -/*===========================================================================* - * do_int * - *===========================================================================*/ -static void do_int(dep) -dpeth_t *dep; -{ - if (dep->de_flags & (DEF_PACK_SEND | DEF_PACK_RECV)) - reply(dep); -} - -/*===========================================================================* - * do_getstat_s * - *===========================================================================*/ -static void do_getstat_s(mp) -message *mp; -{ - int r; - dpeth_t *dep; - - dep= &de_state; - - if (dep->de_mode == DEM_SINK) - { - put_userdata_s(mp->m_source, - mp->m_net_netdrv_dl_getstat_s.grant, - (vir_bytes) sizeof(dep->de_stat), &dep->de_stat); - - mp->m_type= DL_STAT_REPLY; - r= ipc_send(mp->m_source, mp); - if (r != OK) - panic("do_getstat: ipc_send failed: %d", r); - return; - } - assert(dep->de_mode == DEM_ENABLED); - assert(dep->de_flags & DEF_ENABLED); - dep->de_stat.ets_CRCerr += inb_reg0(dep, DP_CNTR0); dep->de_stat.ets_frameAll += inb_reg0(dep, DP_CNTR1); dep->de_stat.ets_missedP += inb_reg0(dep, DP_CNTR2); - put_userdata_s(mp->m_source, mp->m_net_netdrv_dl_getstat_s.grant, - sizeof(dep->de_stat), &dep->de_stat); - - mp->m_type= DL_STAT_REPLY; - r= ipc_send(mp->m_source, mp); - if (r != OK) - panic("do_getstat: ipc_send failed: %d", r); + memcpy(stat, &dep->de_stat, sizeof(*stat)); } /*===========================================================================* - * dp_stop * + * do_stop * *===========================================================================*/ -static void dp_stop(dep) -dpeth_t *dep; +static void do_stop(void) { + dpeth_t *dep; - if (dep->de_mode == DEM_SINK) - return; - assert(dep->de_mode == DEM_ENABLED); - - if (!(dep->de_flags & DEF_ENABLED)) - return; + dep = &de_state; outb_reg0(dep, DP_CR, CR_STP | CR_DM_ABORT); (dep->de_stopf)(dep); - - dep->de_flags= DEF_EMPTY; } /*===========================================================================* * dp_init * *===========================================================================*/ -static void dp_init(dep) -dpeth_t *dep; +static void dp_init(dpeth_t *dep) { - int dp_rcr_reg; int i, r; /* General initialization */ @@ -669,14 +350,7 @@ dpeth_t *dep; outb_reg0(dep, DP_RBCR0, 0); outb_reg0(dep, DP_RBCR1, 0); /* Step 4: */ - dp_rcr_reg = 0; - if (dep->de_flags & DEF_PROMISC) - dp_rcr_reg |= RCR_AB | RCR_PRO | RCR_AM; - if (dep->de_flags & DEF_BROAD) - dp_rcr_reg |= RCR_AB; - if (dep->de_flags & DEF_MULTI) - dp_rcr_reg |= RCR_AM; - outb_reg0(dep, DP_RCR, dp_rcr_reg); + outb_reg0(dep, DP_RCR, 0); /* Step 5: */ outb_reg0(dep, DP_TCR, TCR_INTERNAL); /* Step 6: */ @@ -718,7 +392,6 @@ dpeth_t *dep; inb_reg0(dep, DP_CNTR2); /* Finish the initialization. */ - dep->de_flags |= DEF_ENABLED; for (i= 0; ide_sendq_nr; i++) dep->de_sendq[i].sq_filled= 0; dep->de_sendq_head= 0; @@ -752,16 +425,13 @@ dpeth_t *dep; r= sys_irqenable(&dep->de_hook); if (r != OK) - { - panic("unable enable interrupts: %d", r); - } + panic("unable to enable interrupts: %d", r); } /*===========================================================================* * dp_confaddr * *===========================================================================*/ -static void dp_confaddr(dep) -dpeth_t *dep; +static void dp_confaddr(dpeth_t *dep) { int i; char eakey[16]; @@ -785,31 +455,10 @@ dpeth_t *dep; if (i != 0 && i != 6) env_panic(eakey); /* It's all or nothing */ } -/*===========================================================================* - * dp_reinit * - *===========================================================================*/ -static void dp_reinit(dep) -dpeth_t *dep; -{ - int dp_rcr_reg; - - outb_reg0(dep, DP_CR, CR_PS_P0 | CR_EXTRA); - - dp_rcr_reg = 0; - if (dep->de_flags & DEF_PROMISC) - dp_rcr_reg |= RCR_AB | RCR_PRO | RCR_AM; - if (dep->de_flags & DEF_BROAD) - dp_rcr_reg |= RCR_AB; - if (dep->de_flags & DEF_MULTI) - dp_rcr_reg |= RCR_AM; - outb_reg0(dep, DP_RCR, dp_rcr_reg); -} - /*===========================================================================* * dp_reset * *===========================================================================*/ -static void dp_reset(dep) -dpeth_t *dep; +static void dp_reset(dpeth_t *dep) { int i; @@ -835,21 +484,20 @@ dpeth_t *dep; dep->de_sendq_head= dep->de_sendq_tail= 0; for (i= 0; ide_sendq_nr; i++) dep->de_sendq[i].sq_filled= 0; - dp_send(dep); + netdriver_send(); dep->de_flags &= ~DEF_STOPPED; } /*===========================================================================* - * dp_check_ints * + * do_intr * *===========================================================================*/ -static void dp_check_ints(dep) -dpeth_t *dep; +static void do_intr(unsigned int __unused mask) { + dpeth_t *dep; int isr, tsr; - int size, sendq_tail; + int r, size, sendq_tail; - if (!(dep->de_flags & DEF_ENABLED)) - panic("dp8390: got premature interrupt"); + dep = &de_state; for(;;) { @@ -924,17 +572,12 @@ dpeth_t *dep; outb_reg0(dep, DP_TBCR0, size & 0xff); outb_reg0(dep, DP_CR, CR_TXP | CR_EXTRA); } - if (dep->de_flags & DEF_SEND_AVAIL) - dp_send(dep); + netdriver_send(); } if (isr & ISR_PRX) - { - /* Only call dp_recv if there is a read request */ - if (dep->de_flags & DEF_READING) - dp_recv(dep); - } - + netdriver_recv(); + if (isr & ISR_RXE) dep->de_stat.ets_recvErr++; if (isr & ISR_CNT) { @@ -949,12 +592,6 @@ dpeth_t *dep; { printW(); printf( "%s: got overwrite warning\n", dep->de_name); } #endif - if (dep->de_flags & DEF_READING) - { - printf( -"dp_check_ints: strange: overwrite warning and pending read request\n"); - dp_recv(dep); - } } if (isr & ISR_RDC) { @@ -972,31 +609,29 @@ dpeth_t *dep; "%s: NIC stopped\n", dep->de_name); } #endif dep->de_flags |= DEF_STOPPED; + netdriver_recv(); /* see if we can reset right now */ break; } } - if ((dep->de_flags & (DEF_READING|DEF_STOPPED)) == - (DEF_READING|DEF_STOPPED)) - { - /* The chip is stopped, and all arrived packets are - * delivered. - */ - dp_reset(dep); - } + + if ((r = sys_irqenable(&dep->de_hook)) != OK) + panic("unable enable interrupts: %d", r); } /*===========================================================================* - * dp_recv * + * do_recv * *===========================================================================*/ -static void dp_recv(dep) -dpeth_t *dep; +static ssize_t do_recv(struct netdriver_data *data, size_t max) { + dpeth_t *dep; dp_rcvhdr_t header; unsigned pageno, curr, next; - vir_bytes length; - int packet_processed, r; + size_t length; + int packet_processed; u16_t eth_type; + dep = &de_state; + packet_processed = FALSE; pageno = inb_reg0(dep, DP_BNRY) + 1; if (pageno == dep->de_stoppage) pageno = dep->de_startpage; @@ -1007,7 +642,16 @@ dpeth_t *dep; curr = inb_reg1(dep, DP_CURR); outb_reg0(dep, DP_CR, CR_PS_P0 | CR_EXTRA); - if (curr == pageno) break; + if (curr == pageno) { + if (dep->de_flags & DEF_STOPPED) { + /* The chip is stopped, and all arrived packets + * are delivered. + */ + dp_reset(dep); + } + + return SUSPEND; + } (dep->de_getblockf)(dep, pageno, (size_t)0, sizeof(header), &header); @@ -1017,8 +661,7 @@ dpeth_t *dep; 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_TAGGED) + if (length < ETH_MIN_PACK_SIZE || length > max) { printf("%s: packet with strange length arrived: %d\n", dep->de_name, (int) length); @@ -1038,12 +681,9 @@ dpeth_t *dep; dep->de_stat.ets_fifoOver++; next = curr; } - else if ((header.dr_status & RSR_PRX) && - (dep->de_flags & DEF_ENABLED)) + else if (header.dr_status & RSR_PRX) { - r = dp_pkt2user_s(dep, pageno, length); - if (r != OK) - return; + dp_pkt2user_s(dep, data, pageno, length); packet_processed = TRUE; dep->de_stat.ets_packetR++; @@ -1054,32 +694,16 @@ dpeth_t *dep; outb_reg0(dep, DP_BNRY, next - 1); pageno = next; - } - while (!packet_processed); -} + } while (!packet_processed); -/*===========================================================================* - * dp_send * - *===========================================================================*/ -static void dp_send(dep) -dpeth_t *dep; -{ - if (!(dep->de_flags & DEF_SEND_AVAIL)) - return; - - dep->de_flags &= ~DEF_SEND_AVAIL; - do_vwrite_s(&dep->de_sendmsg, TRUE); + return length; } /*===========================================================================* * dp_getblock * *===========================================================================*/ -static void dp_getblock(dep, page, offset, size, dst) -dpeth_t *dep; -int page; -size_t offset; -size_t size; -void *dst; +static void dp_getblock(dpeth_t *dep, int page, size_t offset, size_t size, + void *dst) { offset = page * DP_PAGESIZE + offset; @@ -1089,12 +713,8 @@ void *dst; /*===========================================================================* * dp_pio8_getblock * *===========================================================================*/ -static void dp_pio8_getblock(dep, page, offset, size, dst) -dpeth_t *dep; -int page; -size_t offset; -size_t size; -void *dst; +static void dp_pio8_getblock(dpeth_t *dep, int page, size_t offset, + size_t size, void *dst) { offset = page * DP_PAGESIZE + offset; outb_reg0(dep, DP_RBCR0, size & 0xFF); @@ -1109,12 +729,8 @@ void *dst; /*===========================================================================* * dp_pio16_getblock * *===========================================================================*/ -static void dp_pio16_getblock(dep, page, offset, size, dst) -dpeth_t *dep; -int page; -size_t offset; -size_t size; -void *dst; +static void dp_pio16_getblock(dpeth_t *dep, int page, size_t offset, + size_t size, void *dst) { offset = page * DP_PAGESIZE + offset; outb_reg0(dep, DP_RBCR0, size & 0xFF); @@ -1130,99 +746,45 @@ void *dst; /*===========================================================================* * dp_pkt2user_s * *===========================================================================*/ -static int dp_pkt2user_s(dpeth_t *dep, int page, vir_bytes length) +static void dp_pkt2user_s(dpeth_t *dep, struct netdriver_data *data, int page, + size_t length) { int last, count; - if (!(dep->de_flags & DEF_READING)) - return EGENERIC; - last = page + (length - 1) / DP_PAGESIZE; if (last >= dep->de_stoppage) { count = (dep->de_stoppage - page) * DP_PAGESIZE - sizeof(dp_rcvhdr_t); - /* Save read_iovec since we need it twice. */ - dep->de_tmp_iovec_s = dep->de_read_iovec_s; - (dep->de_nic2userf_s)(dep, page * DP_PAGESIZE + - sizeof(dp_rcvhdr_t), &dep->de_tmp_iovec_s, 0, count); - (dep->de_nic2userf_s)(dep, dep->de_startpage * DP_PAGESIZE, - &dep->de_read_iovec_s, count, length - count); + (dep->de_nic2userf_s)(dep, data, + page * DP_PAGESIZE + sizeof(dp_rcvhdr_t), 0, count); + (dep->de_nic2userf_s)(dep, data, + dep->de_startpage * DP_PAGESIZE, count, length - count); } else { - (dep->de_nic2userf_s)(dep, page * DP_PAGESIZE + - sizeof(dp_rcvhdr_t), &dep->de_read_iovec_s, 0, length); + (dep->de_nic2userf_s)(dep, data, + page * DP_PAGESIZE + sizeof(dp_rcvhdr_t), 0, length); } - - dep->de_read_s = length; - dep->de_flags |= DEF_PACK_RECV; - dep->de_flags &= ~DEF_READING; - - return OK; } /*===========================================================================* * dp_user2nic_s * *===========================================================================*/ -static void dp_user2nic_s(dep, iovp, offset, nic_addr, count) -dpeth_t *dep; -iovec_dat_s_t *iovp; -vir_bytes offset; -int nic_addr; -vir_bytes count; +static void dp_user2nic_s(dpeth_t *dep, struct netdriver_data *data, + int nic_addr, size_t offset, size_t count) { - vir_bytes vir_hw; - int bytes, i, r; - - vir_hw = (vir_bytes)dep->de_locmem + nic_addr; - - i= 0; - while (count > 0) - { - if (i >= IOVEC_NR) - { - dp_next_iovec_s(iovp); - i= 0; - continue; - } - assert(i < iovp->iod_iovec_s); - if (offset >= iovp->iod_iovec[i].iov_size) - { - offset -= iovp->iod_iovec[i].iov_size; - i++; - continue; - } - bytes = iovp->iod_iovec[i].iov_size - offset; - if (bytes > count) - bytes = count; - - r= sys_safecopyfrom(iovp->iod_proc_nr, - iovp->iod_iovec[i].iov_grant, offset, - vir_hw, bytes); - if (r != OK) { - panic("dp_user2nic_s: sys_safecopyfrom failed: %d", r); - } - - count -= bytes; - vir_hw += bytes; - offset += bytes; - } - assert(count == 0); + netdriver_copyin(data, offset, dep->de_locmem + nic_addr, count); } /*===========================================================================* * dp_pio8_user2nic_s * *===========================================================================*/ -static void dp_pio8_user2nic_s(dep, iovp, offset, nic_addr, count) -dpeth_t *dep; -iovec_dat_s_t *iovp; -vir_bytes offset; -int nic_addr; -vir_bytes count; +static void dp_pio8_user2nic_s(dpeth_t *dep, struct netdriver_data *data, + int nic_addr, size_t offset, size_t count) { - int bytes, i, r; + int i; outb_reg0(dep, DP_ISR, ISR_RDC); @@ -1232,36 +794,7 @@ vir_bytes count; outb_reg0(dep, DP_RSAR1, nic_addr >> 8); outb_reg0(dep, DP_CR, CR_DM_RW | CR_PS_P0 | CR_STA); - i= 0; - while (count > 0) - { - if (i >= IOVEC_NR) - { - dp_next_iovec_s(iovp); - i= 0; - continue; - } - assert(i < iovp->iod_iovec_s); - if (offset >= iovp->iod_iovec[i].iov_size) - { - offset -= iovp->iod_iovec[i].iov_size; - i++; - continue; - } - bytes = iovp->iod_iovec[i].iov_size - offset; - if (bytes > count) - bytes = count; - - r= sys_safe_outsb(dep->de_data_port, iovp->iod_proc_nr, - iovp->iod_iovec[i].iov_grant, offset, bytes); - if (r != OK) { - panic("dp_pio8_user2nic_s: sys_safe_outsb failed: %d", - r); - } - count -= bytes; - offset += bytes; - } - assert(count == 0); + netdriver_portoutb(data, offset, dep->de_data_port, count); for (i= 0; i<100; i++) { @@ -1277,21 +810,13 @@ vir_bytes count; /*===========================================================================* * dp_pio16_user2nic_s * *===========================================================================*/ -static void dp_pio16_user2nic_s(dep, iovp, offset, nic_addr, count) -dpeth_t *dep; -iovec_dat_s_t *iovp; -vir_bytes offset; -int nic_addr; -vir_bytes count; +static void dp_pio16_user2nic_s(dpeth_t *dep, struct netdriver_data *data, + int nic_addr, size_t offset, size_t count) { - vir_bytes ecount; - cp_grant_id_t gid; - int i, r, bytes, user_proc; - u8_t two_bytes[2]; - int odd_byte; + size_t ecount; + int i; ecount= (count+1) & ~1; - odd_byte= 0; outb_reg0(dep, DP_ISR, ISR_RDC); outb_reg0(dep, DP_RBCR0, ecount & 0xFF); @@ -1300,73 +825,7 @@ vir_bytes count; outb_reg0(dep, DP_RSAR1, nic_addr >> 8); outb_reg0(dep, DP_CR, CR_DM_RW | CR_PS_P0 | CR_STA); - i= 0; - while (count > 0) - { - if (i >= IOVEC_NR) - { - dp_next_iovec_s(iovp); - i= 0; - continue; - } - assert(i < iovp->iod_iovec_s); - if (offset >= iovp->iod_iovec[i].iov_size) - { - offset -= iovp->iod_iovec[i].iov_size; - i++; - continue; - } - bytes = iovp->iod_iovec[i].iov_size - offset; - if (bytes > count) - bytes = count; - - user_proc= iovp->iod_proc_nr; - gid= iovp->iod_iovec[i].iov_grant; - if (odd_byte) - { - r= sys_safecopyfrom(user_proc, gid, offset, - (vir_bytes)&two_bytes[1], 1); - if (r != OK) { - panic("dp_pio16_user2nic: sys_safecopyfrom failed: %d", r); - } - outw(dep->de_data_port, *(u16_t *)two_bytes); - count--; - offset++; - bytes--; - odd_byte= 0; - if (!bytes) - continue; - } - ecount= bytes & ~1; - if (ecount != 0) - { - r= sys_safe_outsw(dep->de_data_port, user_proc, - gid, offset, ecount); - if (r != OK) { - panic("dp_pio16_user2nic: sys_safe_outsw failed: %d", r); - } - count -= ecount; - offset += ecount; - bytes -= ecount; - } - if (bytes) - { - assert(bytes == 1); - r= sys_safecopyfrom(user_proc, gid, offset, - (vir_bytes)&two_bytes[0], 1); - if (r != OK) { - panic("dp_pio16_user2nic: sys_safecopyfrom failed: %d", r); - } - count--; - offset++; - bytes--; - odd_byte= 1; - } - } - assert(count == 0); - - if (odd_byte) - outw(dep->de_data_port, *(u16_t *)two_bytes); + netdriver_portoutw(data, offset, dep->de_data_port, count); for (i= 0; i<100; i++) { @@ -1382,118 +841,36 @@ vir_bytes count; /*===========================================================================* * dp_nic2user_s * *===========================================================================*/ -static void dp_nic2user_s(dep, nic_addr, iovp, offset, count) -dpeth_t *dep; -int nic_addr; -iovec_dat_s_t *iovp; -vir_bytes offset; -vir_bytes count; +static void dp_nic2user_s(dpeth_t *dep, struct netdriver_data *data, + int nic_addr, size_t offset, size_t count) { - vir_bytes vir_hw; - int bytes, i, r; - - vir_hw = (vir_bytes)dep->de_locmem + nic_addr; - - i= 0; - while (count > 0) - { - if (i >= IOVEC_NR) - { - dp_next_iovec_s(iovp); - i= 0; - continue; - } - assert(i < iovp->iod_iovec_s); - if (offset >= iovp->iod_iovec[i].iov_size) - { - offset -= iovp->iod_iovec[i].iov_size; - i++; - continue; - } - bytes = iovp->iod_iovec[i].iov_size - offset; - if (bytes > count) - bytes = count; - - r= sys_safecopyto(iovp->iod_proc_nr, - iovp->iod_iovec[i].iov_grant, offset, - vir_hw, bytes); - if (r != OK) - panic("dp_nic2user_s: sys_safecopyto failed: %d", r); - - count -= bytes; - vir_hw += bytes; - offset += bytes; - } - assert(count == 0); + netdriver_copyout(data, offset, dep->de_locmem + nic_addr, count); } /*===========================================================================* * dp_pio8_nic2user_s * *===========================================================================*/ -static void dp_pio8_nic2user_s(dep, nic_addr, iovp, offset, count) -dpeth_t *dep; -int nic_addr; -iovec_dat_s_t *iovp; -vir_bytes offset; -vir_bytes count; +static void dp_pio8_nic2user_s(dpeth_t *dep, struct netdriver_data *data, + int nic_addr, size_t offset, size_t count) { - int bytes, i, r; - outb_reg0(dep, DP_RBCR0, count & 0xFF); outb_reg0(dep, DP_RBCR1, count >> 8); outb_reg0(dep, DP_RSAR0, nic_addr & 0xFF); outb_reg0(dep, DP_RSAR1, nic_addr >> 8); outb_reg0(dep, DP_CR, CR_DM_RR | CR_PS_P0 | CR_STA); - i= 0; - while (count > 0) - { - if (i >= IOVEC_NR) - { - dp_next_iovec_s(iovp); - i= 0; - continue; - } - assert(i < iovp->iod_iovec_s); - if (offset >= iovp->iod_iovec[i].iov_size) - { - offset -= iovp->iod_iovec[i].iov_size; - i++; - continue; - } - bytes = iovp->iod_iovec[i].iov_size - offset; - if (bytes > count) - bytes = count; - - r= sys_safe_insb(dep->de_data_port, iovp->iod_proc_nr, - iovp->iod_iovec[i].iov_grant, offset, bytes); - if (r != OK) { - panic("dp_pio8_nic2user_s: sys_safe_insb failed: %d", r); - } - count -= bytes; - offset += bytes; - } - assert(count == 0); + netdriver_portinb(data, offset, dep->de_data_port, count); } /*===========================================================================* * dp_pio16_nic2user_s * *===========================================================================*/ -static void dp_pio16_nic2user_s(dep, nic_addr, iovp, offset, count) -dpeth_t *dep; -int nic_addr; -iovec_dat_s_t *iovp; -vir_bytes offset; -vir_bytes count; +static void dp_pio16_nic2user_s(dpeth_t *dep, struct netdriver_data *data, + int nic_addr, size_t offset, size_t count) { - vir_bytes ecount; - cp_grant_id_t gid; - int i, r, bytes, user_proc; - u8_t two_bytes[2]; - int odd_byte; + size_t ecount; ecount= (count+1) & ~1; - odd_byte= 0; outb_reg0(dep, DP_RBCR0, ecount & 0xFF); outb_reg0(dep, DP_RBCR1, ecount >> 8); @@ -1501,166 +878,49 @@ vir_bytes count; outb_reg0(dep, DP_RSAR1, nic_addr >> 8); outb_reg0(dep, DP_CR, CR_DM_RR | CR_PS_P0 | CR_STA); - i= 0; - while (count > 0) - { - if (i >= IOVEC_NR) - { - dp_next_iovec_s(iovp); - i= 0; - continue; - } - assert(i < iovp->iod_iovec_s); - if (offset >= iovp->iod_iovec[i].iov_size) - { - offset -= iovp->iod_iovec[i].iov_size; - i++; - continue; - } - bytes = iovp->iod_iovec[i].iov_size - offset; - if (bytes > count) - bytes = count; - - user_proc= iovp->iod_proc_nr; - gid= iovp->iod_iovec[i].iov_grant; - if (odd_byte) - { - r= sys_safecopyto(user_proc, gid, offset, - (vir_bytes)&two_bytes[1], 1); - if (r != OK) { - panic("dp_pio16_nic2user: sys_safecopyto failed: %d", r); - } - count--; - offset++; - bytes--; - odd_byte= 0; - if (!bytes) - continue; - } - ecount= bytes & ~1; - if (ecount != 0) - { - r= sys_safe_insw(dep->de_data_port, user_proc, gid, - offset, ecount); - if (r != OK) { - panic("dp_pio16_nic2user: sys_safe_insw failed: %d", - r); - } - count -= ecount; - offset += ecount; - bytes -= ecount; - } - if (bytes) - { - assert(bytes == 1); - *(u16_t *)two_bytes= inw(dep->de_data_port); - r= sys_safecopyto(user_proc, gid, offset, - (vir_bytes)&two_bytes[0], 1); - if (r != OK) - { - panic("dp_pio16_nic2user: sys_safecopyto failed: %d", - r); - } - count--; - offset++; - bytes--; - odd_byte= 1; - } - } - assert(count == 0); -} - -/*===========================================================================* - * dp_next_iovec_s * - *===========================================================================*/ -static void dp_next_iovec_s(iovp) -iovec_dat_s_t *iovp; -{ - assert(iovp->iod_iovec_s > IOVEC_NR); - - 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 > IOVEC_NR ? IOVEC_NR : iovp->iod_iovec_s) * - sizeof(iovp->iod_iovec[0]), iovp->iod_iovec); + netdriver_portinw(data, offset, dep->de_data_port, count); } /*===========================================================================* * conf_hw * *===========================================================================*/ -static void conf_hw(dep) -dpeth_t *dep; +static void conf_hw(dpeth_t *dep) { - static eth_stat_t empty_stat = {0, 0, 0, 0, 0, 0 /* ,... */ }; - int confnr; dp_conf_t *dcp; - dep->de_mode= DEM_DISABLED; /* Superfluous */ - /* Pick a default configuration for this instance. */ confnr= MIN(de_instance, DP_CONF_NR-1); dcp= &dp_conf[confnr]; update_conf(dep, dcp); - if (dep->de_mode != DEM_ENABLED) - return; if (!wdeth_probe(dep) && !ne_probe(dep) && !el2_probe(dep)) - { - printf("%s: No ethernet card found at 0x%x\n", - dep->de_name, dep->de_base_port); - dep->de_mode= DEM_DISABLED; - return; - } + panic("no ethernet card found at 0x%x\n", dep->de_base_port); /* XXX */ if (dep->de_linmem == 0) dep->de_linmem= 0xFFFF0000; - - dep->de_flags = DEF_EMPTY; - dep->de_stat = empty_stat; } /*===========================================================================* * update_conf * *===========================================================================*/ -static void update_conf(dep, dcp) -dpeth_t *dep; -dp_conf_t *dcp; +static void update_conf(dpeth_t *dep, dp_conf_t *dcp) { long v; static char dpc_fmt[] = "x:d:x:x"; char eckey[16]; -#if ENABLE_PCI if (dep->de_pci) { - if (dep->de_pci == 1) - { - /* PCI device is present */ - dep->de_mode= DEM_ENABLED; - } + /* PCI device is present */ return; /* Already configured */ } -#endif strlcpy(eckey, "DPETH0", sizeof(eckey)); eckey[5] += de_instance; /* Get the default settings and modify them from the environment. */ - dep->de_mode= DEM_SINK; v= dcp->dpc_port; - switch (env_parse(eckey, dpc_fmt, 0, &v, 0x0000L, 0xFFFFL)) { - case EP_OFF: - dep->de_mode= DEM_DISABLED; - break; - case EP_ON: - case EP_SET: - dep->de_mode= DEM_ENABLED; /* Might become disabled if - * all probes fail */ - break; - } + (void) env_parse(eckey, dpc_fmt, 0, &v, 0x0000L, 0xFFFFL); dep->de_base_port= v; v= dcp->dpc_irq | DEI_DEFAULT; @@ -1679,8 +939,7 @@ dp_conf_t *dcp; /*===========================================================================* * map_hw_buffer * *===========================================================================*/ -static void map_hw_buffer(dep) -dpeth_t *dep; +static void map_hw_buffer(dpeth_t *dep) { if (dep->de_prog_IO) @@ -1699,108 +958,6 @@ dpeth_t *dep; panic("map_hw_buffer: vm_map_phys failed"); } -/*===========================================================================* - * calc_iovec_size_s * - *===========================================================================*/ -static int calc_iovec_size_s(iovp) -iovec_dat_s_t *iovp; -{ - /* Calculate the size of a request. Note that the iovec_dat - * structure will be unusable after calc_iovec_size_s. - */ - int size; - int i; - - size= 0; - i= 0; - while (i < iovp->iod_iovec_s) - { - if (i >= IOVEC_NR) - { - dp_next_iovec_s(iovp); - i= 0; - continue; - } - size += iovp->iod_iovec[i].iov_size; - i++; - } - return size; -} - -/*===========================================================================* - * reply * - *===========================================================================*/ -static void reply(dep) -dpeth_t *dep; -{ - message reply; - int flags; - int r; - - flags = DL_NOFLAGS; - if (dep->de_flags & DEF_PACK_SEND) - flags |= DL_PACK_SEND; - if (dep->de_flags & DEF_PACK_RECV) - flags |= DL_PACK_RECV; - - reply.m_type = DL_TASK_REPLY; - reply.m_netdrv_net_dl_task.flags = flags; - reply.m_netdrv_net_dl_task.count = dep->de_read_s; - r= ipc_send(dep->de_client, &reply); - - if (r < 0) - panic("dp8390: ipc_send failed: %d", r); - - dep->de_read_s = 0; - dep->de_flags &= ~(DEF_PACK_SEND | DEF_PACK_RECV); -} - -/*===========================================================================* - * mess_reply * - *===========================================================================*/ -static void mess_reply(req, reply_mess) -message *req; -message *reply_mess; -{ - if (ipc_send(req->m_source, reply_mess) != OK) - panic("dp8390: unable to mess_reply"); -} - -/*===========================================================================* - * get_userdata_s * - *===========================================================================*/ -static void get_userdata_s(user_proc, grant, offset, count, loc_addr) -int user_proc; -cp_grant_id_t grant; -vir_bytes offset; -vir_bytes count; -void *loc_addr; -{ - int r; - - r= sys_safecopyfrom(user_proc, grant, offset, - (vir_bytes)loc_addr, count); - if (r != OK) - panic("get_userdata: sys_safecopyfrom failed: %d", r); -} - -/*===========================================================================* - * put_userdata_s * - *===========================================================================*/ -static void put_userdata_s(user_proc, grant, count, loc_addr) -int user_proc; -cp_grant_id_t grant; -size_t count; -void *loc_addr; -{ - int r; - - r= sys_safecopyto(user_proc, grant, 0, (vir_bytes)loc_addr, - count); - if (r != OK) - panic("put_userdata: sys_safecopyto failed: %d", r); -} - u8_t inb(port_t port) { int r; @@ -1845,29 +1002,19 @@ void outw(port_t port, u16_t value) } static void insb(port_t port, void *buf, size_t size) -{ - do_vir_insb(port, SELF, (vir_bytes)buf, size); -} - -static void insw(port_t port, void *buf, size_t size) -{ - do_vir_insw(port, SELF, (vir_bytes)buf, size); -} - -static void do_vir_insb(port_t port, int proc, vir_bytes buf, size_t size) { int r; - r= sys_insb(port, proc, (void *) buf, size); + r= sys_insb(port, SELF, buf, size); if (r != OK) panic("sys_sdevio failed: %d", r); } -static void do_vir_insw(port_t port, int proc, vir_bytes buf, size_t size) +static void insw(port_t port, void *buf, size_t size) { int r; - r= sys_insw(port, proc, (void *) buf, size); + r= sys_insw(port, SELF, buf, size); if (r != OK) panic("sys_sdevio failed: %d", r); } diff --git a/minix/drivers/net/dp8390/dp8390.h b/minix/drivers/net/dp8390/dp8390.h index 342bb632b..ab02f7baf 100644 --- a/minix/drivers/net/dp8390/dp8390.h +++ b/minix/drivers/net/dp8390/dp8390.h @@ -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 $ diff --git a/minix/drivers/net/dp8390/local.h b/minix/drivers/net/dp8390/local.h index 3ee5ba3f1..be8a25015 100644 --- a/minix/drivers/net/dp8390/local.h +++ b/minix/drivers/net/dp8390/local.h @@ -5,7 +5,6 @@ local.h #define ENABLE_WDETH 1 #define ENABLE_NE2000 1 #define ENABLE_3C503 1 -#define ENABLE_PCI 1 struct dpeth; diff --git a/minix/drivers/net/dp8390/ne2000.c b/minix/drivers/net/dp8390/ne2000.c index f6d47d4c8..de0ee889d 100644 --- a/minix/drivers/net/dp8390/ne2000.c +++ b/minix/drivers/net/dp8390/ne2000.c @@ -8,12 +8,10 @@ Created: March 15, 1994 by Philip Homburg */ #include +#include #include #include -#if __minix_vmd -#include "config.h" -#endif #include "local.h" #include "dp8390.h" diff --git a/minix/drivers/net/dp8390/rtl8029.c b/minix/drivers/net/dp8390/rtl8029.c index f69453da9..c66f43bae 100644 --- a/minix/drivers/net/dp8390/rtl8029.c +++ b/minix/drivers/net/dp8390/rtl8029.c @@ -7,6 +7,7 @@ Created: April 2000 by Philip Homburg */ #include +#include #include #include @@ -20,8 +21,6 @@ Created: April 2000 by Philip Homburg #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 $ */ diff --git a/minix/drivers/net/dp8390/wdeth.c b/minix/drivers/net/dp8390/wdeth.c index 2d21f5af4..e9feb7991 100644 --- a/minix/drivers/net/dp8390/wdeth.c +++ b/minix/drivers/net/dp8390/wdeth.c @@ -5,6 +5,7 @@ Created: March 14, 1994 by Philip Homburg */ #include +#include #include #include @@ -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); diff --git a/minix/drivers/net/dpeth/3c501.c b/minix/drivers/net/dpeth/3c501.c index 14c43bc05..d74600279 100644 --- a/minix/drivers/net/dpeth/3c501.c +++ b/minix/drivers/net/dpeth/3c501.c @@ -10,7 +10,7 @@ */ #include -#include +#include #include #include #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) diff --git a/minix/drivers/net/dpeth/3c503.c b/minix/drivers/net/dpeth/3c503.c index e20f1fd94..8b3503e1b 100644 --- a/minix/drivers/net/dpeth/3c503.c +++ b/minix/drivers/net/dpeth/3c503.c @@ -10,6 +10,7 @@ */ #include +#include #include #include #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); diff --git a/minix/drivers/net/dpeth/3c509.c b/minix/drivers/net/dpeth/3c509.c index 74e66982a..d1b6dc4c2 100644 --- a/minix/drivers/net/dpeth/3c509.c +++ b/minix/drivers/net/dpeth/3c509.c @@ -10,7 +10,7 @@ */ #include -#include +#include #include #include @@ -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 */ diff --git a/minix/drivers/net/dpeth/8390.c b/minix/drivers/net/dpeth/8390.c index 521a34159..8007d0b0b 100644 --- a/minix/drivers/net/dpeth/8390.c +++ b/minix/drivers/net/dpeth/8390.c @@ -1,4 +1,3 @@ -#include /* ** File: 8390.c May 02, 2000 ** @@ -12,32 +11,18 @@ */ #include -#include +#include #include #include +#include #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 **/ diff --git a/minix/drivers/net/dpeth/Makefile b/minix/drivers/net/dpeth/Makefile index 9c3d2ed15..8bf0cdff6 100644 --- a/minix/drivers/net/dpeth/Makefile +++ b/minix/drivers/net/dpeth/Makefile @@ -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 diff --git a/minix/drivers/net/dpeth/devio.c b/minix/drivers/net/dpeth/devio.c index ba8a545c2..1e388b0f2 100644 --- a/minix/drivers/net/dpeth/devio.c +++ b/minix/drivers/net/dpeth/devio.c @@ -3,11 +3,12 @@ ** ** Author: Giovanni Falzoni ** -** This file contains the routines for readind/writing +** This file contains the routines for reading/writing ** from/to the device registers. */ #include +#include #include #include #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 diff --git a/minix/drivers/net/dpeth/dp.c b/minix/drivers/net/dpeth/dp.c index 9ed770fcd..0099dcef1 100644 --- a/minix/drivers/net/dpeth/dp.c +++ b/minix/drivers/net/dpeth/dp.c @@ -14,9 +14,10 @@ #include #include #include -#include #include #include +#include +#include #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 **/ diff --git a/minix/drivers/net/dpeth/dp.h b/minix/drivers/net/dpeth/dp.h index d36b5ea99..6a0b56f0e 100644 --- a/minix/drivers/net/dpeth/dp.h +++ b/minix/drivers/net/dpeth/dp.h @@ -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 #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 **/ diff --git a/minix/drivers/net/dpeth/ne.c b/minix/drivers/net/dpeth/ne.c index ea6cbe6b1..4b8add035 100644 --- a/minix/drivers/net/dpeth/ne.c +++ b/minix/drivers/net/dpeth/ne.c @@ -13,6 +13,7 @@ */ #include +#include #include #include #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 diff --git a/minix/drivers/net/dpeth/netbuff.c b/minix/drivers/net/dpeth/netbuff.c index e190048d3..955c466e7 100644 --- a/minix/drivers/net/dpeth/netbuff.c +++ b/minix/drivers/net/dpeth/netbuff.c @@ -8,6 +8,7 @@ */ #include +#include #include #include #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 */ diff --git a/minix/drivers/net/dpeth/wd.c b/minix/drivers/net/dpeth/wd.c index 1ce57fdd9..2e3d5d1df 100644 --- a/minix/drivers/net/dpeth/wd.c +++ b/minix/drivers/net/dpeth/wd.c @@ -13,6 +13,7 @@ */ #include +#include #include #include #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; diff --git a/minix/drivers/net/e1000/Makefile b/minix/drivers/net/e1000/Makefile index a21331d34..ce5945683 100644 --- a/minix/drivers/net/e1000/Makefile +++ b/minix/drivers/net/e1000/Makefile @@ -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 diff --git a/minix/drivers/net/e1000/e1000.c b/minix/drivers/net/e1000/e1000.c index 64cbf1720..72b7e3baf 100644 --- a/minix/drivers/net/e1000/e1000.c +++ b/minix/drivers/net/e1000/e1000.c @@ -1,19 +1,8 @@ -/** - * @file e1000.c - * - * @brief This file contains a device driver for Intel Pro/1000 - * Gigabit Ethernet Controllers. - */ +/* A device driver for Intel Pro/1000 Gigabit Ethernet Controllers. */ #include #include -#include -#include -#include #include -#include -#include -#include #include #include "assert.h" #include "e1000.h" @@ -21,1188 +10,836 @@ #include "e1000_reg.h" #include "e1000_pci.h" -static int e1000_instance; -static e1000_t e1000_state; - -static void e1000_init(message *mp); -static void e1000_init_pci(void); +static int e1000_init(unsigned int instance, ether_addr_t *addr); +static void e1000_stop(void); +static int e1000_send(struct netdriver_data *data, size_t size); +static ssize_t e1000_recv(struct netdriver_data *data, size_t max); +static void e1000_stat(eth_stat_t *stat); +static void e1000_intr(unsigned int mask); static int e1000_probe(e1000_t *e, int skip); -static int e1000_init_hw(e1000_t *e); -static void e1000_init_addr(e1000_t *e); -static void e1000_init_buf(e1000_t *e); -static void e1000_reset_hw(e1000_t *e); -static void e1000_writev_s(message *mp, int from_int); -static void e1000_readv_s(message *mp, int from_int); -static void e1000_getstat_s(message *mp); -static void e1000_interrupt(message *mp); -static int e1000_link_changed(e1000_t *e); -static void e1000_stop(e1000_t *e); +static void e1000_init_hw(e1000_t *e, ether_addr_t *addr); static uint32_t e1000_reg_read(e1000_t *e, uint32_t reg); static void e1000_reg_write(e1000_t *e, uint32_t reg, uint32_t value); static void e1000_reg_set(e1000_t *e, uint32_t reg, uint32_t value); static void e1000_reg_unset(e1000_t *e, uint32_t reg, uint32_t value); -static u16_t eeprom_eerd(void *e, int reg); -static u16_t eeprom_ich(void *e, int reg); +static u16_t eeprom_eerd(e1000_t *e, int reg); +static u16_t eeprom_ich(e1000_t *e, int reg); static int eeprom_ich_init(e1000_t *e); -static int eeprom_ich_cycle(const e1000_t *e, u32_t timeout); -static void reply(e1000_t *e); -static void mess_reply(message *req, message *reply); +static int eeprom_ich_cycle(e1000_t *e, u32_t timeout); -/* 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); +static int e1000_instance; +static e1000_t e1000_state; -/*===========================================================================* - * main * - *===========================================================================*/ -int main(int argc, char *argv[]) +static const struct netdriver e1000_table = { + .ndr_init = e1000_init, + .ndr_stop = e1000_stop, + .ndr_recv = e1000_recv, + .ndr_send = e1000_send, + .ndr_stat = e1000_stat, + .ndr_intr = e1000_intr, +}; + +/* + * The e1000 driver. + */ +int +main(int argc, char * argv[]) { - message m; - int ipc_status; - int r; - /* SEF local startup. */ - env_setargs(argc, argv); - sef_local_startup(); + env_setargs(argc, argv); - /* - * Enter the main driver loop. - */ - while (TRUE) - { - if ((r= netdriver_receive(ANY, &m, &ipc_status)) != OK) - { - panic("netdriver_receive failed: %d", r); - } + /* Let the netdriver library take control. */ + netdriver_task(&e1000_table); - if (is_ipc_notify(ipc_status)) - { - switch (_ENDPOINT_P(m.m_source)) - { - case HARDWARE: - e1000_interrupt(&m); - break; - - case CLOCK: - break; - } - continue; - } - switch (m.m_type) - { - case DL_WRITEV_S: e1000_writev_s(&m, FALSE); break; - case DL_READV_S: e1000_readv_s(&m, FALSE); break; - case DL_CONF: e1000_init(&m); break; - case DL_GETSTAT_S: e1000_getstat_s(&m); break; - default: - panic("illegal message: %d", m.m_type); - } - } + return 0; } -/*===========================================================================* - * sef_local_startup * - *===========================================================================*/ -static void sef_local_startup() +/* + * Initialize the e1000 driver and device. + */ +static int +e1000_init(unsigned int instance, ether_addr_t * addr) { - /* Register init callbacks. */ - sef_setcb_init_fresh(sef_cb_init_fresh); - sef_setcb_init_lu(sef_cb_init_fresh); - sef_setcb_init_restart(sef_cb_init_fresh); + e1000_t *e; + int r; - /* 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); + e1000_instance = instance; - /* Register signal callbacks. */ - sef_setcb_signal_handler(sef_cb_signal_handler); + /* Clear state. */ + memset(&e1000_state, 0, sizeof(e1000_state)); - /* Let SEF perform startup. */ - sef_startup(); + e = &e1000_state; + strlcpy(e->name, "e1000#0", sizeof(e->name)); + e->name[6] += instance; + + /* Perform calibration. */ + if ((r = tsc_calibrate()) != OK) + panic("tsc_calibrate failed: %d", r); + + /* See if we can find a matching device. */ + if (!e1000_probe(e, instance)) + return ENXIO; + + /* Initialize the hardware, and return its ethernet address. */ + e1000_init_hw(e, addr); + + return OK; } -/*===========================================================================* - * sef_cb_init_fresh * - *===========================================================================*/ -static int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *UNUSED(info)) +/* + * Map flash memory. This step is optional. + */ +static void +e1000_map_flash(e1000_t * e, int devind, int did) { -/* Initialize the e1000 driver. */ - long v; - int r; + u32_t flash_addr, gfpreg, sector_base_addr; + size_t flash_size; - v = 0; - (void) env_parse("instance", "d", 0, &v, 0, 255); - e1000_instance = (int) v; + /* The flash memory is pointed to by BAR2. It may not be present. */ + if ((flash_addr = pci_attr_r32(devind, PCI_BAR_2)) == 0) + return; - /* Clear state. */ - memset(&e1000_state, 0, sizeof(e1000_state)); + /* The default flash size. */ + flash_size = 0x10000; - /* Perform calibration. */ - if((r = tsc_calibrate()) != OK) - { - panic("tsc_calibrate failed: %d", r); - } - - /* Announce we are up! */ - netdriver_announce(); - - return(OK); -} - -/*===========================================================================* - * sef_cb_signal_handler * - *===========================================================================*/ -static void sef_cb_signal_handler(int signo) -{ - e1000_t *e; - e = &e1000_state; - - E1000_DEBUG(3, ("%s: got signal\n", e->name)); - - /* Only check for termination signal, ignore anything else. */ - if (signo != SIGTERM) return; - - e1000_stop(e); -} - -/*===========================================================================* - * e1000_init * - *===========================================================================*/ -static void e1000_init(message *mp) -{ - static int first_time = 1; - message reply_mess; - e1000_t *e; - - E1000_DEBUG(3, ("e1000: init()\n")); - - /* Configure PCI devices, if needed. */ - if (first_time) - { - first_time = 0; - e1000_init_pci(); - } - e = &e1000_state; - - /* Initialize hardware, if needed. */ - if (!(e->status & E1000_ENABLED) && !(e1000_init_hw(e))) - { - reply_mess.m_type = DL_CONF_REPLY; - reply_mess.m_netdrv_net_dl_conf.stat = ENXIO; - mess_reply(mp, &reply_mess); - return; - } - /* Reply back to INET. */ - reply_mess.m_type = DL_CONF_REPLY; - reply_mess.m_netdrv_net_dl_conf.stat = OK; - memcpy(reply_mess.m_netdrv_net_dl_conf.hw_addr, e->address.ea_addr, - sizeof(reply_mess.m_netdrv_net_dl_conf.hw_addr)); - mess_reply(mp, &reply_mess); -} - -/*===========================================================================* - * e1000_int_pci * - *===========================================================================*/ -static void e1000_init_pci() -{ - e1000_t *e; - - /* Initialize the PCI bus. */ - pci_init(); - - /* Try to detect e1000's. */ - e = &e1000_state; - strlcpy(e->name, "e1000#0", sizeof(e->name)); - e->name[6] += e1000_instance; - e1000_probe(e, e1000_instance); -} - -/*===========================================================================* - * e1000_probe * - *===========================================================================*/ -static int e1000_probe(e1000_t *e, int skip) -{ - int r, devind, ioflag; - u16_t vid, did, cr; - u32_t status[2]; - u32_t base, size; - u32_t gfpreg, sector_base_addr; - char *dname; - - E1000_DEBUG(3, ("%s: probe()\n", e->name)); - - /* - * Attempt to iterate the PCI bus. Start at the beginning. - */ - if ((r = pci_first_dev(&devind, &vid, &did)) == 0) - { - return FALSE; - } - /* Loop devices on the PCI bus. */ - while (skip--) - { - E1000_DEBUG(3, ("%s: probe() devind %d vid 0x%x did 0x%x\n", - e->name, devind, vid, did)); - - if (!(r = pci_next_dev(&devind, &vid, &did))) - { - return FALSE; - } - } - /* - * Successfully detected an Intel Pro/1000 on the PCI bus. - */ - e->status |= E1000_DETECTED; - e->eeprom_read = eeprom_eerd; - - /* - * Set card specific properties. - */ - switch (did) - { - case E1000_DEV_ID_ICH10_D_BM_LM: - case E1000_DEV_ID_ICH10_R_BM_LF: - e->eeprom_read = eeprom_ich; - break; - - case E1000_DEV_ID_82540EM: + switch (did) { + case E1000_DEV_ID_82540EM: case E1000_DEV_ID_82545EM: - e->eeprom_done_bit = (1 << 4); - e->eeprom_addr_off = 8; - break; + case E1000_DEV_ID_82540EP: + return; /* don't even try */ + + /* 82566/82567/82562V series support mapping 4kB of flash memory. */ + case E1000_DEV_ID_ICH10_D_BM_LM: + case E1000_DEV_ID_ICH10_R_BM_LF: + flash_size = 0x1000; + break; + } + + e->flash = vm_map_phys(SELF, (void *)flash_addr, flash_size); + if (e->flash == MAP_FAILED) + panic("e1000: couldn't map in flash"); + + /* sector_base_addr is a "sector"-aligned address (4096 bytes). */ + gfpreg = E1000_READ_FLASH_REG(e, ICH_FLASH_GFPREG); + sector_base_addr = gfpreg & FLASH_GFPREG_BASE_MASK; + + /* flash_base_addr is byte-aligned. */ + e->flash_base_addr = sector_base_addr << FLASH_SECTOR_ADDR_SHIFT; +} + +/* + * Find a matching device. Return TRUE on success. + */ +static int +e1000_probe(e1000_t * e, int skip) +{ + int r, devind, ioflag; + u16_t vid, did, cr; + u32_t status; + u32_t base, size; + char *dname; + + E1000_DEBUG(3, ("%s: probe()\n", e->name)); + + /* Initialize communication to the PCI driver. */ + pci_init(); + + /* Attempt to iterate the PCI bus. Start at the beginning. */ + if ((r = pci_first_dev(&devind, &vid, &did)) == 0) + return FALSE; + + /* Loop devices on the PCI bus. */ + while (skip--) { + E1000_DEBUG(3, ("%s: probe() devind %d vid 0x%x did 0x%x\n", + e->name, devind, vid, did)); + + if (!(r = pci_next_dev(&devind, &vid, &did))) + return FALSE; + } + + /* We found a matching card. Set card-specific properties. */ + e->eeprom_read = eeprom_eerd; + + switch (did) { + case E1000_DEV_ID_ICH10_D_BM_LM: + case E1000_DEV_ID_ICH10_R_BM_LF: + e->eeprom_read = eeprom_ich; + break; + + case E1000_DEV_ID_82540EM: + case E1000_DEV_ID_82545EM: + e->eeprom_done_bit = (1 << 4); + e->eeprom_addr_off = 8; + break; default: - e->eeprom_done_bit = (1 << 1); - e->eeprom_addr_off = 2; - break; - } + e->eeprom_done_bit = (1 << 1); + e->eeprom_addr_off = 2; + break; + } - /* Inform the user about the new card. */ - if (!(dname = pci_dev_name(vid, did))) - { - dname = "Intel Pro/1000 Gigabit Ethernet Card"; - } - E1000_DEBUG(1, ("%s: %s (%04x/%04x/%02x) at %s\n", - e->name, dname, vid, did, e->revision, - pci_slot_name(devind))); + /* Inform the user about the new card. */ + if (!(dname = pci_dev_name(vid, did))) + dname = "Intel Pro/1000 Gigabit Ethernet Card"; + E1000_DEBUG(1, ("%s: %s (%04x/%04x) at %s\n", + e->name, dname, vid, did, pci_slot_name(devind))); - /* Reserve PCI resources found. */ - if ((r = pci_reserve_ok(devind)) != OK) - { - panic("failed to reserve PCI device: %d", r); - } - /* Read PCI configuration. */ - e->irq = pci_attr_r8(devind, PCI_ILR); + /* Reserve PCI resources found. */ + pci_reserve(devind); - if ((r = pci_get_bar(devind, PCI_BAR, &base, &size, &ioflag)) != OK) - panic("failed to get PCI BAR (%d)", r); - if (ioflag) panic("PCI BAR is not for memory"); + /* Read PCI configuration. */ + e->irq = pci_attr_r8(devind, PCI_ILR); - e->regs = vm_map_phys(SELF, (void *) base, size); - if (e->regs == (u8_t *) -1) { + if ((r = pci_get_bar(devind, PCI_BAR, &base, &size, &ioflag)) != OK) + panic("failed to get PCI BAR: %d", r); + if (ioflag) + panic("PCI BAR is not for memory"); + + if ((e->regs = vm_map_phys(SELF, (void *)base, size)) == MAP_FAILED) panic("failed to map hardware registers from PCI"); - } - /* FIXME: enable DMA bus mastering if necessary. This is disabled by - * default on VMware. Eventually, the PCI driver should deal with this. - */ - cr = pci_attr_r16(devind, PCI_CR); - if (!(cr & PCI_CR_MAST_EN)) + /* Enable DMA bus mastering if necessary. */ + cr = pci_attr_r16(devind, PCI_CR); + if (!(cr & PCI_CR_MAST_EN)) pci_attr_w16(devind, PCI_CR, cr | PCI_CR_MAST_EN); - /* Optionally map flash memory. */ - if (did != E1000_DEV_ID_82540EM && - did != E1000_DEV_ID_82545EM && - did != E1000_DEV_ID_82540EP && - pci_attr_r32(devind, PCI_BAR_2)) - { - size_t flash_size; + /* Optionally map flash memory. */ + e1000_map_flash(e, devind, did); - /* 82566/82567/82562V series support mapping 4kB of flash memory */ - switch(did) - { - case E1000_DEV_ID_ICH10_D_BM_LM: - case E1000_DEV_ID_ICH10_R_BM_LF: - flash_size = 0x1000; - break; - default: - flash_size = 0x10000; - } + /* Output debug information. */ + status = e1000_reg_read(e, E1000_REG_STATUS); + E1000_DEBUG(3, ("%s: MEM at %p, IRQ %d\n", e->name, e->regs, e->irq)); + E1000_DEBUG(3, ("%s: link %s, %s duplex\n", e->name, + status & 3 ? "up" : "down", status & 1 ? "full" : "half")); - if ((e->flash = vm_map_phys(SELF, - (void *) pci_attr_r32(devind, PCI_BAR_2), - flash_size)) == MAP_FAILED) { - panic("e1000: couldn't map in flash."); - } - - gfpreg = E1000_READ_FLASH_REG(e, ICH_FLASH_GFPREG); - /* - * sector_base_addr is a "sector"-aligned address (4096 bytes) - */ - sector_base_addr = gfpreg & FLASH_GFPREG_BASE_MASK; - - /* flash_base_addr is byte-aligned */ - e->flash_base_addr = sector_base_addr << FLASH_SECTOR_ADDR_SHIFT; - } - /* - * Output debug information. - */ - status[0] = e1000_reg_read(e, E1000_REG_STATUS); - E1000_DEBUG(3, ("%s: MEM at %p, IRQ %d\n", - e->name, e->regs, e->irq)); - E1000_DEBUG(3, ("%s: link %s, %s duplex\n", - e->name, status[0] & 3 ? "up" : "down", - status[0] & 1 ? "full" : "half")); - return TRUE; + return TRUE; } -/*===========================================================================* - * e1000_init_hw * - *===========================================================================*/ -static int e1000_init_hw(e) -e1000_t *e; +/* + * Reset the card. + */ +static void +e1000_reset_hw(e1000_t * e) { - int r, i; - e->status |= E1000_ENABLED; - e->irq_hook = e->irq; + /* Assert a Device Reset signal. */ + e1000_reg_set(e, E1000_REG_CTRL, E1000_REG_CTRL_RST); - /* - * Set the interrupt handler and policy. Do not automatically - * re-enable interrupts. Return the IRQ line number on interrupts. - */ - if ((r = sys_irqsetpolicy(e->irq, 0, &e->irq_hook)) != OK) - { - panic("sys_irqsetpolicy failed: %d", r); - } - if ((r = sys_irqenable(&e->irq_hook)) != OK) - { - panic("sys_irqenable failed: %d", r); - } - /* Reset hardware. */ - e1000_reset_hw(e); - - /* - * Initialize appropriately, according to section 14.3 General Configuration - * of Intel's Gigabit Ethernet Controllers Software Developer's Manual. - */ - e1000_reg_set(e, E1000_REG_CTRL, E1000_REG_CTRL_ASDE | E1000_REG_CTRL_SLU); - e1000_reg_unset(e, E1000_REG_CTRL, E1000_REG_CTRL_LRST); - e1000_reg_unset(e, E1000_REG_CTRL, E1000_REG_CTRL_PHY_RST); - e1000_reg_unset(e, E1000_REG_CTRL, E1000_REG_CTRL_ILOS); - e1000_reg_write(e, E1000_REG_FCAL, 0); - e1000_reg_write(e, E1000_REG_FCAH, 0); - e1000_reg_write(e, E1000_REG_FCT, 0); - e1000_reg_write(e, E1000_REG_FCTTV, 0); - e1000_reg_unset(e, E1000_REG_CTRL, E1000_REG_CTRL_VME); - - /* Clear Multicast Table Array (MTA). */ - for (i = 0; i < 128; i++) - { - e1000_reg_write(e, E1000_REG_MTA + i, 0); - } - /* Initialize statistics registers. */ - for (i = 0; i < 64; i++) - { - e1000_reg_write(e, E1000_REG_CRCERRS + (i * 4), 0); - } - /* - * Aquire MAC address and setup RX/TX buffers. - */ - e1000_init_addr(e); - e1000_init_buf(e); - - /* Enable interrupts. */ - e1000_reg_set(e, E1000_REG_IMS, E1000_REG_IMS_LSC | - E1000_REG_IMS_RXO | - E1000_REG_IMS_RXT | - E1000_REG_IMS_TXQE | - E1000_REG_IMS_TXDW); - return TRUE; + /* Wait one microsecond. */ + tickdelay(1); } -/*===========================================================================* - * e1000_init_addr * - *===========================================================================*/ -static void e1000_init_addr(e) -e1000_t *e; +/* + * Initialize and return the card's ethernet address. + */ +static void +e1000_init_addr(e1000_t * e, ether_addr_t * addr) { - static char eakey[]= E1000_ENVVAR "#_EA"; - static char eafmt[]= "x:x:x:x:x:x"; - u16_t word; - int i; - long v; + static char eakey[] = E1000_ENVVAR "#_EA"; + static char eafmt[] = "x:x:x:x:x:x"; + u16_t word; + int i; + long v; - /* - * Do we have a user defined ethernet address? - */ - eakey[sizeof(E1000_ENVVAR)-1] = '0' + e1000_instance; + /* Do we have a user defined ethernet address? */ + eakey[sizeof(E1000_ENVVAR)-1] = '0' + e1000_instance; - for (i= 0; i < 6; i++) - { - if (env_parse(eakey, eafmt, i, &v, 0x00L, 0xFFL) != EP_SET) - break; - else - e->address.ea_addr[i]= v; - } - /* - * If that fails, read Ethernet Address from EEPROM. - */ - if (i != 6) - { - for (i = 0; i < 3; i++) - { - word = e->eeprom_read(e, i); - e->address.ea_addr[(i * 2)] = (word & 0xff); - e->address.ea_addr[(i * 2) + 1] = (word & 0xff00) >> 8; + for (i = 0; i < 6; i++) { + if (env_parse(eakey, eafmt, i, &v, 0x00L, 0xFFL) != EP_SET) + break; + else + addr->ea_addr[i] = v; } - } - /* - * Set Receive Address. - */ - e1000_reg_write(e, E1000_REG_RAL, *(u32_t *)(&e->address.ea_addr[0])); - e1000_reg_write(e, E1000_REG_RAH, *(u16_t *)(&e->address.ea_addr[4])); - e1000_reg_set(e, E1000_REG_RAH, E1000_REG_RAH_AV); - e1000_reg_set(e, E1000_REG_RCTL, E1000_REG_RCTL_MPE); - E1000_DEBUG(3, ("%s: Ethernet Address %x:%x:%x:%x:%x:%x\n", e->name, - e->address.ea_addr[0], e->address.ea_addr[1], - e->address.ea_addr[2], e->address.ea_addr[3], - e->address.ea_addr[4], e->address.ea_addr[5])); + /* If that fails, read Ethernet Address from EEPROM. */ + if (i != 6) { + for (i = 0; i < 3; i++) { + word = e->eeprom_read(e, i); + addr->ea_addr[i * 2] = (word & 0x00ff); + addr->ea_addr[i * 2 + 1] = (word & 0xff00) >> 8; + } + } + + /* Set Receive Address. */ + e1000_reg_write(e, E1000_REG_RAL, *(u32_t *)(&addr->ea_addr[0])); + e1000_reg_write(e, E1000_REG_RAH, *(u16_t *)(&addr->ea_addr[4])); + e1000_reg_set(e, E1000_REG_RAH, E1000_REG_RAH_AV); + e1000_reg_set(e, E1000_REG_RCTL, E1000_REG_RCTL_MPE); + + E1000_DEBUG(3, ("%s: Ethernet Address %x:%x:%x:%x:%x:%x\n", e->name, + addr->ea_addr[0], addr->ea_addr[1], addr->ea_addr[2], + addr->ea_addr[3], addr->ea_addr[4], addr->ea_addr[5])); } -/*===========================================================================* - * e1000_init_buf * - *===========================================================================*/ -static void e1000_init_buf(e) -e1000_t *e; +/* + * Initialize receive and transmit buffers. + */ +static void +e1000_init_buf(e1000_t * e) { - phys_bytes rx_buff_p; - phys_bytes tx_buff_p; - int i; + phys_bytes rx_desc_p, rx_buff_p; + phys_bytes tx_desc_p, tx_buff_p; + int i; - /* Number of descriptors. */ - e->rx_desc_count = E1000_RXDESC_NR; - e->tx_desc_count = E1000_TXDESC_NR; + /* Number of descriptors. */ + e->rx_desc_count = E1000_RXDESC_NR; + e->tx_desc_count = E1000_TXDESC_NR; - /* - * First, allocate the receive descriptors. - */ - if (!e->rx_desc) - { - if ((e->rx_desc = alloc_contig(sizeof(e1000_rx_desc_t) * - e->rx_desc_count, AC_ALIGN4K, - &e->rx_desc_p)) == NULL) { + /* Allocate receive descriptors. */ + if ((e->rx_desc = alloc_contig(sizeof(e1000_rx_desc_t) * + e->rx_desc_count, AC_ALIGN4K, &rx_desc_p)) == NULL) panic("failed to allocate RX descriptors"); - } - memset(e->rx_desc, 0, sizeof(e1000_rx_desc_t) * e->rx_desc_count); - /* - * Allocate 2048-byte buffers. - */ + memset(e->rx_desc, 0, sizeof(e1000_rx_desc_t) * e->rx_desc_count); + + /* Allocate receive buffers. */ e->rx_buffer_size = E1000_RXDESC_NR * E1000_IOBUF_SIZE; - - /* Attempt to allocate. */ - if ((e->rx_buffer = alloc_contig(e->rx_buffer_size, - AC_ALIGN4K, &rx_buff_p)) == NULL) - { - panic("failed to allocate RX buffers"); - } - /* Setup receive descriptors. */ + + if ((e->rx_buffer = alloc_contig(e->rx_buffer_size, AC_ALIGN4K, + &rx_buff_p)) == NULL) + panic("failed to allocate RX buffers"); + + /* Set up receive descriptors. */ for (i = 0; i < E1000_RXDESC_NR; i++) - { - e->rx_desc[i].buffer = rx_buff_p + (i * E1000_IOBUF_SIZE); - } - } - /* - * Then, allocate transmit descriptors. - */ - if (!e->tx_desc) - { - if ((e->tx_desc = alloc_contig(sizeof(e1000_tx_desc_t) * - e->tx_desc_count, AC_ALIGN4K, - &e->tx_desc_p)) == NULL) { + e->rx_desc[i].buffer = rx_buff_p + i * E1000_IOBUF_SIZE; + + /* Allocate transmit descriptors. */ + if ((e->tx_desc = alloc_contig(sizeof(e1000_tx_desc_t) * + e->tx_desc_count, AC_ALIGN4K, &tx_desc_p)) == NULL) panic("failed to allocate TX descriptors"); - } - memset(e->tx_desc, 0, sizeof(e1000_tx_desc_t) * e->tx_desc_count); - /* - * Allocate 2048-byte buffers. - */ + memset(e->tx_desc, 0, sizeof(e1000_tx_desc_t) * e->tx_desc_count); + + /* Allocate transmit buffers. */ e->tx_buffer_size = E1000_TXDESC_NR * E1000_IOBUF_SIZE; - - /* Attempt to allocate. */ - if ((e->tx_buffer = alloc_contig(e->tx_buffer_size, - AC_ALIGN4K, &tx_buff_p)) == NULL) - { - panic("failed to allocate TX buffers"); - } - /* Setup transmit descriptors. */ + + if ((e->tx_buffer = alloc_contig(e->tx_buffer_size, AC_ALIGN4K, + &tx_buff_p)) == NULL) + panic("failed to allocate TX buffers"); + + /* Set up transmit descriptors. */ for (i = 0; i < E1000_TXDESC_NR; i++) - { - e->tx_desc[i].buffer = tx_buff_p + (i * E1000_IOBUF_SIZE); - } - } - /* - * Setup the receive ring registers. - */ - e1000_reg_write(e, E1000_REG_RDBAL, e->rx_desc_p); - e1000_reg_write(e, E1000_REG_RDBAH, 0); - e1000_reg_write(e, E1000_REG_RDLEN, e->rx_desc_count * - sizeof(e1000_rx_desc_t)); - e1000_reg_write(e, E1000_REG_RDH, 0); - e1000_reg_write(e, E1000_REG_RDT, e->rx_desc_count - 1); - e1000_reg_unset(e, E1000_REG_RCTL, E1000_REG_RCTL_BSIZE); - e1000_reg_set(e, E1000_REG_RCTL, E1000_REG_RCTL_EN); - - /* - * Setup the transmit ring registers. - */ - e1000_reg_write(e, E1000_REG_TDBAL, e->tx_desc_p); - e1000_reg_write(e, E1000_REG_TDBAH, 0); - e1000_reg_write(e, E1000_REG_TDLEN, e->tx_desc_count * - sizeof(e1000_tx_desc_t)); - e1000_reg_write(e, E1000_REG_TDH, 0); - e1000_reg_write(e, E1000_REG_TDT, 0); - e1000_reg_set( e, E1000_REG_TCTL, E1000_REG_TCTL_EN | E1000_REG_TCTL_PSP); + e->tx_desc[i].buffer = tx_buff_p + i * E1000_IOBUF_SIZE; + + /* Set up the receive ring registers. */ + e1000_reg_write(e, E1000_REG_RDBAL, rx_desc_p); + e1000_reg_write(e, E1000_REG_RDBAH, 0); + e1000_reg_write(e, E1000_REG_RDLEN, + e->rx_desc_count * sizeof(e1000_rx_desc_t)); + e1000_reg_write(e, E1000_REG_RDH, 0); + e1000_reg_write(e, E1000_REG_RDT, e->rx_desc_count - 1); + e1000_reg_unset(e, E1000_REG_RCTL, E1000_REG_RCTL_BSIZE); + e1000_reg_set(e, E1000_REG_RCTL, E1000_REG_RCTL_EN); + + /* Set up the transmit ring registers. */ + e1000_reg_write(e, E1000_REG_TDBAL, tx_desc_p); + e1000_reg_write(e, E1000_REG_TDBAH, 0); + e1000_reg_write(e, E1000_REG_TDLEN, + e->tx_desc_count * sizeof(e1000_tx_desc_t)); + e1000_reg_write(e, E1000_REG_TDH, 0); + e1000_reg_write(e, E1000_REG_TDT, 0); + e1000_reg_set(e, E1000_REG_TCTL, + E1000_REG_TCTL_EN | E1000_REG_TCTL_PSP); } -/*===========================================================================* - * e1000_reset_hw * - *===========================================================================*/ -static void e1000_reset_hw(e) -e1000_t *e; +/* + * Initialize the hardware. Return the ethernet address. + */ +static void +e1000_init_hw(e1000_t * e, ether_addr_t * addr) { - /* Assert a Device Reset signal. */ - e1000_reg_set(e, E1000_REG_CTRL, E1000_REG_CTRL_RST); + int r, i; - /* Wait one microsecond. */ - tickdelay(1); -} - -/*===========================================================================* - * e1000_writev_s * - *===========================================================================*/ -static void e1000_writev_s(mp, from_int) -message *mp; -int from_int; -{ - e1000_t *e = &e1000_state; - e1000_tx_desc_t *desc; - iovec_s_t iovec[E1000_IOVEC_NR]; - int r, head, tail, i, bytes = 0, size; - - E1000_DEBUG(3, ("e1000: writev_s(%p,%d)\n", mp, from_int)); - - /* Are we called from the interrupt handler? */ - if (!from_int) - { - /* We cannot write twice simultaneously. - assert(!(e->status & E1000_WRITING)); */ - - /* Copy write message. */ - e->tx_message = *mp; - e->client = mp->m_source; - e->status |= E1000_WRITING; - - /* Must be a sane vector count. */ - assert(e->tx_message.m_net_netdrv_dl_writev_s.count > 0); - assert(e->tx_message.m_net_netdrv_dl_writev_s.count < E1000_IOVEC_NR); + e->irq_hook = e->irq; /* - * Copy the I/O vector table. + * Set the interrupt handler and policy. Do not automatically + * reenable interrupts. Return the IRQ line number on interrupts. */ - if ((r = sys_safecopyfrom(e->tx_message.m_source, - e->tx_message.m_net_netdrv_dl_writev_s.grant, 0, - (vir_bytes) iovec, - e->tx_message.m_net_netdrv_dl_writev_s.count * - sizeof(iovec_s_t))) != OK) - { - panic("sys_safecopyfrom() failed: %d", r); - } - /* Find the head, tail and current descriptors. */ - head = e1000_reg_read(e, E1000_REG_TDH); - tail = e1000_reg_read(e, E1000_REG_TDT); + if ((r = sys_irqsetpolicy(e->irq, 0, &e->irq_hook)) != OK) + panic("sys_irqsetpolicy failed: %d", r); + if ((r = sys_irqenable(&e->irq_hook)) != OK) + panic("sys_irqenable failed: %d", r); + + /* Reset hardware. */ + e1000_reset_hw(e); + + /* + * Initialize appropriately, according to section 14.3 General + * Configuration of Intel's Gigabit Ethernet Controllers Software + * Developer's Manual. + */ + e1000_reg_set(e, E1000_REG_CTRL, + E1000_REG_CTRL_ASDE | E1000_REG_CTRL_SLU); + e1000_reg_unset(e, E1000_REG_CTRL, E1000_REG_CTRL_LRST); + e1000_reg_unset(e, E1000_REG_CTRL, E1000_REG_CTRL_PHY_RST); + e1000_reg_unset(e, E1000_REG_CTRL, E1000_REG_CTRL_ILOS); + e1000_reg_write(e, E1000_REG_FCAL, 0); + e1000_reg_write(e, E1000_REG_FCAH, 0); + e1000_reg_write(e, E1000_REG_FCT, 0); + e1000_reg_write(e, E1000_REG_FCTTV, 0); + e1000_reg_unset(e, E1000_REG_CTRL, E1000_REG_CTRL_VME); + + /* Clear Multicast Table Array (MTA). */ + for (i = 0; i < 128; i++) + e1000_reg_write(e, E1000_REG_MTA + i * 4, 0); + + /* Initialize statistics registers. */ + for (i = 0; i < 64; i++) + e1000_reg_write(e, E1000_REG_CRCERRS + i * 4, 0); + + /* Acquire MAC address and set up RX/TX buffers. */ + e1000_init_addr(e, addr); + e1000_init_buf(e); + + /* Enable interrupts. */ + e1000_reg_set(e, E1000_REG_IMS, E1000_REG_IMS_LSC | E1000_REG_IMS_RXO | + E1000_REG_IMS_RXT | E1000_REG_IMS_TXQE | E1000_REG_IMS_TXDW); +} + +/* + * Try to send a packet. + */ +static int +e1000_send(struct netdriver_data * data, size_t size) +{ + e1000_t *e; + e1000_tx_desc_t *desc; + unsigned int head, tail, next; + char *ptr; + + e = &e1000_state; + + if (size > E1000_IOBUF_SIZE) + panic("packet too large to send"); + + /* + * The queue tail must not advance to the point that it is equal to the + * queue head, since this condition indicates that the queue is empty. + */ + head = e1000_reg_read(e, E1000_REG_TDH); + tail = e1000_reg_read(e, E1000_REG_TDT); + next = (tail + 1) % e->tx_desc_count; + + if (next == head) + return SUSPEND; + + /* The descriptor to use is the one pointed to by the current tail. */ desc = &e->tx_desc[tail]; - - E1000_DEBUG(4, ("%s: head=%d, tail=%d\n", - e->name, head, tail)); - /* Loop vector elements. */ - for (i = 0; i < e->tx_message.m_net_netdrv_dl_writev_s.count; i++) - { - size = iovec[i].iov_size < (E1000_IOBUF_SIZE - bytes) ? - iovec[i].iov_size : (E1000_IOBUF_SIZE - bytes); + /* Copy the packet from the caller. */ + ptr = e->tx_buffer + tail * E1000_IOBUF_SIZE; - E1000_DEBUG(4, ("iovec[%d] = %d\n", i, size)); + netdriver_copyin(data, 0, ptr, size); - /* Copy bytes to TX queue buffers. */ - if ((r = sys_safecopyfrom(e->tx_message.m_source, - iovec[i].iov_grant, 0, - (vir_bytes) e->tx_buffer + - (tail * E1000_IOBUF_SIZE), - size)) != OK) - { - panic("sys_safecopyfrom() failed: %d", r); - } - /* Mark this descriptor ready. */ - desc->status = 0; - desc->command = 0; - desc->length = size; + /* Mark this descriptor ready. */ + desc->status = 0; + desc->length = size; + desc->command = E1000_TX_CMD_EOP | E1000_TX_CMD_FCS | E1000_TX_CMD_RS; - /* Marks End-of-Packet. */ - if (i == e->tx_message.m_net_netdrv_dl_writev_s.count - 1) - { - desc->command = E1000_TX_CMD_EOP | - E1000_TX_CMD_FCS | - E1000_TX_CMD_RS; - } - /* Move to next descriptor. */ - tail = (tail + 1) % e->tx_desc_count; - bytes += size; - desc = &e->tx_desc[tail]; - } - /* Increment tail. Start transmission. */ - e1000_reg_write(e, E1000_REG_TDT, tail); + /* Increment tail. Start transmission. */ + e1000_reg_write(e, E1000_REG_TDT, next); - E1000_DEBUG(2, ("e1000: wrote %d byte packet\n", bytes)); - } - else - { - e->status |= E1000_TRANSMIT; - } - reply(e); + return OK; } -/*===========================================================================* - * e1000_readv_s * - *===========================================================================*/ -static void e1000_readv_s(mp, from_int) -message *mp; -int from_int; +/* + * Try to receive a packet. + */ +static ssize_t +e1000_recv(struct netdriver_data * data, size_t max) { - e1000_t *e = &e1000_state; - e1000_rx_desc_t *desc; - iovec_s_t iovec[E1000_IOVEC_NR]; - int i, r, head, tail, cur, bytes = 0, size; + e1000_t *e; + e1000_rx_desc_t *desc; + unsigned int head, tail, cur; + char *ptr; + size_t size; - E1000_DEBUG(3, ("e1000: readv_s(%p,%d)\n", mp, from_int)); + e = &e1000_state; - /* Are we called from the interrupt handler? */ - if (!from_int) - { - e->rx_message = *mp; - e->client = mp->m_source; - e->status |= E1000_READING; - e->rx_size = 0; - - assert(e->rx_message.m_net_netdrv_dl_readv_s.count > 0); - assert(e->rx_message.m_net_netdrv_dl_readv_s.count < E1000_IOVEC_NR); - } - if (e->status & E1000_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); - } - /* Find the head, tail and current descriptors. */ + /* If the queue head and tail are equal, the queue is empty. */ head = e1000_reg_read(e, E1000_REG_RDH); tail = e1000_reg_read(e, E1000_REG_RDT); - cur = (tail + 1) % e->rx_desc_count; + + E1000_DEBUG(4, ("%s: head=%u, tail=%u\n", e->name, head, tail)); + + if (head == tail) + return SUSPEND; + + /* Has a packet been received? */ + cur = (tail + 1) % e->rx_desc_count; desc = &e->rx_desc[cur]; - + + if (!(desc->status & E1000_RX_STATUS_DONE)) + return SUSPEND; + /* - * Only handle one packet at a time. + * HACK: we expect all packets to fit in a single receive buffer. + * Eventually, some sort of support to deal with packets spanning + * multiple receive descriptors should be added. For now, we panic, + * so that we can continue after the restart; this is already an + * improvement over freezing (the old behavior of this driver). */ + size = desc->length; + if (!(desc->status & E1000_RX_STATUS_EOP)) - { - reply(e); - return; - } - E1000_DEBUG(4, ("%s: head=%x, tail=%d\n", - e->name, head, tail)); + panic("received packet too large"); - /* - * Copy to vector elements. - */ - for (i = 0; i < e->rx_message.m_net_netdrv_dl_readv_s.count && - bytes < desc->length; i++) - { - size = iovec[i].iov_size < (desc->length - bytes) ? - iovec[i].iov_size : (desc->length - bytes); - - E1000_DEBUG(4, ("iovec[%d] = %lu[%d]\n", - i, iovec[i].iov_size, size)); + /* Copy the packet to the caller. */ + ptr = e->rx_buffer + cur * E1000_IOBUF_SIZE; - if ((r = sys_safecopyto(e->rx_message.m_source, iovec[i].iov_grant, - 0, (vir_bytes) e->rx_buffer + bytes + - (cur * E1000_IOBUF_SIZE), - size)) != OK) - { - panic("sys_safecopyto() failed: %d", r); - } - bytes += size; - } + if (size > max) + size = max; + + netdriver_copyout(data, 0, ptr, size); + + /* Reset the descriptor. */ desc->status = 0; - /* - * Update state. - */ - e->rx_size = bytes; - e->status |= E1000_RECEIVED; - E1000_DEBUG(2, ("e1000: got %d byte packet\n", e->rx_size)); - /* Increment tail. */ - e1000_reg_write(e, E1000_REG_RDT, (tail + 1) % e->rx_desc_count); - } - reply(e); + e1000_reg_write(e, E1000_REG_RDT, cur); + + /* Return the size of the received packet. */ + return size; } -/*===========================================================================* - * e1000_getstat_s * - *===========================================================================*/ -static void e1000_getstat_s(mp) -message *mp; +/* + * Return statistics. + */ +static void +e1000_stat(eth_stat_t * stat) { - int r; - eth_stat_t stats; - e1000_t *e = &e1000_state; + e1000_t *e = &e1000_state; - E1000_DEBUG(3, ("e1000: getstat_s()\n")); + E1000_DEBUG(3, ("e1000: stat()\n")); - stats.ets_recvErr = e1000_reg_read(e, E1000_REG_RXERRC); - stats.ets_sendErr = 0; - stats.ets_OVW = 0; - stats.ets_CRCerr = e1000_reg_read(e, E1000_REG_CRCERRS); - stats.ets_frameAll = 0; - stats.ets_missedP = e1000_reg_read(e, E1000_REG_MPC); - stats.ets_packetR = e1000_reg_read(e, E1000_REG_TPR); - stats.ets_packetT = e1000_reg_read(e, E1000_REG_TPT); - stats.ets_collision = e1000_reg_read(e, E1000_REG_COLC); - stats.ets_transAb = 0; - stats.ets_carrSense = 0; - stats.ets_fifoUnder = 0; - stats.ets_fifoOver = 0; - 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("e1000_getstat: ipc_send() failed: %d", r); + stat->ets_recvErr = e1000_reg_read(e, E1000_REG_RXERRC); + stat->ets_sendErr = 0; + stat->ets_OVW = 0; + stat->ets_CRCerr = e1000_reg_read(e, E1000_REG_CRCERRS); + stat->ets_frameAll = 0; + stat->ets_missedP = e1000_reg_read(e, E1000_REG_MPC); + stat->ets_packetR = e1000_reg_read(e, E1000_REG_TPR); + stat->ets_packetT = e1000_reg_read(e, E1000_REG_TPT); + stat->ets_collision = e1000_reg_read(e, E1000_REG_COLC); + stat->ets_transAb = 0; + stat->ets_carrSense = 0; + stat->ets_fifoUnder = 0; + stat->ets_fifoOver = 0; + stat->ets_CDheartbeat = 0; + stat->ets_OWC = 0; } -/*===========================================================================* - * e1000_interrupt * - *===========================================================================*/ -static void e1000_interrupt(mp) -message *mp; +/* + * Link status has changed. Nothing to do for now. + */ +static void +e1000_link_changed(e1000_t * e) { - e1000_t *e; - u32_t cause; - E1000_DEBUG(3, ("e1000: interrupt\n")); - - /* - * Check the card for interrupt reason(s). - */ - e = &e1000_state; - - /* Re-enable interrupts. */ - if (sys_irqenable(&e->irq_hook) != OK) - { - panic("failed to re-enable IRQ"); - } - - /* Read the Interrupt Cause Read register. */ - if ((cause = e1000_reg_read(e, E1000_REG_ICR))) - { - if (cause & E1000_REG_ICR_LSC) - e1000_link_changed(e); - - if (cause & (E1000_REG_ICR_RXO | E1000_REG_ICR_RXT)) - e1000_readv_s(&e->rx_message, TRUE); - - if ((cause & E1000_REG_ICR_TXQE) || - (cause & E1000_REG_ICR_TXDW)) - e1000_writev_s(&e->tx_message, TRUE); - } + E1000_DEBUG(4, ("%s: link_changed()\n", e->name)); } -/*===========================================================================* - * e1000_link_changed * - *===========================================================================*/ -static int e1000_link_changed(e) -e1000_t *e; +/* + * Handle an interrupt. + */ +static void +e1000_intr(unsigned int __unused mask) { - E1000_DEBUG(4, ("%s: link_changed()\n", e->name)); - return FALSE; + e1000_t *e; + u32_t cause; + + E1000_DEBUG(3, ("e1000: interrupt\n")); + + e = &e1000_state; + + /* Reenable interrupts. */ + if (sys_irqenable(&e->irq_hook) != OK) + panic("failed to re-enable IRQ"); + + /* Read the Interrupt Cause Read register. */ + if ((cause = e1000_reg_read(e, E1000_REG_ICR)) != 0) { + if (cause & E1000_REG_ICR_LSC) + e1000_link_changed(e); + + if (cause & (E1000_REG_ICR_RXO | E1000_REG_ICR_RXT)) + netdriver_recv(); + + if (cause & (E1000_REG_ICR_TXQE | E1000_REG_ICR_TXDW)) + netdriver_send(); + } } -/*===========================================================================* - * e1000_stop * - *===========================================================================*/ -static void e1000_stop(e) -e1000_t *e; +/* + * Stop the card. + */ +static void +e1000_stop(void) { - E1000_DEBUG(3, ("%s: stop()\n", e->name)); + e1000_t *e; - e1000_reset_hw(e); + e = &e1000_state; - exit(EXIT_SUCCESS); + E1000_DEBUG(3, ("%s: stop()\n", e->name)); + + e1000_reset_hw(e); } -/*===========================================================================* - * e1000_reg_read * - *===========================================================================*/ -static uint32_t e1000_reg_read(e, reg) -e1000_t *e; -uint32_t reg; +/* + * Read from a register. + */ +static uint32_t +e1000_reg_read(e1000_t * e, uint32_t reg) { - uint32_t value; + uint32_t value; - /* Assume a sane register. */ - assert(reg < 0x1ffff); + /* Assume a sane register. */ + assert(reg < 0x1ffff); - /* Read from memory mapped register. */ - value = *(volatile u32_t *)(e->regs + reg); + /* Read from memory mapped register. */ + value = *(volatile uint32_t *)(e->regs + reg); - /* Return the result. */ - return value; + /* Return the result. */ + return value; } -/*===========================================================================* - * e1000_reg_write * - *===========================================================================*/ -static void e1000_reg_write(e, reg, value) -e1000_t *e; -uint32_t reg; -uint32_t value; +/* + * Write to a register. + */ +static void +e1000_reg_write(e1000_t * e, uint32_t reg, uint32_t value) { - /* Assume a sane register. */ - assert(reg < 0x1ffff); - - /* Write to memory mapped register. */ - *(volatile u32_t *)(e->regs + reg) = value; + + /* Assume a sane register. */ + assert(reg < 0x1ffff); + + /* Write to memory mapped register. */ + *(volatile u32_t *)(e->regs + reg) = value; } -/*===========================================================================* - * e1000_reg_set * - *===========================================================================*/ -static void e1000_reg_set(e, reg, value) -e1000_t *e; -uint32_t reg; -uint32_t value; +/* + * Set bits in a register. + */ +static void +e1000_reg_set(e1000_t * e, uint32_t reg, uint32_t value) { - uint32_t data; + uint32_t data; - /* First read the current value. */ - data = e1000_reg_read(e, reg); - - /* Set value, and write back. */ - e1000_reg_write(e, reg, data | value); + /* First read the current value. */ + data = e1000_reg_read(e, reg); + + /* Set bits, and write back. */ + e1000_reg_write(e, reg, data | value); } -/*===========================================================================* - * e1000_reg_unset * - *===========================================================================*/ -static void e1000_reg_unset(e, reg, value) -e1000_t *e; -uint32_t reg; -uint32_t value; +/* + * Clear bits in a register. + */ +static void +e1000_reg_unset(e1000_t * e, uint32_t reg, uint32_t value) { - uint32_t data; + uint32_t data; - /* First read the current value. */ - data = e1000_reg_read(e, reg); - - /* Unset value, and write back. */ - e1000_reg_write(e, reg, data & ~value); + /* First read the current value. */ + data = e1000_reg_read(e, reg); + + /* Unset bits, and write back. */ + e1000_reg_write(e, reg, data & ~value); } - -/*===========================================================================* - * eeprom_eerd * - *===========================================================================*/ -static u16_t eeprom_eerd(v, reg) -void *v; -int reg; +/* + * Read from EEPROM. + */ +static u16_t +eeprom_eerd(e1000_t * e, int reg) { - e1000_t *e = (e1000_t *) v; - u32_t data; + u32_t data; - /* Request EEPROM read. */ - e1000_reg_write(e, E1000_REG_EERD, - (reg << e->eeprom_addr_off) | (E1000_REG_EERD_START)); + /* Request EEPROM read. */ + e1000_reg_write(e, E1000_REG_EERD, + (reg << e->eeprom_addr_off) | (E1000_REG_EERD_START)); - /* Wait until ready. */ - while (!((data = (e1000_reg_read(e, E1000_REG_EERD))) & e->eeprom_done_bit)); + /* Wait until ready. */ + while (!((data = (e1000_reg_read(e, E1000_REG_EERD))) & + e->eeprom_done_bit)); - return data >> 16; + return data >> 16; } -/*===========================================================================* - * eeprom_ich_init * - *===========================================================================*/ -static int eeprom_ich_init(e) -e1000_t *e; +/* + * Initialize ICH8 flash. + */ +static int +eeprom_ich_init(e1000_t * e) { - union ich8_hws_flash_status hsfsts; - int ret_val = -1; - int i = 0; + union ich8_hws_flash_status hsfsts; + int ret_val = -1; + int i = 0; - hsfsts.regval = E1000_READ_FLASH_REG16(e, ICH_FLASH_HSFSTS); + hsfsts.regval = E1000_READ_FLASH_REG16(e, ICH_FLASH_HSFSTS); - /* Check if the flash descriptor is valid */ - if (hsfsts.hsf_status.fldesvalid == 0) - { - E1000_DEBUG(3, ("Flash descriptor invalid. " - "SW Sequencing must be used.")); - goto out; - } - /* Clear FCERR and DAEL in hw status by writing 1 */ - hsfsts.hsf_status.flcerr = 1; - hsfsts.hsf_status.dael = 1; - - E1000_WRITE_FLASH_REG16(e, ICH_FLASH_HSFSTS, hsfsts.regval); - - /* - * Either we should have a hardware SPI cycle in progress - * bit to check against, in order to start a new cycle or - * FDONE bit should be changed in the hardware so that it - * is 1 after hardware reset, which can then be used as an - * indication whether a cycle is in progress or has been - * completed. - */ - if (hsfsts.hsf_status.flcinprog == 0) - { - /* - * There is no cycle running at present, - * so we can start a cycle. - * Begin by setting Flash Cycle Done. - */ - hsfsts.hsf_status.flcdone = 1; - E1000_WRITE_FLASH_REG16(e, ICH_FLASH_HSFSTS, hsfsts.regval); - ret_val = 0; - } - else - { - /* - * Otherwise poll for sometime so the current - * cycle has a chance to end before giving up. - */ - for (i = 0; i < ICH_FLASH_READ_COMMAND_TIMEOUT; i++) - { - hsfsts.regval = E1000_READ_FLASH_REG16(e, ICH_FLASH_HSFSTS); - - if (hsfsts.hsf_status.flcinprog == 0) - { - ret_val = 0; - break; - } - tickdelay(1); - } - if (ret_val == 0) - { - /* - * Successful in waiting for previous cycle to timeout, - * now set the Flash Cycle Done. - */ - hsfsts.hsf_status.flcdone = 1; - E1000_WRITE_FLASH_REG16(e, ICH_FLASH_HSFSTS, - hsfsts.regval); - } - else - { - E1000_DEBUG(3, ("Flash controller busy, cannot get access")); - } - } -out: - return ret_val; + /* Check if the flash descriptor is valid */ + if (hsfsts.hsf_status.fldesvalid == 0) { + E1000_DEBUG(3, ("Flash descriptor invalid. " + "SW Sequencing must be used.")); + return ret_val; + } + + /* Clear FCERR and DAEL in hw status by writing 1 */ + hsfsts.hsf_status.flcerr = 1; + hsfsts.hsf_status.dael = 1; + + E1000_WRITE_FLASH_REG16(e, ICH_FLASH_HSFSTS, hsfsts.regval); + + /* + * Either we should have a hardware SPI cycle in progress bit to check + * against, in order to start a new cycle or FDONE bit should be + * changed in the hardware so that it is 1 after hardware reset, which + * can then be used as an indication whether a cycle is in progress or + * has been completed. + */ + if (hsfsts.hsf_status.flcinprog == 0) { + /* + * There is no cycle running at present, so we can start a + * cycle. Begin by setting Flash Cycle Done. + */ + hsfsts.hsf_status.flcdone = 1; + E1000_WRITE_FLASH_REG16(e, ICH_FLASH_HSFSTS, hsfsts.regval); + ret_val = 0; + } else { + /* + * Otherwise poll for sometime so the current cycle has a + * chance to end before giving up. + */ + for (i = 0; i < ICH_FLASH_READ_COMMAND_TIMEOUT; i++) { + hsfsts.regval = E1000_READ_FLASH_REG16(e, + ICH_FLASH_HSFSTS); + + if (hsfsts.hsf_status.flcinprog == 0) { + ret_val = 0; + break; + } + tickdelay(1); + } + if (ret_val == 0) { + /* + * Successful in waiting for previous cycle to timeout, + * now set the Flash Cycle Done. + */ + hsfsts.hsf_status.flcdone = 1; + E1000_WRITE_FLASH_REG16(e, ICH_FLASH_HSFSTS, + hsfsts.regval); + } else { + E1000_DEBUG(3, + ("Flash controller busy, cannot get access")); + } + } + + return ret_val; } -/*===========================================================================* - * eeprom_ich_cycle * - *===========================================================================*/ -static int eeprom_ich_cycle(const e1000_t *e, u32_t timeout) +/* + * Start ICH8 flash cycle. + */ +static int +eeprom_ich_cycle(e1000_t * e, u32_t timeout) { - union ich8_hws_flash_ctrl hsflctl; - union ich8_hws_flash_status hsfsts; - int ret_val = -1; - u32_t i = 0; + union ich8_hws_flash_ctrl hsflctl; + union ich8_hws_flash_status hsfsts; + int ret_val = -1; + u32_t i = 0; - E1000_DEBUG(3, ("e1000_flash_cycle_ich8lan")); + E1000_DEBUG(3, ("e1000_flash_cycle_ich8lan")); - /* Start a cycle by writing 1 in Flash Cycle Go in Hw Flash Control */ - hsflctl.regval = E1000_READ_FLASH_REG16(e, ICH_FLASH_HSFCTL); - hsflctl.hsf_ctrl.flcgo = 1; - E1000_WRITE_FLASH_REG16(e, ICH_FLASH_HSFCTL, hsflctl.regval); - - /* wait till FDONE bit is set to 1 */ - do - { - hsfsts.regval = E1000_READ_FLASH_REG16(e, ICH_FLASH_HSFSTS); - if (hsfsts.hsf_status.flcdone == 1) - break; - tickdelay(1); - } - while (i++ < timeout); - - if (hsfsts.hsf_status.flcdone == 1 && hsfsts.hsf_status.flcerr == 0) - ret_val = 0; - - return ret_val; + /* Start a cycle by writing 1 in Flash Cycle Go in Hw Flash Control */ + hsflctl.regval = E1000_READ_FLASH_REG16(e, ICH_FLASH_HSFCTL); + hsflctl.hsf_ctrl.flcgo = 1; + E1000_WRITE_FLASH_REG16(e, ICH_FLASH_HSFCTL, hsflctl.regval); + + /* Wait till the FDONE bit is set to 1 */ + do { + hsfsts.regval = E1000_READ_FLASH_REG16(e, ICH_FLASH_HSFSTS); + if (hsfsts.hsf_status.flcdone == 1) + break; + tickdelay(1); + } while (i++ < timeout); + + if (hsfsts.hsf_status.flcdone == 1 && hsfsts.hsf_status.flcerr == 0) + ret_val = 0; + + return ret_val; } -/*===========================================================================* - * eeprom_ich * - *===========================================================================*/ -static u16_t eeprom_ich(v, reg) -void *v; -int reg; +/* + * Read from ICH8 flash. + */ +static u16_t +eeprom_ich(e1000_t * e, int reg) { - union ich8_hws_flash_status hsfsts; - union ich8_hws_flash_ctrl hsflctl; - u32_t flash_linear_addr; - u32_t flash_data = 0; - int ret_val = -1; - u8_t count = 0; - e1000_t *e = (e1000_t *) v; - u16_t data = 0; - - E1000_DEBUG(3, ("e1000_read_flash_data_ich8lan")); - - if (reg > ICH_FLASH_LINEAR_ADDR_MASK) - goto out; + union ich8_hws_flash_status hsfsts; + union ich8_hws_flash_ctrl hsflctl; + u32_t flash_linear_addr; + u32_t flash_data = 0; + int ret_val = -1; + u8_t count = 0; + u16_t data = 0; - reg *= sizeof(u16_t); - flash_linear_addr = (ICH_FLASH_LINEAR_ADDR_MASK & reg) + - e->flash_base_addr; + E1000_DEBUG(3, ("e1000_read_flash_data_ich8lan")); - do { - tickdelay(1); - - /* Steps */ - ret_val = eeprom_ich_init(e); - if (ret_val != 0) - break; + if (reg > ICH_FLASH_LINEAR_ADDR_MASK) + return data; - hsflctl.regval = E1000_READ_FLASH_REG16(e, ICH_FLASH_HSFCTL); - /* 0b/1b corresponds to 1 or 2 byte size, respectively. */ - hsflctl.hsf_ctrl.fldbcount = 1; - hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_READ; - E1000_WRITE_FLASH_REG16(e, ICH_FLASH_HSFCTL, hsflctl.regval); - E1000_WRITE_FLASH_REG(e, ICH_FLASH_FADDR, flash_linear_addr); + reg *= sizeof(u16_t); + flash_linear_addr = (ICH_FLASH_LINEAR_ADDR_MASK & reg) + + e->flash_base_addr; - ret_val = eeprom_ich_cycle(v, ICH_FLASH_READ_COMMAND_TIMEOUT); - - /* - * Check if FCERR is set to 1, if set to 1, clear it - * and try the whole sequence a few more times, else - * read in (shift in) the Flash Data0, the order is - * least significant byte first msb to lsb - */ - if (ret_val == 0) - { - flash_data = E1000_READ_FLASH_REG(e, ICH_FLASH_FDATA0); - data = (u16_t)(flash_data & 0x0000FFFF); - break; - } - else - { - /* - * If we've gotten here, then things are probably - * completely hosed, but if the error condition is - * detected, it won't hurt to give it another try... - * ICH_FLASH_CYCLE_REPEAT_COUNT times. - */ - hsfsts.regval = E1000_READ_FLASH_REG16(e, ICH_FLASH_HSFSTS); - - if (hsfsts.hsf_status.flcerr == 1) - { - /* Repeat for some time before giving up. */ - continue; - } - else if (hsfsts.hsf_status.flcdone == 0) - { - E1000_DEBUG(3, ("Timeout error - flash cycle " - "did not complete.")); - break; - } - } - } while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT); + do { + tickdelay(1); -out: - return data; -} - -/*===========================================================================* - * reply * - *===========================================================================*/ -static void reply(e) -e1000_t *e; -{ - message msg; - int r; - - /* Only reply to client for read/write request. */ - if (!(e->status & E1000_READING || - e->status & E1000_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 & E1000_READING && - e->status & E1000_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 &= ~(E1000_READING | E1000_RECEIVED); - } - /* Did we successfully transmit packet(s)? */ - if (e->status & E1000_TRANSMIT && - e->status & E1000_WRITING) - { - msg.m_netdrv_net_dl_task.flags |= DL_PACK_SEND; - - /* Clear flags. */ - e->status &= ~(E1000_WRITING | E1000_TRANSMIT); - } - - /* Acknowledge to INET. */ - if ((r = ipc_send(e->client, &msg)) != OK) - { - panic("ipc_send() failed: %d", r); - } -} - -/*===========================================================================* - * mess_reply * - *===========================================================================*/ -static void mess_reply(req, reply_mess) -message *req; -message *reply_mess; -{ - if (ipc_send(req->m_source, reply_mess) != OK) - { - panic("unable to send reply message"); - } + /* Steps */ + ret_val = eeprom_ich_init(e); + if (ret_val != 0) + break; + + hsflctl.regval = E1000_READ_FLASH_REG16(e, ICH_FLASH_HSFCTL); + /* 0b/1b corresponds to 1 or 2 byte size, respectively. */ + hsflctl.hsf_ctrl.fldbcount = 1; + hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_READ; + E1000_WRITE_FLASH_REG16(e, ICH_FLASH_HSFCTL, hsflctl.regval); + E1000_WRITE_FLASH_REG(e, ICH_FLASH_FADDR, flash_linear_addr); + + ret_val = eeprom_ich_cycle(e, ICH_FLASH_READ_COMMAND_TIMEOUT); + + /* + * Check if FCERR is set to 1, if set to 1, clear it and try + * the whole sequence a few more times, else read in (shift in) + * the Flash Data0, the order is least significant byte first + * msb to lsb. + */ + if (ret_val == 0) { + flash_data = E1000_READ_FLASH_REG(e, ICH_FLASH_FDATA0); + data = (u16_t)(flash_data & 0x0000FFFF); + break; + } else { + /* + * If we've gotten here, then things are probably + * completely hosed, but if the error condition is + * detected, it won't hurt to give it another try... + * ICH_FLASH_CYCLE_REPEAT_COUNT times. + */ + hsfsts.regval = E1000_READ_FLASH_REG16(e, + ICH_FLASH_HSFSTS); + + if (hsfsts.hsf_status.flcerr == 1) { + /* Repeat for some time before giving up. */ + continue; + } else if (hsfsts.hsf_status.flcdone == 0) { + E1000_DEBUG(3, ("Timeout error - flash cycle " + "did not complete.")); + break; + } + } + } while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT); + + return data; } diff --git a/minix/drivers/net/e1000/e1000.h b/minix/drivers/net/e1000/e1000.h index d1e26dd72..f97b437e7 100644 --- a/minix/drivers/net/e1000/e1000.h +++ b/minix/drivers/net/e1000/e1000.h @@ -18,13 +18,6 @@ #ifndef __E1000_H #define __E1000_H -#include -#include -#include -#include -#include -#include -#include #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 */ diff --git a/minix/drivers/net/fxp/Makefile b/minix/drivers/net/fxp/Makefile index 48cd2a49e..5425dec40 100644 --- a/minix/drivers/net/fxp/Makefile +++ b/minix/drivers/net/fxp/Makefile @@ -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 diff --git a/minix/drivers/net/fxp/fxp.c b/minix/drivers/net/fxp/fxp.c index 90ec370b6..48d4bdcb5 100644 --- a/minix/drivers/net/fxp/fxp.c +++ b/minix/drivers/net/fxp/fxp.c @@ -1,7 +1,7 @@ /* * fxp.c * - * This file contains an ethernet device driver for Intel 82557, 82558, + * This file contains an ethernet device driver for Intel 82557, 82558, * 82559, 82550, and 82562 fast ethernet controllers. * * Created: Nov 2004 by Philip Homburg @@ -10,21 +10,10 @@ #include #include -#include -#include -#include -#include #include #include -#include +#include -#include - -#define debug 0 -#define RAND_UPDATE /**/ -#define printW() ((void)0) - -#include "assert.h" #include "fxp.h" #include "mii.h" @@ -34,17 +23,11 @@ /* Number of transmit buffers */ #define N_TX_BUF 4 -/* I/O vectors are handled IOVEC_NR entries at a time. */ -#define IOVEC_NR 16 - /* Configuration */ #define FXP_ENVVAR "FXPETH" typedef int irq_hook_t; -/* ignore interrupt for the moment */ -#define interrupt(x) do { } while(0) - static union tmpbuf { char pad[4096]; @@ -55,12 +38,8 @@ static union tmpbuf typedef struct fxp { port_t fxp_base_port; - int fxp_mode; int fxp_got_int; int fxp_send_int; - int fxp_flags; - int fxp_client; - int fxp_features; /* Needed? */ int fxp_irq; int fxp_type; /* What kind of hardware */ int fxp_ms_regs; /* Master/slave registers */ @@ -69,7 +48,6 @@ typedef struct fxp int fxp_need_reset; /* Rx */ - vir_bytes fxp_read_s; int fxp_rx_nbuf; int fxp_rx_bufsize; struct rfd *fxp_rx_buf; @@ -93,42 +71,13 @@ typedef struct fxp /* Link status */ int fxp_report_link; int fxp_link_up; - int fxp_mii_busy; u16_t fxp_mii_scr; - /* PCI related */ - int fxp_seen; /* TRUE iff device available */ - - /* 'large' items */ irq_hook_t fxp_hook; - ether_addr_t fxp_address; - message fxp_rx_mess; - message fxp_tx_mess; struct sc fxp_stat; u8_t fxp_conf_bytes[CC_BYTES_NR]; char fxp_name[sizeof("fxp#n")]; - iovec_t fxp_iovec[IOVEC_NR]; - iovec_s_t fxp_iovec_s[IOVEC_NR]; -} -fxp_t; - -/* fxp_mode */ -#define FM_DISABLED 0x0 -#define FM_ENABLED 0x1 - -/* fxp_flags */ -#define FF_EMPTY 0x000 -#define FF_PACK_SENT 0x001 -#define FF_PACK_RECV 0x002 -#define FF_SEND_AVAIL 0x004 -#define FF_READING 0x010 -#define FF_PROMISC 0x040 -#define FF_MULTI 0x080 -#define FF_BROAD 0x100 -#define FF_ENABLED 0x200 - -/* fxp_features */ -#define FFE_NONE 0x0 +} fxp_t; /* fxp_type */ #define FT_UNKNOWN 0x0 @@ -141,40 +90,35 @@ static int fxp_instance; static fxp_t *fxp_state; -static minix_timer_t fxp_watchdog; - -static u32_t system_hz; - #define fxp_inb(port, offset) (do_inb((port) + (offset))) #define fxp_inl(port, offset) (do_inl((port) + (offset))) #define fxp_outb(port, offset, value) (do_outb((port) + (offset), (value))) #define fxp_outl(port, offset, value) (do_outl((port) + (offset), (value))) -static void fxp_init(message *mp); -static void fxp_pci_conf(void); +static int fxp_init(unsigned int instance, ether_addr_t *addr); +static void fxp_intr(unsigned int __unused mask); +static void fxp_stop(void); static int fxp_probe(fxp_t *fp, int skip); static void fxp_conf_hw(fxp_t *fp); -static void fxp_init_hw(fxp_t *fp); +static void fxp_init_hw(fxp_t *fp, ether_addr_t *addr); static void fxp_init_buf(fxp_t *fp); static void fxp_reset_hw(fxp_t *fp); -static void fxp_confaddr(fxp_t *fp); -static void fxp_rec_mode(fxp_t *fp); -static void fxp_writev_s(const message *mp, int from_int); -static void fxp_readv_s(message *mp, int from_int); +static void fxp_confaddr(fxp_t *fp, ether_addr_t *addr); +static void fxp_mode(unsigned int mode); +static int fxp_send(struct netdriver_data *data, size_t size); +static ssize_t fxp_recv(struct netdriver_data *data, size_t max); static void fxp_do_conf(fxp_t *fp); static void fxp_cu_ptr_cmd(fxp_t *fp, int cmd, phys_bytes bus_addr, int check_idle); static void fxp_ru_ptr_cmd(fxp_t *fp, int cmd, phys_bytes bus_addr, int check_idle); static void fxp_restart_ru(fxp_t *fp); -static void fxp_getstat_s(message *mp); +static void fxp_stat(eth_stat_t *stat); static void fxp_handler(fxp_t *fp); static void fxp_check_ints(fxp_t *fp); -static void fxp_watchdog_f(minix_timer_t *tp); +static void fxp_alarm(clock_t stamp); static int fxp_link_changed(fxp_t *fp); static void fxp_report_link(fxp_t *fp); -static void reply(fxp_t *fp); -static void mess_reply(message *req, message *reply); static u16_t eeprom_read(fxp_t *fp, int reg); static void eeprom_addrsize(fxp_t *fp); static u16_t mii_read(fxp_t *fp, int reg); @@ -182,240 +126,110 @@ static u8_t do_inb(port_t port); static u32_t do_inl(port_t port); static void do_outb(port_t port, u8_t v); static void do_outl(port_t port, u32_t v); -static void tell_dev(vir_bytes start, size_t size, int pci_bus, int +static void tell_iommu(vir_bytes start, size_t size, int pci_bus, int pci_dev, int pci_func); -static void handle_hw_intr(void) -{ - int r; - fxp_t *fp; - - fp= fxp_state; - - if (fp->fxp_mode != FM_ENABLED) - return; - fxp_handler(fp); - - r= sys_irqenable(&fp->fxp_hook); - if (r != OK) { - panic("unable enable interrupts: %d", r); - } - - if (!fp->fxp_got_int) - return; - fp->fxp_got_int= 0; - assert(fp->fxp_flags & FF_ENABLED); - fxp_check_ints(fp); -} - -/* 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); +static const struct netdriver fxp_table = { + .ndr_init = fxp_init, + .ndr_stop = fxp_stop, + .ndr_mode = fxp_mode, + .ndr_recv = fxp_recv, + .ndr_send = fxp_send, + .ndr_stat = fxp_stat, + .ndr_intr = fxp_intr, + .ndr_alarm = fxp_alarm, +}; /*===========================================================================* * main * *===========================================================================*/ int main(int argc, char *argv[]) { - message m; - int ipc_status; - int r; - - /* SEF local startup. */ env_setargs(argc, argv); - sef_local_startup(); - while (TRUE) - { - if ((r= netdriver_receive(ANY, &m, &ipc_status)) != OK) - panic("netdriver_receive failed: %d", r); + netdriver_task(&fxp_table); - if (is_ipc_notify(ipc_status)) { - switch (_ENDPOINT_P(m.m_source)) { - case HARDWARE: - handle_hw_intr(); - break; - case CLOCK: - expire_timers(m.m_notify.timestamp); - break; - default: - panic(" illegal notify from: %d", m.m_source); - } - - /* get new message */ - continue; - } - - switch (m.m_type) - { - case DL_WRITEV_S: fxp_writev_s(&m, FALSE); break; - case DL_READV_S: fxp_readv_s(&m, FALSE); break; - case DL_CONF: fxp_init(&m); break; - case DL_GETSTAT_S: fxp_getstat_s(&m); break; - default: - panic(" illegal message: %d", m.m_type); - } - } + return 0; } /*===========================================================================* - * sef_local_startup * + * fxp_intr * *===========================================================================*/ -static void sef_local_startup() +static void fxp_intr(unsigned int __unused mask) { - /* 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 UNUSED(type), sef_init_info_t *UNUSED(info)) -{ -/* Initialize the fxp driver. */ - long v; int r; - vir_bytes ft; + fxp_t *fp; - system_hz = sys_hz(); + fp= fxp_state; - v = 0; - (void) env_parse("instance", "d", 0, &v, 0, 255); - fxp_instance = (int) v; + fxp_handler(fp); - ft = sizeof(*fxp_state); + if ((r = sys_irqenable(&fp->fxp_hook)) != OK) + panic("unable to enable interrupts: %d", r); - if(!(fxp_state = alloc_contig(ft, 0, NULL))) - panic("couldn't allocate table: %d", ENOMEM); - - memset(fxp_state, 0, ft); - - if((r=tsc_calibrate()) != OK) - panic("tsc_calibrate failed: %d", r); - - /* Announce we are up! */ - netdriver_announce(); - - return(OK); + if (!fp->fxp_got_int) + return; + fp->fxp_got_int= 0; + fxp_check_ints(fp); } /*===========================================================================* - * sef_cb_signal_handler * + * fxp_stop * *===========================================================================*/ -static void sef_cb_signal_handler(int signo) +static void fxp_stop(void) { port_t port; fxp_t *fp; - /* Only check for termination signal, ignore anything else. */ - if (signo != SIGTERM) return; - fp= fxp_state; - if (fp->fxp_mode == FM_ENABLED && (fp->fxp_flags & FF_ENABLED)) { - port= fp->fxp_base_port; + port= fp->fxp_base_port; - /* Reset device */ - if (debug) - printf("%s: resetting device\n", fp->fxp_name); - fxp_outl(port, CSR_PORT, CP_CMD_SOFT_RESET); - } + /* Stop device */ +#if VERBOSE + printf("%s: stopping device\n", fp->fxp_name); +#endif - exit(0); + fxp_outl(port, CSR_PORT, CP_CMD_SOFT_RESET); } /*===========================================================================* * fxp_init * *===========================================================================*/ -static void fxp_init(mp) -message *mp; -{ - static int first_time= 1; - - fxp_t *fp; - message reply_mess; - - if (first_time) - { - first_time= 0; - fxp_pci_conf(); /* Configure PCI devices. */ - - init_timer(&fxp_watchdog); - set_timer(&fxp_watchdog, system_hz, fxp_watchdog_f, 0); - } - - fp= fxp_state; - if (fp->fxp_mode == FM_DISABLED) - { - /* This is the default, try to (re)locate the device. */ - fxp_conf_hw(fp); - if (fp->fxp_mode == FM_DISABLED) - { - /* Probe failed, or the device is configured off. */ - reply_mess.m_type= DL_CONF_REPLY; - reply_mess.m_netdrv_net_dl_conf.stat= ENXIO; - mess_reply(mp, &reply_mess); - return; - } - if (fp->fxp_mode == FM_ENABLED) - fxp_init_hw(fp); - fxp_report_link(fp); - } - - assert(fp->fxp_mode == FM_ENABLED); - assert(fp->fxp_flags & FF_ENABLED); - - fp->fxp_flags &= ~(FF_PROMISC | FF_MULTI | FF_BROAD); - - if (mp->m_net_netdrv_dl_conf.mode & DL_PROMISC_REQ) - fp->fxp_flags |= FF_PROMISC; - if (mp->m_net_netdrv_dl_conf.mode & DL_MULTI_REQ) - fp->fxp_flags |= FF_MULTI; - if (mp->m_net_netdrv_dl_conf.mode & DL_BROAD_REQ) - fp->fxp_flags |= FF_BROAD; - - fxp_rec_mode(fp); - - reply_mess.m_type = DL_CONF_REPLY; - reply_mess.m_netdrv_net_dl_conf.stat = OK; - memcpy(reply_mess.m_netdrv_net_dl_conf.hw_addr, - fp->fxp_address.ea_addr, - sizeof(reply_mess.m_netdrv_net_dl_conf.hw_addr)); - - mess_reply(mp, &reply_mess); -} - -/*===========================================================================* - * fxp_pci_conf * - *===========================================================================*/ -static void fxp_pci_conf() +static int fxp_init(unsigned int instance, ether_addr_t *addr) { fxp_t *fp; + int r; + + fxp_instance = instance; + + if (!(fxp_state = alloc_contig(sizeof(*fxp_state), 0, NULL))) + panic("couldn't allocate table"); fp= fxp_state; + memset(fp, 0, sizeof(*fp)); + strlcpy(fp->fxp_name, "fxp#0", sizeof(fp->fxp_name)); fp->fxp_name[4] += fxp_instance; - fp->fxp_seen= FALSE; - fp->fxp_features= FFE_NONE; - pci_init(); + if ((r = tsc_calibrate()) != OK) + panic("tsc_calibrate failed: %d", r); - if (fxp_probe(fp, fxp_instance)) - fp->fxp_seen= TRUE; + /* Configure PCI device. */ + if (!fxp_probe(fp, fxp_instance)) + return ENXIO; + + fxp_conf_hw(fp); + + fxp_init_hw(fp, addr); + fxp_report_link(fp); + + /* Set watchdog timer. */ + if ((r = sys_setalarm(sys_hz(), 0)) != OK) + panic("unable to set watchdog alarm"); + + return OK; } /*===========================================================================* @@ -424,7 +238,7 @@ static void fxp_pci_conf() static int fxp_probe(fxp_t *fp, int skip) { int r, devind; - u16_t vid, did; + u16_t vid, did, cr; u32_t bar; u8_t ilr, rev; char *str; @@ -432,6 +246,8 @@ static int fxp_probe(fxp_t *fp, int skip) char *dname; #endif + pci_init(); + r= pci_first_dev(&devind, &vid, &did); if (r == 0) return FALSE; @@ -452,6 +268,11 @@ static int fxp_probe(fxp_t *fp, int skip) #endif pci_reserve(devind); + /* Enable bus mastering if necessary. */ + cr = pci_attr_r16(devind, PCI_CR); + if (!(cr & PCI_CR_MAST_EN)) + pci_attr_w16(devind, PCI_CR, cr | PCI_CR_MAST_EN); + bar= pci_attr_r32(devind, PCI_BAR_2) & 0xffffffe0; if (bar < 0x400) { panic("fxp_probe: base address is not properly configured"); @@ -460,11 +281,10 @@ static int fxp_probe(fxp_t *fp, int skip) ilr= pci_attr_r8(devind, PCI_ILR); fp->fxp_irq= ilr; - if (debug) - { - printf("%s: using I/O address 0x%lx, IRQ %d\n", - fp->fxp_name, (unsigned long)bar, ilr); - } +#if VERBOSE + printf("%s: using I/O address 0x%lx, IRQ %d\n", + fp->fxp_name, (unsigned long)bar, ilr); +#endif rev= pci_attr_r8(devind, PCI_REV); str= NULL; @@ -541,23 +361,12 @@ static void fxp_conf_hw(fxp_t *fp) int i; #endif - fp->fxp_mode= FM_DISABLED; /* Superfluous */ - - if (!fp->fxp_seen) - return; - - /* PCI device is present */ - fp->fxp_mode= FM_ENABLED; - - fp->fxp_flags= FF_EMPTY; fp->fxp_got_int= 0; fp->fxp_send_int= 0; fp->fxp_ee_addrlen= 0; /* Unknown */ fp->fxp_need_reset= 0; fp->fxp_report_link= 0; fp->fxp_link_up= -1; /* Unknown */ - fp->fxp_mii_busy= 0; - fp->fxp_read_s= 0; fp->fxp_rx_need_restart= 0; fp->fxp_need_conf= 0; fp->fxp_tx_head= 0; @@ -636,10 +445,9 @@ static void fxp_conf_hw(fxp_t *fp) /*===========================================================================* * fxp_init_hw * *===========================================================================*/ -static void fxp_init_hw(fp) -fxp_t *fp; +static void fxp_init_hw(fxp_t *fp, ether_addr_t *addr) { - int i, r, isr; + int r, isr; port_t port; phys_bytes bus_addr; @@ -647,10 +455,7 @@ fxp_t *fp; fxp_init_buf(fp); - fp->fxp_flags = FF_EMPTY; - fp->fxp_flags |= FF_ENABLED; - - /* Set the interrupt handler and policy. Do not automatically + /* Set the interrupt handler and policy. Do not automatically * reenable interrupts. Return the IRQ line number on interrupts. */ fp->fxp_hook = fp->fxp_irq; @@ -685,16 +490,7 @@ fxp_t *fp; fxp_ru_ptr_cmd(fp, SC_RU_START, fp->fxp_rx_busaddr, TRUE /* check idle */); - fxp_confaddr(fp); - if (debug) - { - printf("%s: Ethernet address ", fp->fxp_name); - for (i= 0; i < 6; i++) - { - printf("%x%c", fp->fxp_address.ea_addr[i], - i < 5 ? ':' : '\n'); - } - } + fxp_confaddr(fp, addr); } /*===========================================================================* @@ -724,13 +520,13 @@ fxp_t *fp; tot_bufsize += 4096 - (tot_bufsize % 4096); alloc_bufsize= tot_bufsize; alloc_buf= alloc_contig(alloc_bufsize, AC_ALIGN4K, &ph); - if (alloc_buf == NULL) { - panic("fxp_init_buf: unable to alloc_contig size: %d", alloc_bufsize); - } + if (alloc_buf == NULL) + panic("fxp_init_buf: unable to alloc_contig size: %d", + alloc_bufsize); buf= (phys_bytes)alloc_buf; - tell_dev((vir_bytes)buf, tot_bufsize, 0, 0, 0); + tell_iommu((vir_bytes)buf, tot_bufsize, 0, 0, 0); tmpbufp= (union tmpbuf *)buf; @@ -797,7 +593,7 @@ fxp_t *fp; txp->tx_tthresh= fp->fxp_tx_threshold; txp->tx_ntbd= 0; } - fp->fxp_tx_idle= 1; + fp->fxp_tx_idle= TRUE; } /*===========================================================================* @@ -828,7 +624,7 @@ fxp_t *fp; /*===========================================================================* * fxp_confaddr * *===========================================================================*/ -static void fxp_confaddr(fxp_t *fp) +static void fxp_confaddr(fxp_t *fp, ether_addr_t *addr) { static char eakey[]= FXP_ENVVAR "#_EA"; static char eafmt[]= "x:x:x:x:x:x"; @@ -843,7 +639,7 @@ static void fxp_confaddr(fxp_t *fp) { if (env_parse(eakey, eafmt, i, &v, 0x00L, 0xFFL) != EP_SET) break; - fp->fxp_address.ea_addr[i]= v; + addr->ea_addr[i]= v; } if (i != 0 && i != 6) env_panic(eakey); /* It's all or nothing */ @@ -854,8 +650,8 @@ static void fxp_confaddr(fxp_t *fp) for (i= 0; i<3; i++) { v= eeprom_read(fp, i); - fp->fxp_address.ea_addr[i*2]= (v & 0xff); - fp->fxp_address.ea_addr[i*2+1]= ((v >> 8) & 0xff); + addr->ea_addr[i*2]= (v & 0xff); + addr->ea_addr[i*2+1]= ((v >> 8) & 0xff); } } @@ -863,7 +659,7 @@ static void fxp_confaddr(fxp_t *fp) tmpbufp->ias.ias_status= 0; tmpbufp->ias.ias_command= CBL_C_EL | CBL_AIS; tmpbufp->ias.ias_linkaddr= 0; - memcpy(tmpbufp->ias.ias_ethaddr, fp->fxp_address.ea_addr, + memcpy(tmpbufp->ias.ias_ethaddr, addr->ea_addr, sizeof(tmpbufp->ias.ias_ethaddr)); r= sys_umap(SELF, VM_D, (vir_bytes)&tmpbufp->ias, (phys_bytes)sizeof(tmpbufp->ias), &bus_addr); @@ -883,30 +679,30 @@ static void fxp_confaddr(fxp_t *fp) #if VERBOSE printf("%s: hardware ethernet address: ", fp->fxp_name); for (i= 0; i<6; i++) - { - printf("%02x%s", fp->fxp_address.ea_addr[i], - i < 5 ? ":" : ""); - } + printf("%02x%s", addr->ea_addr[i], i < 5 ? ":" : ""); printf("\n"); #endif } /*===========================================================================* - * fxp_rec_mode * + * fxp_mode * *===========================================================================*/ -static void fxp_rec_mode(fp) -fxp_t *fp; +static void fxp_mode(unsigned int mode) { + fxp_t *fp; + + fp = fxp_state; + fp->fxp_conf_bytes[0]= CC_BYTES_NR; /* Just to be sure */ fp->fxp_conf_bytes[15] &= ~(CCB15_BD|CCB15_PM); fp->fxp_conf_bytes[21] &= ~CCB21_MA; - if (fp->fxp_flags & FF_PROMISC) + if (mode & NDEV_PROMISC) fp->fxp_conf_bytes[15] |= CCB15_PM; - if (fp->fxp_flags & FF_MULTI) + if (mode & NDEV_MULTI) fp->fxp_conf_bytes[21] |= CCB21_MA; - if (!(fp->fxp_flags & (FF_BROAD|FF_MULTI|FF_PROMISC))) + if (!(mode & (NDEV_BROAD|NDEV_MULTI|NDEV_PROMISC))) fp->fxp_conf_bytes[15] |= CCB15_BD; /* Queue request if not idle */ @@ -922,35 +718,18 @@ fxp_t *fp; } /*===========================================================================* - * fxp_writev_s * + * fxp_send * *===========================================================================*/ -static void fxp_writev_s(const message *mp, int from_int) +static int fxp_send(struct netdriver_data *data, size_t size) { - endpoint_t iov_endpt; - cp_grant_id_t iov_grant; - vir_bytes iov_offset; - int i, j, n, o, r, s, count, size, prev_head; + int prev_head; int fxp_tx_nbuf, fxp_tx_head; u16_t tx_command; fxp_t *fp; - iovec_s_t *iovp; struct tx *txp, *prev_txp; fp= fxp_state; - count = mp->m_net_netdrv_dl_writev_s.count; - fp->fxp_client= mp->m_source; - - assert(fp->fxp_mode == FM_ENABLED); - assert(fp->fxp_flags & FF_ENABLED); - - if (from_int) - { - assert(fp->fxp_flags & FF_SEND_AVAIL); - fp->fxp_flags &= ~FF_SEND_AVAIL; - fp->fxp_tx_alive= TRUE; - } - if (fp->fxp_tx_idle) { txp= fp->fxp_tx_buf; @@ -958,7 +737,7 @@ static void fxp_writev_s(const message *mp, int from_int) prev_txp= NULL; /* lint */ } else - { + { fxp_tx_nbuf= fp->fxp_tx_nbuf; prev_head= fp->fxp_tx_head; fxp_tx_head= prev_head+1; @@ -969,54 +748,15 @@ static void fxp_writev_s(const message *mp, int from_int) if (fxp_tx_head == fp->fxp_tx_tail) { /* Send queue is full */ - assert(!(fp->fxp_flags & FF_SEND_AVAIL)); - fp->fxp_flags |= FF_SEND_AVAIL; - goto suspend; + return SUSPEND; } prev_txp= &fp->fxp_tx_buf[prev_head]; txp= &fp->fxp_tx_buf[fxp_tx_head]; } - assert(!(fp->fxp_flags & FF_SEND_AVAIL)); - assert(!(fp->fxp_flags & FF_PACK_SENT)); - - iov_endpt= mp->m_source; - iov_grant= mp->m_net_netdrv_dl_writev_s.grant; - - size= 0; - o= 0; - iov_offset= 0; - for (i= 0; ifxp_iovec_s[0])) - { - n= IOVEC_NR; - if (i+n > count) - n= count-i; - r= sys_safecopyfrom(iov_endpt, iov_grant, iov_offset, - (vir_bytes)fp->fxp_iovec_s, - n * sizeof(fp->fxp_iovec_s[0])); - if (r != OK) - panic("fxp_writev: sys_safecopyfrom failed: %d", r); - - for (j= 0, iovp= fp->fxp_iovec_s; jiov_size; - if (size + s > ETH_MAX_PACK_SIZE_TAGGED) { - panic("fxp_writev: invalid packet size: %d", size + s); - } - - r= sys_safecopyfrom(iov_endpt, iovp->iov_grant, - 0, (vir_bytes)(txp->tx_buf+o), s); - if (r != OK) { - panic("fxp_writev_s: sys_safecopyfrom failed: %d", r); - } - size += s; - o += s; - } - } - if (size < ETH_MIN_PACK_SIZE) - panic("fxp_writev: invalid packet size: %d", size); + /* Copy in the packet data */ + netdriver_copyin(data, 0, txp->tx_buf, size); txp->tx_status= 0; txp->tx_command= TXC_EL | CBL_XMIT; @@ -1026,7 +766,7 @@ static void fxp_writev_s(const message *mp, int from_int) txp->tx_ntbd= 0; if (fp->fxp_tx_idle) { - fp->fxp_tx_idle= 0; + fp->fxp_tx_idle= FALSE; fp->fxp_tx_head= fp->fxp_tx_tail= 0; fxp_cu_ptr_cmd(fp, SC_CU_START, fp->fxp_tx_busaddr, @@ -1041,62 +781,63 @@ static void fxp_writev_s(const message *mp, int from_int) fp->fxp_tx_head= fxp_tx_head; } - fp->fxp_flags |= FF_PACK_SENT; - - /* If the interrupt handler called, don't send a reply. The reply - * will be sent after all interrupts are handled. - */ - if (from_int) - return; - reply(fp); - return; - -suspend: - if (from_int) - panic("fxp: should not be sending"); - - fp->fxp_tx_mess= *mp; - reply(fp); + return OK; } /*===========================================================================* - * fxp_readv_s * + * fxp_check_restart * *===========================================================================*/ -static void fxp_readv_s(mp, from_int) -message *mp; -int from_int; +static void fxp_check_restart(fxp_t *fp) { - int i, j, n, o, r, s, count, size, fxp_rx_head, fxp_rx_nbuf; - endpoint_t iov_endpt; - cp_grant_id_t iov_grant; + port_t port; + u8_t scb_status; + + if (!fp->fxp_rx_need_restart) + return; + + fp->fxp_rx_need_restart= 0; + + /* Check the status of the RU */ + port= fp->fxp_base_port; + scb_status= fxp_inb(port, SCB_STATUS); + if ((scb_status & SS_RUS_MASK) != SS_RU_NORES) + { + /* Race condition? */ + printf("fxp_check_restart: restart race: 0x%x\n", scb_status); + assert((scb_status & SS_RUS_MASK) == SS_RU_READY); + } + else + { + fxp_restart_ru(fp); + } +} + +/*===========================================================================* + * fxp_recv * + *===========================================================================*/ +static ssize_t fxp_recv(struct netdriver_data *data, size_t max) +{ + int fxp_rx_head, fxp_rx_nbuf; port_t port; unsigned packlen; - vir_bytes iov_offset; u16_t rfd_status; u16_t rfd_res; - u8_t scb_status; fxp_t *fp; - iovec_s_t *iovp; struct rfd *rfdp, *prev_rfdp; fp= fxp_state; - count = mp->m_net_netdrv_dl_readv_s.count; - fp->fxp_client= mp->m_source; - - assert(fp->fxp_mode == FM_ENABLED); - assert(fp->fxp_flags & FF_ENABLED); - port= fp->fxp_base_port; fxp_rx_head= fp->fxp_rx_head; rfdp= &fp->fxp_rx_buf[fxp_rx_head]; rfd_status= rfdp->rfd_status; - if (!(rfd_status & RFDS_C)) - { + if (!(rfd_status & RFDS_C)) { /* Receive buffer is empty, suspend */ - goto suspend; + fxp_check_restart(fp); + + return SUSPEND; } if (!(rfd_status & RFDS_OK)) @@ -1107,7 +848,7 @@ int from_int; else { assert(!(rfd_status & (RFDS_CRCERR | RFDS_ALIGNERR | - RFDS_OUTOFBUF | RFDS_DMAOVR | RFDS_TOOSHORT | + RFDS_OUTOFBUF | RFDS_DMAOVR | RFDS_TOOSHORT | RFDS_RXERR))); } rfd_res= rfdp->rfd_res; @@ -1116,55 +857,11 @@ int from_int; packlen= rfd_res & RFDSZ_SIZE; - iov_endpt = mp->m_source; - iov_grant = mp->m_net_netdrv_dl_readv_s.grant; + /* Copy out the packet data */ + if (packlen > max) + packlen = max; - size= 0; - o= 0; - iov_offset= 0; - for (i= 0; ifxp_iovec_s[0])) - { - n= IOVEC_NR; - if (i+n > count) - n= count-i; - r= sys_safecopyfrom(iov_endpt, iov_grant, iov_offset, - (vir_bytes)fp->fxp_iovec_s, - n * sizeof(fp->fxp_iovec_s[0])); - if (r != OK) - panic("fxp_readv_s: sys_safecopyfrom failed: %d", r); - - for (j= 0, iovp= fp->fxp_iovec_s; jiov_size; - if (size + s > packlen) - { - assert(packlen > size); - s= packlen-size; - } - - r= sys_safecopyto(iov_endpt, iovp->iov_grant, - 0, (vir_bytes)(rfdp->rfd_buf+o), s); - if (r != OK) - { - panic("fxp_readv: sys_safecopyto failed: %d", r); - } - - size += s; - if (size == packlen) - break; - o += s; - } - if (size == packlen) - break; - } - if (size < packlen) - { - assert(0); - } - - fp->fxp_read_s= packlen; - fp->fxp_flags= (fp->fxp_flags & ~FF_READING) | FF_PACK_RECV; + netdriver_copyout(data, 0, rfdp->rfd_buf, packlen); /* Re-init the current buffer */ rfdp->rfd_status= 0; @@ -1190,43 +887,7 @@ int from_int; assert(fxp_rx_head < fxp_rx_nbuf); fp->fxp_rx_head= fxp_rx_head; - if (!from_int) - reply(fp); - - return; - -suspend: - if (fp->fxp_rx_need_restart) - { - fp->fxp_rx_need_restart= 0; - - /* Check the status of the RU */ - scb_status= fxp_inb(port, SCB_STATUS); - if ((scb_status & SS_RUS_MASK) != SS_RU_NORES) - { - /* Race condition? */ - printf("fxp_readv: restart race: 0x%x\n", - scb_status); - assert((scb_status & SS_RUS_MASK) == SS_RU_READY); - } - else - { - fxp_restart_ru(fp); - } - } - if (from_int) - { - assert(fp->fxp_flags & FF_READING); - - /* No need to store any state */ - return; - } - - fp->fxp_rx_mess= *mp; - assert(!(fp->fxp_flags & FF_READING)); - fp->fxp_flags |= FF_READING; - - reply(fp); + return packlen; } /*===========================================================================* @@ -1373,20 +1034,15 @@ fxp_t *fp; } /*===========================================================================* - * fxp_getstat_s * + * fxp_stat * *===========================================================================*/ -static void fxp_getstat_s(message *mp) +static void fxp_stat(eth_stat_t *stat) { - int r; fxp_t *fp; u32_t *p; - eth_stat_t stats; fp= fxp_state; - assert(fp->fxp_mode == FM_ENABLED); - assert(fp->fxp_flags & FF_ENABLED); - p= &fp->fxp_stat.sc_tx_fcp; *p= 0; @@ -1399,45 +1055,35 @@ static void fxp_getstat_s(message *mp) SPIN_UNTIL(*p != 0, 1000); if (*p == 0) - panic("fxp_getstat: CU command failed to complete"); + panic("fxp_stat: CU command failed to complete"); if (*p != SCM_DSC) - panic("fxp_getstat: bad magic"); + panic("fxp_stat: bad magic"); - stats.ets_recvErr= + stat->ets_recvErr= fp->fxp_stat.sc_rx_crc + fp->fxp_stat.sc_rx_align + fp->fxp_stat.sc_rx_resource + fp->fxp_stat.sc_rx_overrun + fp->fxp_stat.sc_rx_cd + fp->fxp_stat.sc_rx_short; - stats.ets_sendErr= + stat->ets_sendErr= fp->fxp_stat.sc_tx_maxcol + fp->fxp_stat.sc_tx_latecol + fp->fxp_stat.sc_tx_crs; - stats.ets_OVW= fp->fxp_stat.sc_rx_overrun; - stats.ets_CRCerr= fp->fxp_stat.sc_rx_crc; - stats.ets_frameAll= fp->fxp_stat.sc_rx_align; - stats.ets_missedP= fp->fxp_stat.sc_rx_resource; - stats.ets_packetR= fp->fxp_stat.sc_rx_good; - stats.ets_packetT= fp->fxp_stat.sc_tx_good; - stats.ets_transDef= fp->fxp_stat.sc_tx_defered; - stats.ets_collision= fp->fxp_stat.sc_tx_totcol; - stats.ets_transAb= fp->fxp_stat.sc_tx_maxcol; - stats.ets_carrSense= fp->fxp_stat.sc_tx_crs; - stats.ets_fifoUnder= fp->fxp_stat.sc_tx_underrun; - stats.ets_fifoOver= fp->fxp_stat.sc_rx_overrun; - stats.ets_CDheartbeat= 0; - stats.ets_OWC= fp->fxp_stat.sc_tx_latecol; - - r= sys_safecopyto(mp->m_source, mp->m_net_netdrv_dl_getstat_s.grant, 0, - (vir_bytes)&stats, sizeof(stats)); - if (r != OK) - panic("fxp_getstat_s: sys_safecopyto failed: %d", r); - - mp->m_type= DL_STAT_REPLY; - r= ipc_send(mp->m_source, mp); - if (r != OK) - panic("fxp_getstat_s: ipc_send failed: %d", r); + stat->ets_OVW= fp->fxp_stat.sc_rx_overrun; + stat->ets_CRCerr= fp->fxp_stat.sc_rx_crc; + stat->ets_frameAll= fp->fxp_stat.sc_rx_align; + stat->ets_missedP= fp->fxp_stat.sc_rx_resource; + stat->ets_packetR= fp->fxp_stat.sc_rx_good; + stat->ets_packetT= fp->fxp_stat.sc_tx_good; + stat->ets_transDef= fp->fxp_stat.sc_tx_defered; + stat->ets_collision= fp->fxp_stat.sc_tx_totcol; + stat->ets_transAb= fp->fxp_stat.sc_tx_maxcol; + stat->ets_carrSense= fp->fxp_stat.sc_tx_crs; + stat->ets_fifoUnder= fp->fxp_stat.sc_tx_underrun; + stat->ets_fifoOver= fp->fxp_stat.sc_rx_overrun; + stat->ets_CDheartbeat= 0; + stat->ets_OWC= fp->fxp_stat.sc_tx_latecol; } /*===========================================================================* @@ -1448,8 +1094,6 @@ static void fxp_handler(fxp_t *fp) int port; u16_t isr; - RAND_UPDATE - port= fp->fxp_base_port; /* Ack interrupt */ @@ -1460,11 +1104,7 @@ static void fxp_handler(fxp_t *fp) { isr &= ~SIS_FR; - if (!fp->fxp_got_int && (fp->fxp_flags & FF_READING)) - { - fp->fxp_got_int= TRUE; - interrupt(fxp_tasknr); - } + fp->fxp_got_int= TRUE; } if (isr & SIS_CNA) { @@ -1472,18 +1112,14 @@ static void fxp_handler(fxp_t *fp) if (!fp->fxp_tx_idle) { fp->fxp_send_int= TRUE; - if (!fp->fxp_got_int) - { - fp->fxp_got_int= TRUE; - interrupt(fxp_tasknr); - } + fp->fxp_got_int= TRUE; } } if (isr & SIS_RNR) { isr &= ~SIS_RNR; - /* Assume that receive buffer is full of packets. fxp_readv + /* Assume that receive buffer is full of packets. fxp_recv * will restart the RU. */ fp->fxp_rx_need_restart= 1; @@ -1500,7 +1136,7 @@ static void fxp_handler(fxp_t *fp) *===========================================================================*/ static void fxp_check_ints(fxp_t *fp) { - int n, fxp_flags, prev_tail; + int n, prev_tail; int fxp_tx_tail, fxp_tx_nbuf, fxp_tx_threshold; port_t port; u32_t busaddr; @@ -1508,17 +1144,8 @@ static void fxp_check_ints(fxp_t *fp) u8_t scb_status; struct tx *txp; - fxp_flags= fp->fxp_flags; + netdriver_recv(); - if (fxp_flags & FF_READING) - { - if (!(fp->fxp_rx_buf[fp->fxp_rx_head].rfd_status & RFDS_C)) - ; /* Nothing */ - else - { - fxp_readv_s(&fp->fxp_rx_mess, TRUE /* from int */); - } - } if (fp->fxp_tx_idle) ; /* Nothing to do */ else if (fp->fxp_send_int) @@ -1552,7 +1179,7 @@ static void fxp_check_ints(fxp_t *fp) if (txp->tx_command & TXC_EL) { - fp->fxp_tx_idle= 1; + fp->fxp_tx_idle= TRUE; break; } @@ -1585,7 +1212,7 @@ static void fxp_check_ints(fxp_t *fp) if (!fp->fxp_tx_idle) { fp->fxp_tx_tail= fxp_tx_tail; - + /* Check the status of the CU */ port= fp->fxp_base_port; scb_status= fxp_inb(port, SCB_STATUS); @@ -1610,51 +1237,37 @@ static void fxp_check_ints(fxp_t *fp) } } - if (fp->fxp_flags & FF_SEND_AVAIL) - { - fxp_writev_s(&fp->fxp_tx_mess, - TRUE /* from int */); - } + fp->fxp_tx_alive = TRUE; + + netdriver_send(); } - + } if (fp->fxp_report_link) fxp_report_link(fp); - - if (fp->fxp_flags & (FF_PACK_SENT | FF_PACK_RECV)) - reply(fp); } /*===========================================================================* - * fxp_watchdog_f * + * fxp_alarm * *===========================================================================*/ -static void fxp_watchdog_f(tp) -minix_timer_t *tp; +static void fxp_alarm(clock_t __unused stamp) { fxp_t *fp; - set_timer(&fxp_watchdog, system_hz, fxp_watchdog_f, 0); + sys_setalarm(sys_hz(), 0); fp= fxp_state; - if (fp->fxp_mode != FM_ENABLED) - return; - /* Handle race condition, MII interface might be busy */ - if(!fp->fxp_mii_busy) - { - /* Check the link status. */ - if (fxp_link_changed(fp)) - { + /* Check the link status. */ + if (fxp_link_changed(fp)) { #if VERBOSE - printf("fxp_watchdog_f: link changed\n"); + printf("fxp_alarm: link changed\n"); #endif - fp->fxp_report_link= TRUE; - fp->fxp_got_int= TRUE; - interrupt(fxp_tasknr); - } + fp->fxp_report_link= TRUE; + fxp_check_ints(fp); } - - if (!(fp->fxp_flags & FF_SEND_AVAIL)) + + if (fp->fxp_tx_idle) { /* Assume that an idle system is alive */ fp->fxp_tx_alive= TRUE; @@ -1666,16 +1279,15 @@ minix_timer_t *tp; return; } + /* XXX this flag is never actually checked! */ fp->fxp_need_reset= TRUE; - fp->fxp_got_int= TRUE; - interrupt(fxp_tasknr); + fxp_check_ints(fp); } /*===========================================================================* * fxp_link_changed * *===========================================================================*/ -static int fxp_link_changed(fp) -fxp_t *fp; +static int fxp_link_changed(fxp_t *fp) { u16_t scr; @@ -1690,7 +1302,7 @@ fxp_t *fp; *===========================================================================*/ static void fxp_report_link(fxp_t *fp) { - u16_t mii_ctrl, mii_status, mii_id1, mii_id2, + u16_t mii_ctrl, mii_status, mii_id1, mii_id2, mii_ana, mii_anlpa, mii_ane, mii_extstat, mii_ms_ctrl, mii_ms_status, scr; u32_t oui; @@ -1738,13 +1350,13 @@ static void fxp_report_link(fxp_t *fp) return; } - oui= (mii_id1 << MII_PH_OUI_H_C_SHIFT) | + oui= (mii_id1 << MII_PH_OUI_H_C_SHIFT) | ((mii_id2 & MII_PL_OUI_L_MASK) >> MII_PL_OUI_L_SHIFT); model= ((mii_id2 & MII_PL_MODEL_MASK) >> MII_PL_MODEL_SHIFT); rev= (mii_id2 & MII_PL_REV_MASK); #if VERBOSE - printf("OUI 0x%06lx, Model 0x%02x, Revision 0x%x\n", oui, model, rev); + printf("OUI 0x%06x, Model 0x%02x, Revision 0x%x\n", oui, model, rev); #endif if (mii_ctrl & (MII_CTRL_LB|MII_CTRL_PD|MII_CTRL_ISO)) @@ -1789,8 +1401,7 @@ static void fxp_report_link(fxp_t *fp) return; } - if (!debug) goto resspeed; - +#if VERBOSE printf("%s: ", fp->fxp_name); mii_print_stat_speed(mii_status, mii_extstat); printf("\n"); @@ -1911,62 +1522,20 @@ static void fxp_report_link(fxp_t *fp) } printf("\n"); } - resspeed: +#endif + #if VERBOSE printf("%s: link up, %d Mbps, %s duplex\n", fp->fxp_name, (scr & MII_SCR_100) ? 100 : 10, (scr & MII_SCR_FD) ? "full" : "half"); #endif - ; -} - -/*===========================================================================* - * reply * - *===========================================================================*/ -static void reply(fp) -fxp_t *fp; -{ - message reply; - int flags; - int r; - - flags = DL_NOFLAGS; - if (fp->fxp_flags & FF_PACK_SENT) - flags |= DL_PACK_SEND; - if (fp->fxp_flags & FF_PACK_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 = fp->fxp_read_s; - - r= ipc_send(fp->fxp_client, &reply); - - if (r < 0) - panic("fxp: ipc_send failed: %d", r); - - fp->fxp_read_s = 0; - fp->fxp_flags &= ~(FF_PACK_SENT | FF_PACK_RECV); -} - -/*===========================================================================* - * mess_reply * - *===========================================================================*/ -static void mess_reply(req, reply_mess) -message *req; -message *reply_mess; -{ - if (ipc_send(req->m_source, reply_mess) != OK) - panic("fxp: unable to mess_reply"); } /*===========================================================================* * eeprom_read * *===========================================================================*/ -static u16_t eeprom_read(fp, reg) -fxp_t *fp; -int reg; +static u16_t eeprom_read(fxp_t *fp, int reg) { port_t port; u16_t v; @@ -1990,10 +1559,10 @@ int reg; fxp_outb(port, CSR_EEPROM, CE_EECS | b); /* bit */ fxp_outb(port, CSR_EEPROM, CE_EECS | b | CE_EESK); /* Clock */ micro_delay(EESK_PERIOD/2+1); - fxp_outb(port, CSR_EEPROM, CE_EECS | b); + fxp_outb(port, CSR_EEPROM, CE_EECS | b); micro_delay(EESK_PERIOD/2+1); } - + v= reg; for (i= alen-1; i >= 0; i--) { @@ -2001,7 +1570,7 @@ int reg; fxp_outb(port, CSR_EEPROM, CE_EECS | b); /* bit */ fxp_outb(port, CSR_EEPROM, CE_EECS | b | CE_EESK); /* Clock */ micro_delay(EESK_PERIOD/2+1); - fxp_outb(port, CSR_EEPROM, CE_EECS | b); + fxp_outb(port, CSR_EEPROM, CE_EECS | b); micro_delay(EESK_PERIOD/2+1); } @@ -2012,7 +1581,7 @@ int reg; micro_delay(EESK_PERIOD/2+1); b= !!(fxp_inb(port, CSR_EEPROM) & CE_EEDO); v= (v << 1) | b; - fxp_outb(port, CSR_EEPROM, CE_EECS ); + fxp_outb(port, CSR_EEPROM, CE_EECS ); micro_delay(EESK_PERIOD/2+1); } fxp_outb(port, CSR_EEPROM, 0); /* Disable EEPROM */ @@ -2024,8 +1593,7 @@ int reg; /*===========================================================================* * eeprom_addrsize * *===========================================================================*/ -static void eeprom_addrsize(fp) -fxp_t *fp; +static void eeprom_addrsize(fxp_t *fp) { port_t port; u16_t v; @@ -2042,7 +1610,7 @@ fxp_t *fp; fxp_outb(port, CSR_EEPROM, CE_EECS | b); /* bit */ fxp_outb(port, CSR_EEPROM, CE_EECS | b | CE_EESK); /* Clock */ micro_delay(EESK_PERIOD/2+1); - fxp_outb(port, CSR_EEPROM, CE_EECS | b); + fxp_outb(port, CSR_EEPROM, CE_EECS | b); micro_delay(EESK_PERIOD/2+1); } @@ -2052,7 +1620,7 @@ fxp_t *fp; fxp_outb(port, CSR_EEPROM, CE_EECS | b); /* bit */ fxp_outb(port, CSR_EEPROM, CE_EECS | b | CE_EESK); /* Clock */ micro_delay(EESK_PERIOD/2+1); - fxp_outb(port, CSR_EEPROM, CE_EECS | b); + fxp_outb(port, CSR_EEPROM, CE_EECS | b); micro_delay(EESK_PERIOD/2+1); v= fxp_inb(port, CSR_EEPROM); if (!(v & CE_EEDO)) @@ -2067,7 +1635,7 @@ fxp_t *fp; { fxp_outb(port, CSR_EEPROM, CE_EECS | CE_EESK); /* Clock */ micro_delay(EESK_PERIOD/2+1); - fxp_outb(port, CSR_EEPROM, CE_EECS ); + fxp_outb(port, CSR_EEPROM, CE_EECS ); micro_delay(EESK_PERIOD/2+1); } fxp_outb(port, CSR_EEPROM, 0); /* Disable EEPROM */ @@ -2082,9 +1650,7 @@ fxp_t *fp; /*===========================================================================* * mii_read * *===========================================================================*/ -static u16_t mii_read(fp, reg) -fxp_t *fp; -int reg; +static u16_t mii_read(fxp_t *fp, int reg) { spin_t spin; port_t port; @@ -2092,9 +1658,6 @@ int reg; port= fp->fxp_base_port; - assert(!fp->fxp_mii_busy); - fp->fxp_mii_busy++; - if (!(fxp_inl(port, CSR_MDI_CTL) & CM_READY)) panic("mii_read: MDI not ready"); fxp_outl(port, CSR_MDI_CTL, CM_READ | (1 << CM_PHYADDR_SHIFT) | @@ -2110,9 +1673,6 @@ int reg; if (!(v & CM_READY)) panic("mii_read: MDI not ready after command"); - fp->fxp_mii_busy--; - assert(!fp->fxp_mii_busy); - return v & CM_DATA_MASK; } @@ -2156,12 +1716,9 @@ static void do_outl(port_t port, u32_t value) panic("sys_outl failed: %d", r); } -static void tell_dev(buf, size, pci_bus, pci_dev, pci_func) -vir_bytes buf; -size_t size; -int pci_bus; -int pci_dev; -int pci_func; +/* TODO: obviously this needs a lot of work. */ +static void tell_iommu(vir_bytes buf, size_t size, int pci_bus, int pci_dev, + int pci_func) { int r; endpoint_t dev_e; @@ -2171,9 +1728,8 @@ int pci_func; if (r != OK) { #if 0 - printf( - "fxp`tell_dev: ds_retrieve_label_endpt failed for 'amddev': %d\n", - r); + printf("fxp`tell_iommu: ds_retrieve_label_endpt failed " + "for 'amddev': %d\n", r); #endif return; } @@ -2188,13 +1744,13 @@ int pci_func; r= ipc_sendrec(dev_e, &m); if (r != OK) { - printf("fxp`tell_dev: ipc_sendrec to %d failed: %d\n", + printf("fxp`tell_iommu: ipc_sendrec to %d failed: %d\n", dev_e, r); return; } if (m.m_type != OK) { - printf("fxp`tell_dev: dma map request failed: %d\n", + printf("fxp`tell_iommu: dma map request failed: %d\n", m.m_type); return; } @@ -2203,4 +1759,3 @@ int pci_func; /* * $PchId: fxp.c,v 1.4 2005/01/31 22:10:37 philip Exp $ */ - diff --git a/minix/drivers/net/lan8710a/Makefile b/minix/drivers/net/lan8710a/Makefile index 79d790d5e..a3387079f 100644 --- a/minix/drivers/net/lan8710a/Makefile +++ b/minix/drivers/net/lan8710a/Makefile @@ -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 diff --git a/minix/drivers/net/lan8710a/lan8710a.c b/minix/drivers/net/lan8710a/lan8710a.c index 9eac5d698..eb5ecbdea 100644 --- a/minix/drivers/net/lan8710a/lan8710a.c +++ b/minix/drivers/net/lan8710a/lan8710a.c @@ -1,31 +1,28 @@ #include #include -#include -#include -#include #include +#include #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); - } -} diff --git a/minix/drivers/net/lan8710a/lan8710a.h b/minix/drivers/net/lan8710a/lan8710a.h index 214df87cc..3dca3a787 100644 --- a/minix/drivers/net/lan8710a/lan8710a.h +++ b/minix/drivers/net/lan8710a/lan8710a.h @@ -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; diff --git a/minix/drivers/net/lance/lance.c b/minix/drivers/net/lance/lance.c index cf86f9d9e..b63d40029 100644 --- a/minix/drivers/net/lance/lance.c +++ b/minix/drivers/net/lance/lance.c @@ -4,38 +4,6 @@ * This file contains a ethernet device driver for AMD LANCE based ethernet * cards. * - * The valid messages and their parameters are: - * - * m_type DL_COUNT DL_MODE DL_GRANT - * |--------------+----------+---------+---------| - * | DL_WRITEV_S | count | | grant | - * |--------------|----------|---------|---------| - * | DL_READV_S | count | | grant | - * |--------------|----------|---------|---------| - * | DL_CONF | | mode | | - * |--------------|----------|---------|---------| - * | DL_GETSTAT_S | | | grant | - * |--------------|----------|---------|---------| - * | hardware int | | | | - * |--------------|----------|---------|---------| - * - * The messages sent are: - * - * m_type DL_COUNT DL_FLAGS - * |---------------+----------+---------| - * | DL_TASK_REPLY | rd-count | flags | - * |---------------|----------|---------| - * - * m_type - * |---------------| - * | DL_STAT_REPLY | - * |---------------| - * - * m_type DL_STAT DL_ADDR - * |---------------+---------+---------------| - * | DL_CONF_REPLY | code | ethernet addr | - * |---------------|---------|---------------| - * * Created: Jul 27, 2002 by Kazuya Kodama * Adapted for Minix 3: Sep 05, 2005 by Joren l'Ami */ @@ -58,58 +26,21 @@ #include "lance.h" -static ether_card_t ec_state; -static int ec_instance; - -/* Configuration */ -typedef struct ec_conf -{ - port_t ec_port; - int ec_irq; - phys_bytes ec_mem; -} ec_conf_t; - -/* We hardly use these. Just "LANCE0=on/off" "LANCE1=on/off" mean. */ -#define EC_CONF_NR 3 -ec_conf_t ec_conf[EC_CONF_NR]= /* Card addresses */ -{ - /* I/O port, IRQ, Buffer address. */ - { 0x1000, 9, 0x00000, }, - { 0xD000, 15, 0x00000, }, - { 0x0000, 0, 0x00000, }, -}; - -/* General */ -static void do_init(message *mp); -static void ec_init(ether_card_t *ec); -static void ec_confaddr(ether_card_t *ec); +static int do_init(unsigned int instance, ether_addr_t *addr); +static void ec_confaddr(ether_addr_t *addr); static void ec_reinit(ether_card_t *ec); -static void ec_check_ints(ether_card_t *ec); -static void conf_hw(ether_card_t *ec); -static void update_conf(ether_card_t *ec, ec_conf_t *ecp); -static void mess_reply(message *req, message *reply); -static void do_int(ether_card_t *ec); -static void reply(ether_card_t *ec); static void ec_reset(ether_card_t *ec); -static void ec_send(ether_card_t *ec); -static void ec_recv(ether_card_t *ec); -static void do_vwrite_s(message *mp, int from_int); -static void do_vread_s(const message *mp); -static void ec_user2nic(ether_card_t *dep, iovec_dat_t *iovp, vir_bytes - offset, int nic_addr, vir_bytes count); -static void ec_nic2user(ether_card_t *ec, int nic_addr, iovec_dat_t - *iovp, vir_bytes offset, vir_bytes count); -static int calc_iovec_size(iovec_dat_t *iovp); -static void ec_next_iovec(iovec_dat_t *iovp); -static void do_getstat_s(message *mp); -static void lance_stop(ether_card_t *ec); - +static void do_intr(unsigned int mask); +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_stop(void); static void lance_dump(void); -static void getAddressing(int devind, ether_card_t *ec); - -/* probe+init LANCE cards */ -static int lance_probe(ether_card_t *ec, int skip); -static void lance_init_card(ether_card_t *ec); +static void do_other(const message *m_ptr, int ipc_status); +static void get_addressing(int devind, ether_card_t *ec); +static int lance_probe(ether_card_t *ec, unsigned int skip); +static void lance_init_hw(ether_card_t *ec, ether_addr_t *addr); /* Accesses Lance Control and Status Registers */ static u8_t in_byte(port_t port); @@ -118,28 +49,12 @@ static void out_word(port_t port, u16_t value); static u16_t read_csr(port_t ioaddr, u16_t csrno); static void write_csr(port_t ioaddr, u16_t csrno, u16_t value); +static ether_card_t ec_state; +static int ec_instance; + /* --- LANCE --- */ /* General */ -typedef unsigned long Address; - -#define virt_to_bus(x) (vir2phys((unsigned long)x)) -unsigned long vir2phys( unsigned long x ) -{ - int r; - unsigned long value; - - if ( (r=sys_umap( SELF, VM_D, x, 4, &value )) != OK ) { - printf("lance: umap of 0x%lx failed\n",x ); - panic("sys_umap failed: %d", r); - } - - return value; -} - -/* DMA limitations */ -#define DMA_ADDR_MASK 0xFFFFFF /* mask to verify DMA address is 24-bit */ - -#define CORRECT_DMA_MEM() ( (virt_to_bus(lance_buf + sizeof(struct lance_interface)) & ~DMA_ADDR_MASK) == 0 ) +typedef uint32_t Address; #define ETH_FRAME_LEN 1518 @@ -240,153 +155,33 @@ static char *lance_buf = NULL; static int rx_slot_nr = 0; /* Rx-slot number */ static int tx_slot_nr = 0; /* Tx-slot number */ static int cur_tx_slot_nr = 0; /* Tx-slot number */ +static phys_bytes tx_ring_base[TX_RING_SIZE]; /* Tx-slot physical address */ static char isstored[TX_RING_SIZE]; /* Tx-slot in-use */ -phys_bytes lance_buf_phys; - -/* 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); +static const struct netdriver lance_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, +}; /*===========================================================================* * main * *===========================================================================*/ -int main( int argc, char **argv ) +int main(int argc, char **argv) { - message m; - int ipc_status; - int r; - ether_card_t *ec; - /* SEF local startup. */ env_setargs(argc, argv); - sef_local_startup(); - ec= &ec_state; - - while (TRUE) - { - if (ec->ec_irq != 0) - sys_irqenable(&ec->ec_hook); - - if ((r= netdriver_receive(ANY, &m, &ipc_status)) != OK) - panic("netdriver_receive failed: %d", r); - - if (ec->ec_irq != 0) - sys_irqdisable(&ec->ec_hook); - - if (is_ipc_notify(ipc_status)) { - switch(_ENDPOINT_P(m.m_source)) { - case TTY_PROC_NR: - lance_dump(); - break; - case HARDWARE: - if (ec->mode == EC_ENABLED) - { - ec->ec_int_pending = 0; - ec_check_ints(ec); - do_int(ec); - } - break; - default: - panic("illegal notify source: %d", m.m_source); - } - - /* get next message */ - continue; - } - - switch (m.m_type) - { - case DL_WRITEV_S: - do_vwrite_s(&m, FALSE); - break; - case DL_READV_S: - do_vread_s(&m); - break; - case DL_CONF: - do_init(&m); - break; - case DL_GETSTAT_S: - do_getstat_s(&m); - break; - default: - panic("illegal message: %d", m.m_type); - } - } + netdriver_task(&lance_table); 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 lance driver. */ - long v; -#if LANCE_FKEY - int r, fkeys, sfkeys; -#endif - -#if LANCE_FKEY - fkeys = sfkeys = 0; - bit_set( sfkeys, 7 ); - if ( (r = fkey_map(&fkeys, &sfkeys)) != OK ) - printf("Warning: lance couldn't observe Shift+F7 key: %d\n",r); -#endif - - v = 0; - (void) env_parse("instance", "d", 0, &v, 0, 255); - ec_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 (ec_state.mode == EC_ENABLED) - lance_stop(&ec_state); - -#if VERBOSE - printf("LANCE driver stopped.\n"); -#endif - - exit(0); -} - /*===========================================================================* * lance_dump * *===========================================================================*/ @@ -395,41 +190,34 @@ static void lance_dump() ether_card_t *ec; int isr, csr; unsigned short ioaddr; - + printf("\n"); ec = &ec_state; - if (ec->mode == EC_DISABLED) - printf("lance instance %d is disabled\n", ec_instance); - else if (ec->mode == EC_SINK) - printf("lance instance %d is in sink mode\n", ec_instance); - if (ec->mode != EC_ENABLED) - return; - printf("lance statistics of instance %d:\n", ec_instance); - + printf("recvErr :%8ld\t", ec->eth_stat.ets_recvErr); printf("sendErr :%8ld\t", ec->eth_stat.ets_sendErr); printf("OVW :%8ld\n", ec->eth_stat.ets_OVW); - + printf("CRCerr :%8ld\t", ec->eth_stat.ets_CRCerr); printf("frameAll :%8ld\t", ec->eth_stat.ets_frameAll); printf("missedP :%8ld\n", ec->eth_stat.ets_missedP); - + printf("packetR :%8ld\t", ec->eth_stat.ets_packetR); printf("packetT :%8ld\t", ec->eth_stat.ets_packetT); printf("transDef :%8ld\n", ec->eth_stat.ets_transDef); - + printf("collision :%8ld\t", ec->eth_stat.ets_collision); printf("transAb :%8ld\t", ec->eth_stat.ets_transAb); printf("carrSense :%8ld\n", ec->eth_stat.ets_carrSense); - + printf("fifoUnder :%8ld\t", ec->eth_stat.ets_fifoUnder); printf("fifoOver :%8ld\t", ec->eth_stat.ets_fifoOver); printf("CDheartbeat:%8ld\n", ec->eth_stat.ets_CDheartbeat); - + printf("OWC :%8ld\t", ec->eth_stat.ets_OWC); - + ioaddr = ec->ec_port; isr = read_csr(ioaddr, LANCE_CSR0); printf("isr = 0x%x, flags = 0x%x\n", isr, @@ -450,261 +238,19 @@ static void lance_dump() } /*===========================================================================* - * do_init * + * do_other * *===========================================================================*/ -static void do_init(mp) -message *mp; +static void do_other(const message *m_ptr, int ipc_status) { - ether_card_t *ec; - message reply_mess; - pci_init(); - - if(!lance_buf && !(lance_buf = alloc_contig(LANCE_BUF_SIZE, AC_ALIGN4K|AC_LOWER16M, &lance_buf_phys))) { - panic("alloc_contig failed: %d", LANCE_BUF_SIZE); - } - - ec= &ec_state; - strlcpy(ec->port_name, "lance#0", sizeof(ec->port_name)); - ec->port_name[6] += ec_instance; - - if (ec->mode == EC_DISABLED) - { - /* This is the default, try to (re)locate the device. */ - /* only try to enable if memory is correct for DMA */ - if ( CORRECT_DMA_MEM() ) - { - conf_hw(ec); - } - else - { - printf("LANCE: DMA denied because address out of range\n" ); - } - - if (ec->mode == EC_DISABLED) - { - /* Probe failed, or the device is configured off. */ - reply_mess.m_type= DL_CONF_REPLY; - reply_mess.m_netdrv_net_dl_conf.stat = ENXIO; - mess_reply(mp, &reply_mess); - return; - } - if (ec->mode == EC_ENABLED) - ec_init(ec); - } - - if (ec->mode == EC_SINK) - { - ec->mac_address.ea_addr[0] = - ec->mac_address.ea_addr[1] = - ec->mac_address.ea_addr[2] = - ec->mac_address.ea_addr[3] = - ec->mac_address.ea_addr[4] = - ec->mac_address.ea_addr[5] = 0; - ec_confaddr(ec); - reply_mess.m_type = DL_CONF_REPLY; - reply_mess.m_netdrv_net_dl_conf.stat = OK; - memcpy(reply_mess.m_netdrv_net_dl_conf.hw_addr, ec->mac_address.ea_addr, - sizeof(reply_mess.m_netdrv_net_dl_conf.hw_addr)); - mess_reply(mp, &reply_mess); - return; - } - assert(ec->mode == EC_ENABLED); - assert(ec->flags & ECF_ENABLED); - - ec->flags &= ~(ECF_PROMISC | ECF_MULTI | ECF_BROAD); - - if (mp->m_net_netdrv_dl_conf.mode & DL_PROMISC_REQ) - ec->flags |= ECF_PROMISC | ECF_MULTI | ECF_BROAD; - if (mp->m_net_netdrv_dl_conf.mode & DL_MULTI_REQ) - ec->flags |= ECF_MULTI; - if (mp->m_net_netdrv_dl_conf.mode & DL_BROAD_REQ) - ec->flags |= ECF_BROAD; - - ec_reinit(ec); - - reply_mess.m_type = DL_CONF_REPLY; - reply_mess.m_netdrv_net_dl_conf.stat = OK; - memcpy(reply_mess.m_netdrv_net_dl_conf.hw_addr, ec->mac_address.ea_addr, - sizeof(reply_mess.m_netdrv_net_dl_conf.hw_addr)); - - mess_reply(mp, &reply_mess); + if (is_ipc_notify(ipc_status) && m_ptr->m_source == TTY_PROC_NR) + lance_dump(); } - -/*===========================================================================* - * do_int * - *===========================================================================*/ -static void do_int(ec) -ether_card_t *ec; -{ - if (ec->flags & (ECF_PACK_SEND | ECF_PACK_RECV)) - reply(ec); -} - - -/*===========================================================================* - * conf_hw * - *===========================================================================*/ -static void conf_hw(ec) -ether_card_t *ec; -{ - static eth_stat_t empty_stat = {0, 0, 0, 0, 0, 0 /* ,... */ }; - - int confnr; - ec_conf_t *ecp; - - ec->mode= EC_DISABLED; /* Superfluous */ - - /* Pick a default configuration. This hardly matters anymore. */ - confnr= MIN(ec_instance, EC_CONF_NR-1); - - ecp= &ec_conf[confnr]; - update_conf(ec, ecp); - if (ec->mode != EC_ENABLED) - return; - - if (!lance_probe(ec, ec_instance)) - { - printf("%s: No ethernet card found on PCI-BIOS info.\n", - ec->port_name); - ec->mode= EC_DISABLED; - return; - } - - /* XXX */ if (ec->ec_linmem == 0) ec->ec_linmem= 0xFFFF0000; - - ec->flags = ECF_EMPTY; - ec->eth_stat = empty_stat; -} - - -/*===========================================================================* - * update_conf * - *===========================================================================*/ -static void update_conf(ec, ecp) -ether_card_t *ec; -ec_conf_t *ecp; -{ - long v; - char eckey[16]; - static char ec_fmt[] = "x:d:x:x"; - - /* Get the default settings and modify them from the environment. */ - strlcpy(eckey, "LANCE0", sizeof(eckey)); - eckey[5] += ec_instance; - ec->mode= EC_SINK; - v= ecp->ec_port; - switch (env_parse(eckey, ec_fmt, 0, &v, 0x0000L, 0xFFFFL)) - { - case EP_OFF: - ec->mode= EC_DISABLED; - break; - case EP_ON: - case EP_SET: - default: - ec->mode= EC_ENABLED; /* Might become disabled if - * all probes fail */ - break; - } - - ec->ec_port= v; - - v= ecp->ec_irq | DEI_DEFAULT; - (void) env_parse(eckey, ec_fmt, 1, &v, 0L, (long) NR_IRQ_VECTORS - 1); - ec->ec_irq= v; - - v= ecp->ec_mem; - (void) env_parse(eckey, ec_fmt, 2, &v, 0L, 0xFFFFFL); - ec->ec_linmem= v; - - v= 0; - (void) env_parse(eckey, ec_fmt, 3, &v, 0x2000L, 0x8000L); - ec->ec_ramsize= v; -} - - -/*===========================================================================* - * ec_init * - *===========================================================================*/ -static void ec_init(ec) -ether_card_t *ec; -{ - int r; -#if VERBOSE - int i; -#endif - - /* General initialization */ - ec->flags = ECF_EMPTY; - lance_init_card(ec); /* Get mac_address, etc ...*/ - - ec_confaddr(ec); - -#if VERBOSE - printf("%s: Ethernet address ", ec->port_name); - for (i= 0; i < 6; i++) - printf("%x%c", ec->mac_address.ea_addr[i], - i < 5 ? ':' : '\n'); -#endif - - /* Finish the initialization */ - ec->flags |= ECF_ENABLED; - - /* Set the interrupt handler */ - ec->ec_hook = ec->ec_irq; - if ((r=sys_irqsetpolicy(ec->ec_irq, 0, &ec->ec_hook)) != OK) - printf("lance: error, couldn't set IRQ policy: %d\n", r); - - return; -} - - -/*===========================================================================* - * reply * - *===========================================================================*/ -static void reply(ec) -ether_card_t *ec; -{ - message reply; - int flags,r; - - flags = DL_NOFLAGS; - if (ec->flags & ECF_PACK_SEND) - flags |= DL_PACK_SEND; - if (ec->flags & ECF_PACK_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 = ec->read_s; - - r = ipc_send(ec->client, &reply); - if (r < 0) - panic("ipc_send failed: %d", r); - - ec->read_s = 0; - ec->flags &= ~(ECF_PACK_SEND | ECF_PACK_RECV); -} - - -/*===========================================================================* - * mess_reply * - *===========================================================================*/ -static void mess_reply(req, reply_mess) -message *req; -message *reply_mess; -{ - if (ipc_send(req->m_source, reply_mess) != OK) - panic("unable to mess_reply"); -} - - /*===========================================================================* * ec_confaddr * *===========================================================================*/ -static void ec_confaddr(ec) -ether_card_t *ec; +static void ec_confaddr(ether_addr_t *addr) { int i; char eakey[16]; @@ -717,25 +263,68 @@ ether_card_t *ec; for (i = 0; i < 6; i++) { - v= ec->mac_address.ea_addr[i]; + v= addr->ea_addr[i]; if (env_parse(eakey, eafmt, i, &v, 0x00L, 0xFFL) != EP_SET) break; - ec->mac_address.ea_addr[i]= v; + addr->ea_addr[i]= v; } - + if (i != 0 && i != 6) { /* It's all or nothing; force a panic. */ - (void) env_parse(eakey, "?", 0, &v, 0L, 0L); + panic("invalid ethernet address supplied"); } } +/*===========================================================================* + * do_init * + *===========================================================================*/ +static int do_init(unsigned int instance, ether_addr_t *addr) +{ +/* Initialize the lance driver. */ + ether_card_t *ec; +#if VERBOSE + int i, r; +#endif +#if LANCE_FKEY + int fkeys, sfkeys; +#endif + +#if LANCE_FKEY + fkeys = sfkeys = 0; + bit_set( sfkeys, 7 ); + if ( (r = fkey_map(&fkeys, &sfkeys)) != OK ) + printf("Warning: lance couldn't observe Shift+F7 key: %d\n",r); +#endif + + ec_instance = instance; + + /* Initialize the driver state. */ + ec= &ec_state; + memset(ec, 0, sizeof(*ec)); + strlcpy(ec->port_name, "lance#0", sizeof(ec->port_name)); + ec->port_name[6] += instance; + + /* See if there is a matching card. */ + if (!lance_probe(ec, instance)) + return ENXIO; + + /* Initialize the hardware. */ + lance_init_hw(ec, addr); + +#if VERBOSE + printf("%s: Ethernet address ", ec->port_name); + for (i= 0; i < 6; i++) + printf("%x%c", addr->ea_addr[i], i < 5 ? ':' : '\n'); +#endif + + return OK; +} /*===========================================================================* * ec_reinit * *===========================================================================*/ -static void ec_reinit(ec) -ether_card_t *ec; +static void ec_reinit(ether_card_t *ec) { int i; unsigned short ioaddr = ec->ec_port; @@ -784,18 +373,39 @@ ether_card_t *ec; } /*===========================================================================* - * ec_check_ints * + * do_mode * *===========================================================================*/ -static void ec_check_ints(ec) -ether_card_t *ec; +static void do_mode(unsigned int mode) { - int must_restart = 0; - int check,status; - int isr = 0x0000; - unsigned short ioaddr = ec->ec_port; + ether_card_t *ec; - if (!(ec->flags & ECF_ENABLED)) - panic("got premature interrupt"); + ec = &ec_state; + + ec->flags &= ~(ECF_PROMISC | ECF_MULTI | ECF_BROAD); + + if (mode & NDEV_PROMISC) + ec->flags |= ECF_PROMISC | ECF_MULTI | ECF_BROAD; + if (mode & NDEV_MULTI) + ec->flags |= ECF_MULTI; + if (mode & NDEV_BROAD) + ec->flags |= ECF_BROAD; + + ec_reinit(ec); +} + +/*===========================================================================* + * do_intr * + *===========================================================================*/ +static void do_intr(unsigned int __unused mask) +{ + ether_card_t *ec; + int must_restart = 0; + int r, check, status; + int isr = 0x0000; + unsigned short ioaddr; + + ec = &ec_state; + ioaddr = ec->ec_port; for (;;) { @@ -812,8 +422,6 @@ ether_card_t *ec; LANCE_CSR0_BABL|LANCE_CSR0_CERR|LANCE_CSR0_MISS|LANCE_CSR0_MERR |LANCE_CSR0_IDON|LANCE_CSR0_IENA); -#define ISR_RST 0x0000 - if ((isr & (LANCE_CSR0_TINT|LANCE_CSR0_RINT|LANCE_CSR0_MISS |LANCE_CSR0_BABL|LANCE_CSR0_ERR)) == 0x0000) { @@ -847,18 +455,18 @@ ether_card_t *ec; /* status check: restart if needed. */ status = lp->tx_ring[cur_tx_slot_nr].u.base; - /* ??? */ + /* did an error (UFLO, LCOL, LCAR, RTRY) occur? */ if (status & 0x40000000) { status = lp->tx_ring[cur_tx_slot_nr].misc; ec->eth_stat.ets_sendErr++; - if (status & 0x0400) + if (status & 0x0400) /* RTRY */ ec->eth_stat.ets_transAb++; - if (status & 0x0800) + if (status & 0x0800) /* LCAR */ ec->eth_stat.ets_carrSense++; - if (status & 0x1000) + if (status & 0x1000) /* LCOL */ ec->eth_stat.ets_OWC++; - if (status & 0x4000) + if (status & 0x4000) /* UFLO */ { ec->eth_stat.ets_fifoUnder++; must_restart=1; @@ -896,55 +504,43 @@ ether_card_t *ec; } /* we set a buffered message in the slot if it exists. */ /* and transmit it, if needed. */ - if (ec->flags & ECF_SEND_AVAIL) - ec_send(ec); + if (!must_restart) + netdriver_send(); } if (isr & LANCE_CSR0_RINT) { #if VERBOSE printf("RX INT\n"); #endif - ec_recv(ec); + netdriver_recv(); } - if (isr & ISR_RST) - { - ec->flags = ECF_STOPPED; -#if VERBOSE - printf("ISR_RST\n"); -#endif - break; - } - - /* ??? cf. lance driver on linux */ if (must_restart == 1) { #if VERBOSE printf("ETH: restarting...\n"); #endif - /* stop */ - write_csr(ioaddr, LANCE_CSR0, LANCE_CSR0_STOP); - /* start */ - write_csr(ioaddr, LANCE_CSR0, LANCE_CSR0_STRT); + + ec_reset(ec); } } - if ((ec->flags & (ECF_READING|ECF_STOPPED)) == (ECF_READING|ECF_STOPPED)) - { -#if VERBOSE - printf("ETH: resetting...\n"); -#endif - ec_reset(ec); - } + /* reenable interrupts */ + if ((r = sys_irqenable(&ec->ec_hook)) != OK) + panic("couldn't enable interrupt: %d", r); } /*===========================================================================* * ec_reset * *===========================================================================*/ -static void ec_reset(ec) -ether_card_t *ec; +static void ec_reset(ether_card_t *ec) { - /* Stop/start the chip, and clear all RX,TX-slots */ + /* Stop/start the chip, and clear all RX,TX-slots. The spec says this type + * of reset should be done on MERR, UFLO, and TX BUFF errors. For now it is + * called only for UFLO and TX BUFF (which causes UFLO). MERR is not (yet?) + * handled. Also note that the PCnet spec says that the LANCE chip does not + * require resetting Rx/Tx, but PCnet does. We intend to support both here. + */ unsigned short ioaddr = ec->ec_port; int i; @@ -969,185 +565,101 @@ ether_card_t *ec; lp->rx_ring[i].u.addr[3] |= 0x80; } - /* store a buffered message on the slot if exists */ - ec_send(ec); - ec->flags &= ~ECF_STOPPED; + /* store a buffered message on the slot if it exists */ + netdriver_send(); } /*===========================================================================* - * ec_send * + * do_recv * *===========================================================================*/ -static void ec_send(ec) -ether_card_t *ec; +static ssize_t do_recv(struct netdriver_data *data, size_t max) { - /* from ec_check_ints() or ec_reset(). */ - /* this function proccesses the buffered message. (slot/transmit) */ - if (!(ec->flags & ECF_SEND_AVAIL)) - return; - - ec->flags &= ~ECF_SEND_AVAIL; - switch(ec->sendmsg.m_type) - { - case DL_WRITEV_S: do_vwrite_s(&ec->sendmsg, TRUE); break; - default: - panic("wrong type: %d", ec->sendmsg.m_type); - break; - } -} - -/*===========================================================================* - * do_vread_s * - *===========================================================================*/ -static void do_vread_s(const message *mp) -{ - int count, r; ether_card_t *ec; - - ec= &ec_state; - - ec->client= mp->m_source; - count = mp->m_net_netdrv_dl_readv_s.count; - - r = sys_safecopyfrom(mp->m_source, mp->m_net_netdrv_dl_readv_s.grant, 0, - (vir_bytes)ec->read_iovec.iod_iovec, - (count > IOVEC_NR ? IOVEC_NR : count) * - sizeof(iovec_s_t)); - if (r != OK) - panic("do_vread_s: sys_safecopyfrom failed: %d", r); - ec->read_iovec.iod_iovec_s = count; - ec->read_iovec.iod_proc_nr = mp->m_source; - ec->read_iovec.iod_grant = mp->m_net_netdrv_dl_readv_s.grant; - ec->read_iovec.iod_iovec_offset = 0; - - ec->tmp_iovec = ec->read_iovec; - - ec->flags |= ECF_READING; - - ec_recv(ec); - - if ((ec->flags & (ECF_READING|ECF_STOPPED)) == (ECF_READING|ECF_STOPPED)) - ec_reset(ec); - reply(ec); -} - -/*===========================================================================* - * ec_recv * - *===========================================================================*/ -static void ec_recv(ec) -ether_card_t *ec; -{ vir_bytes length; int packet_processed; int status; - unsigned short ioaddr = ec->ec_port; + unsigned short ioaddr; - if ((ec->flags & ECF_READING)==0) - return; - if (!(ec->flags & ECF_ENABLED)) - return; + ec = &ec_state; + ioaddr = ec->ec_port; /* we check all the received slots until find a properly received packet */ packet_processed = FALSE; while (!packet_processed) { status = lp->rx_ring[rx_slot_nr].u.base >> 24; - if ( (status & 0x80) == 0x00 ) + + /* is the slot marked as ready? */ + if ( (status & 0x80) != 0x00 ) + return SUSPEND; /* no */ + + /* did an error occur? */ + if (status != 0x03) { - status = lp->rx_ring[rx_slot_nr].u.base >> 24; - - /* ??? */ - if (status != 0x03) - { - if (status & 0x01) - ec->eth_stat.ets_recvErr++; - if (status & 0x04) - ec->eth_stat.ets_fifoOver++; - if (status & 0x08) - ec->eth_stat.ets_CRCerr++; - if (status & 0x10) - ec->eth_stat.ets_OVW++; - if (status & 0x20) - ec->eth_stat.ets_frameAll++; - length = 0; - } - else - { - ec->eth_stat.ets_packetR++; - length = lp->rx_ring[rx_slot_nr].msg_length; - } - if (length > 0) - { - ec_nic2user(ec, (int)(lp->rbuf[rx_slot_nr]), - &ec->read_iovec, 0, length); - - ec->read_s = length; - ec->flags |= ECF_PACK_RECV; - ec->flags &= ~ECF_READING; - packet_processed = TRUE; - } - /* set up this slot again, and we move to the next slot */ - lp->rx_ring[rx_slot_nr].buf_length = -ETH_FRAME_LEN; - lp->rx_ring[rx_slot_nr].u.addr[3] |= 0x80; - - write_csr(ioaddr, LANCE_CSR0, - LANCE_CSR0_BABL|LANCE_CSR0_CERR|LANCE_CSR0_MISS - |LANCE_CSR0_MERR|LANCE_CSR0_IDON|LANCE_CSR0_IENA); - - rx_slot_nr = (rx_slot_nr + 1) & RX_RING_MOD_MASK; + if (status & 0x01) + ec->eth_stat.ets_recvErr++; + if (status & 0x04) + ec->eth_stat.ets_fifoOver++; + if (status & 0x08) + ec->eth_stat.ets_CRCerr++; + if (status & 0x10) + ec->eth_stat.ets_OVW++; + if (status & 0x20) + ec->eth_stat.ets_frameAll++; + length = 0; } else - break; + { + ec->eth_stat.ets_packetR++; + length = lp->rx_ring[rx_slot_nr].msg_length; + } + + /* do we now have a valid packet? */ + if (length > 0) + { + if (length > max) + length = max; + netdriver_copyout(data, 0, lp->rbuf[rx_slot_nr], length); + packet_processed = TRUE; + } + + /* set up this slot again, and we move to the next slot */ + lp->rx_ring[rx_slot_nr].buf_length = -ETH_FRAME_LEN; + lp->rx_ring[rx_slot_nr].u.addr[3] |= 0x80; + + write_csr(ioaddr, LANCE_CSR0, + LANCE_CSR0_BABL|LANCE_CSR0_CERR|LANCE_CSR0_MISS + |LANCE_CSR0_MERR|LANCE_CSR0_IDON|LANCE_CSR0_IENA); + + rx_slot_nr = (rx_slot_nr + 1) & RX_RING_MOD_MASK; } + + /* return the length of the packet we have received */ + return length; } /*===========================================================================* - * do_vwrite_s * + * do_send * *===========================================================================*/ -static void do_vwrite_s(mp, from_int) -message *mp; -int from_int; +static int do_send(struct netdriver_data *data, size_t size) { - int count, check, r; + int check; ether_card_t *ec; unsigned short ioaddr; ec = &ec_state; - ec->client= mp->m_source; - count = mp->m_net_netdrv_dl_writev_s.count; - + /* if all slots are used, this request must be deferred */ if (isstored[tx_slot_nr]==1) - { - /* all slots are used, so this message is buffered */ - ec->sendmsg= *mp; - ec->flags |= ECF_SEND_AVAIL; - reply(ec); - return; - } + return SUSPEND; - /* convert the message to write_iovec */ - r = sys_safecopyfrom(mp->m_source, mp->m_net_netdrv_dl_writev_s.grant, 0, - (vir_bytes)ec->write_iovec.iod_iovec, - (count > IOVEC_NR ? IOVEC_NR : count) * - sizeof(iovec_s_t)); - if (r != OK) - panic("do_vwrite_s: sys_safecopyfrom failed: %d", r); - ec->write_iovec.iod_iovec_s = count; - ec->write_iovec.iod_proc_nr = mp->m_source; - ec->write_iovec.iod_grant = mp->m_net_netdrv_dl_writev_s.grant; - ec->write_iovec.iod_iovec_offset = 0; + /* copy the packet to the slot on DMA address */ + netdriver_copyin(data, 0, lp->tbuf[tx_slot_nr], size); - ec->tmp_iovec = ec->write_iovec; - ec->write_s = calc_iovec_size(&ec->tmp_iovec); - - /* copy write_iovec to the slot on DMA address */ - ec_user2nic(ec, &ec->write_iovec, 0, - (int)(lp->tbuf[tx_slot_nr]), ec->write_s); /* set-up for transmitting, and transmit it if needed. */ - lp->tx_ring[tx_slot_nr].buf_length = -ec->write_s; + lp->tx_ring[tx_slot_nr].buf_length = -size; lp->tx_ring[tx_slot_nr].misc = 0x0; - lp->tx_ring[tx_slot_nr].u.base - = virt_to_bus(lp->tbuf[tx_slot_nr]) & 0xffffff; + lp->tx_ring[tx_slot_nr].u.base = tx_ring_base[tx_slot_nr]; isstored[tx_slot_nr]=1; if (cur_tx_slot_nr == tx_slot_nr) check=1; @@ -1161,198 +673,44 @@ int from_int; lp->tx_ring[cur_tx_slot_nr].u.addr[3] = 0x83; write_csr(ioaddr, LANCE_CSR0, LANCE_CSR0_IENA|LANCE_CSR0_TDMD); } - - ec->flags |= ECF_PACK_SEND; - /* reply by calling do_int() if this function is called from interrupt. */ - if (from_int) - return; - reply(ec); -} - - -/*===========================================================================* - * ec_user2nic * - *===========================================================================*/ -static void ec_user2nic(ec, iovp, offset, nic_addr, count) -ether_card_t *ec; -iovec_dat_t *iovp; -vir_bytes offset; -int nic_addr; -vir_bytes count; -{ - int bytes, i, r; - - i= 0; - while (count > 0) - { - if (i >= IOVEC_NR) - { - ec_next_iovec(iovp); - i= 0; - continue; - } - if (offset >= iovp->iod_iovec[i].iov_size) - { - offset -= iovp->iod_iovec[i].iov_size; - i++; - continue; - } - bytes = iovp->iod_iovec[i].iov_size - offset; - if (bytes > count) - bytes = count; - - if ( (r=sys_safecopyfrom(iovp->iod_proc_nr, - iovp->iod_iovec[i].iov_grant, offset, - nic_addr, bytes )) != OK ) - panic("ec_user2nic: sys_safecopyfrom failed: %d", r); - - count -= bytes; - nic_addr += bytes; - offset += bytes; - } + return OK; } /*===========================================================================* - * ec_nic2user * + * do_stat * *===========================================================================*/ -static void ec_nic2user(ec, nic_addr, iovp, offset, count) -ether_card_t *ec; -int nic_addr; -iovec_dat_t *iovp; -vir_bytes offset; -vir_bytes count; +static void do_stat(eth_stat_t *stat) { - int bytes, i, r; - i= 0; - while (count > 0) - { - if (i >= IOVEC_NR) - { - ec_next_iovec(iovp); - i= 0; - continue; - } - if (offset >= iovp->iod_iovec[i].iov_size) - { - offset -= iovp->iod_iovec[i].iov_size; - i++; - continue; - } - bytes = iovp->iod_iovec[i].iov_size - offset; - if (bytes > count) - bytes = count; - if ( (r=sys_safecopyto( iovp->iod_proc_nr, iovp->iod_iovec[i].iov_grant, - offset, nic_addr, bytes )) != OK ) - panic("ec_nic2user: sys_safecopyto failed: %d", r); - - count -= bytes; - nic_addr += bytes; - offset += bytes; - } -} - - -/*===========================================================================* - * calc_iovec_size * - *===========================================================================*/ -static int calc_iovec_size(iovec_dat_t *iovp) -{ - int size,i; - - size = i = 0; - - while (i < iovp->iod_iovec_s) - { - if (i >= IOVEC_NR) - { - ec_next_iovec(iovp); - i= 0; - continue; - } - size += iovp->iod_iovec[i].iov_size; - i++; - } - - return size; + memcpy(stat, &ec_state.eth_stat, sizeof(*stat)); } /*===========================================================================* - * ec_next_iovec * + * do_stop * *===========================================================================*/ -static void ec_next_iovec(iovp) -iovec_dat_t *iovp; +static void do_stop(void) { - int r; - - iovp->iod_iovec_s -= IOVEC_NR; - iovp->iod_iovec_offset += IOVEC_NR * sizeof(iovec_s_t); - - r = sys_safecopyfrom(iovp->iod_proc_nr, iovp->iod_grant, - iovp->iod_iovec_offset, - (vir_bytes)iovp->iod_iovec, - (iovp->iod_iovec_s > IOVEC_NR ? - IOVEC_NR : iovp->iod_iovec_s) * - sizeof(iovec_s_t)); - if (r != OK) - panic("ec_next_iovec: sys_safecopyfrom failed: %d", r); -} - - -/*===========================================================================* - * do_getstat_s * - *===========================================================================*/ -static void do_getstat_s(mp) -message *mp; -{ - int r; ether_card_t *ec; - - ec= &ec_state; - - r = sys_safecopyto(mp->m_source, mp->m_net_netdrv_dl_getstat_s.grant, 0, - (vir_bytes)&ec->eth_stat, sizeof(ec->eth_stat)); - - if (r != OK) - panic("do_getstat_s: sys_safecopyto failed: %d", r); - - mp->m_type= DL_STAT_REPLY; - r= ipc_send(mp->m_source, mp); - if (r != OK) - panic("do_getstat_s: send failed: %d", r); -} - -/*===========================================================================* - * lance_stop * - *===========================================================================*/ -static void lance_stop(ec) -ether_card_t *ec; -{ unsigned short ioaddr; - if (!(ec->flags & ECF_ENABLED)) - return; + ec = &ec_state; ioaddr = ec->ec_port; - + /* stop */ write_csr(ioaddr, LANCE_CSR0, LANCE_CSR0_STOP); /* Reset */ in_word(ioaddr+LANCE_RESET); - - ec->flags = ECF_EMPTY; } /*===========================================================================* - * getAddressing * + * get_addressing * *===========================================================================*/ -static void getAddressing(devind, ec) -int devind; -ether_card_t *ec; +static void get_addressing(int devind, ether_card_t *ec) { - unsigned int membase, ioaddr; + unsigned int ioaddr; int reg, irq; for (reg = PCI_BAR; reg <= PCI_BAR_6; reg += 4) @@ -1363,25 +721,20 @@ ether_card_t *ec; continue; /* Strip the I/O address out of the returned value */ ioaddr &= PCI_BAR_IO_MASK; - /* Get the memory base address */ - membase = pci_attr_r32(devind, PCI_BAR_2); - /* KK: Get the IRQ number */ - irq = pci_attr_r8(devind, PCI_IPR); - if (irq) - irq = pci_attr_r8(devind, PCI_ILR); - - ec->ec_linmem = membase; ec->ec_port = ioaddr; - ec->ec_irq = irq; } + + /* KK: Get the IRQ number */ + irq = pci_attr_r8(devind, PCI_IPR); + if (irq) + irq = pci_attr_r8(devind, PCI_ILR); + ec->ec_irq = irq; } /*===========================================================================* * lance_probe * *===========================================================================*/ -static int lance_probe(ec, skip) -ether_card_t *ec; -int skip; +static int lance_probe(ether_card_t *ec, unsigned int skip) { unsigned short pci_cmd; unsigned short ioaddr; @@ -1389,6 +742,8 @@ int skip; int devind, r; u16_t vid, did; + pci_init(); + r= pci_first_dev(&devind, &vid, &did); if (r == 0) return 0; @@ -1402,8 +757,7 @@ int skip; pci_reserve(devind); - getAddressing(devind, ec); - + get_addressing(devind, ec); /* ===== Bus Master ? ===== */ pci_cmd = pci_attr_r32(devind, PCI_CR); @@ -1420,7 +774,7 @@ int skip; if (read_csr(ioaddr, LANCE_CSR0) != LANCE_CSR0_STOP) { - ec->mode=EC_DISABLED; + return 0; } /* Probe Chip Version */ @@ -1434,7 +788,7 @@ int skip; if ((chip_version & 0xfff) != 0x3) { - ec->mode=EC_DISABLED; + return 0; } chip_version = (chip_version >> 12) & 0xffff; for (lance_version = 1; chip_table[lance_version].id_number != 0; @@ -1453,18 +807,38 @@ int skip; } /*===========================================================================* - * lance_init_card * + * virt_to_bus * *===========================================================================*/ -static void lance_init_card(ec) -ether_card_t *ec; +static phys_bytes virt_to_bus(void *ptr) { - int i; - Address l = (vir_bytes)lance_buf; + phys_bytes value; + int r; + + if ((r = sys_umap(SELF, VM_D, (vir_bytes)ptr, 4, &value)) != OK) + panic("sys_umap failed: %d", r); + + return value; +} + +/*===========================================================================* + * lance_init_hw * + *===========================================================================*/ +static void lance_init_hw(ether_card_t *ec, ether_addr_t *addr) +{ + phys_bytes lance_buf_phys; + int i, r; + Address l; unsigned short ioaddr = ec->ec_port; /* ============= setup init_block(cf. lance_probe1) ================ */ /* make sure data structure is 8-byte aligned and below 16MB (for DMA) */ + /* Allocate memory */ + if ((lance_buf = alloc_contig(LANCE_BUF_SIZE, AC_ALIGN4K|AC_LOWER16M, + &lance_buf_phys)) == NULL) + panic("alloc_contig failed: %d", LANCE_BUF_SIZE); + + l = (vir_bytes)lance_buf; lp = (struct lance_interface *)l; /* disable Tx and Rx */ @@ -1485,7 +859,10 @@ ether_card_t *ec; /* ============= Get MAC address (cf. lance_probe1) ================ */ for (i = 0; i < 6; ++i) - ec->mac_address.ea_addr[i]=in_byte(ioaddr+LANCE_ETH_ADDR+i); + addr->ea_addr[i]=in_byte(ioaddr+LANCE_ETH_ADDR+i); + + /* Allow the user to override the hardware address. */ + ec_confaddr(addr); /* ============ (re)start init_block(cf. lance_reset) =============== */ /* Reset the LANCE */ @@ -1494,7 +871,7 @@ ether_card_t *ec; /* ----- Re-initialize the LANCE ----- */ /* Set station address */ for (i = 0; i < 6; ++i) - lp->init_block.phys_addr[i] = ec->mac_address.ea_addr[i]; + lp->init_block.phys_addr[i] = addr->ea_addr[i]; /* Preset the receive ring headers */ for (i=0; itx_ring[i].u.base = 0; + tx_ring_base[i] = virt_to_bus(lp->tbuf[i]) & 0xffffff; isstored[i] = 0; } /* enable Rx and Tx */ @@ -1553,11 +931,16 @@ ether_card_t *ec; } } + /* Set the interrupt handler */ + ec->ec_hook = ec->ec_irq; + if ((r=sys_irqsetpolicy(ec->ec_irq, 0, &ec->ec_hook)) != OK) + panic("couldn't set IRQ policy: %d", r); + if ((r = sys_irqenable(&ec->ec_hook)) != OK) + panic("couldn't enable interrupt: %d", r); + /* start && enable interrupt */ write_csr(ioaddr, LANCE_CSR0, LANCE_CSR0_IDON|LANCE_CSR0_IENA|LANCE_CSR0_STRT); - - return; } /*===========================================================================* diff --git a/minix/drivers/net/lance/lance.h b/minix/drivers/net/lance/lance.h index 6b79a35a7..5a1b3e5dc 100644 --- a/minix/drivers/net/lance/lance.h +++ b/minix/drivers/net/lance/lance.h @@ -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. diff --git a/minix/drivers/net/orinoco/Makefile b/minix/drivers/net/orinoco/Makefile index 172e7d319..a71e040a0 100644 --- a/minix/drivers/net/orinoco/Makefile +++ b/minix/drivers/net/orinoco/Makefile @@ -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 diff --git a/minix/drivers/net/orinoco/orinoco.c b/minix/drivers/net/orinoco/orinoco.c index b6632f080..fd71ffa2a 100644 --- a/minix/drivers/net/orinoco/orinoco.c +++ b/minix/drivers/net/orinoco/orinoco.c @@ -2,52 +2,26 @@ * orinoco.c * * This file contains a wireless device driver for Prism based wireless - * cards. + * cards. * - * Created by Stevens Le Blond + * Created by Stevens Le Blond * and Michael Valkering * */ #include #include -#include -#include -#include -#include -#include #include #include -#include -#include -#include "kernel/const.h" -#include "kernel/config.h" -#include "kernel/type.h" +#include #define VERBOSE 1 /* display message during init */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - #include "assert.h" #include "hermes.h" #include "hermes_rid.h" #include "orinoco.h" -#define ERR -1 - -#define debug 0 - #define OR_M_ENABLED 1 #define OR_M_DISABLED 0 #define OR_F_EMPTY 0 @@ -71,7 +45,6 @@ #define ETH_HLEN 14 static t_or or_state; -static int or_instance; struct ethhdr { u8_t h_dest[ETH_ALEN]; @@ -110,7 +83,7 @@ static const long channel_frequency[] = { #define NUM_CHANNELS (sizeof(channel_frequency) / sizeof(channel_frequency[0])) -/* This tables gives the actual meanings of the bitrate IDs returned by the +/* This tables gives the actual meanings of the bitrate IDs returned by the * firmware. Not used yet */ struct { int bitrate; /* in 100s of kilobits */ @@ -129,46 +102,39 @@ struct { #define BITRATE_TABLE_SIZE (sizeof(bitrate_table) / sizeof(bitrate_table[0])) - -static void or_writev_s(message * mp, int from_int); -static void or_readv_s(message * mp, int from_int); -static void reply(t_or * orp); -static int or_probe(t_or *, int skip); +static void or_other(const message *m_ptr, int ipc_status); +static void or_stop(void); +static int or_probe(t_or *, unsigned int skip); static void or_ev_info(t_or *); -static void or_init(message *); -static void or_pci_conf(void); -static void or_init_struct(t_or *); -static void map_hw_buffer(t_or *); -static void or_init_hw(t_or *); +static int or_init(unsigned int instance, ether_addr_t *addr); +static void or_init_struct(t_or *, unsigned int); +static void or_init_hw(t_or *, ether_addr_t *); static void or_check_ints(t_or *); static void or_writerids(hermes_t *, t_or *); -static void or_readrids(hermes_t *, t_or *); -static void or_rec_mode(t_or *); -static void mess_reply(message *, message *); +static void or_readrids(hermes_t *, t_or *, ether_addr_t *); static u32_t or_get_bar(int devind, t_or * orp); -static void or_getstat_s(message * mp); +static void or_stat(eth_stat_t *stat); static void print_linkstatus(t_or * orp, u16_t status); +static ssize_t or_recv(struct netdriver_data *data, size_t max); static int or_get_recvd_packet(t_or *orp, u16_t rxfid, u8_t *databuf); static void or_reset(void); -static void or_watchdog_f(minix_timer_t *tp); +static void or_alarm(clock_t stamp); +static int or_send(struct netdriver_data *data, size_t size); static void setup_wepkey(t_or *orp, char *wepkey0); -static void do_hard_int(void); -static void check_int_events(void); +static void or_intr(unsigned int mask); static void or_handler(t_or *orp); -static void or_dump(message *m); +static void or_dump(void); -/* The message used in the main loop is made global, so that rl_watchdog_f() - * can change its message type to fake an interrupt message. - */ -static message m; -static int int_event_check; /* set to TRUE if events arrived */ - -static u32_t system_hz; - -/* 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); +static const struct netdriver or_table = { + .ndr_init = or_init, + .ndr_stop = or_stop, + .ndr_recv = or_recv, + .ndr_send = or_send, + .ndr_stat = or_stat, + .ndr_intr = or_intr, + .ndr_alarm = or_alarm, + .ndr_other = or_other +}; /***************************************************************************** * main * @@ -176,164 +142,62 @@ static void sef_cb_signal_handler(int signo); * * * The main function of the driver, receiving and processing messages * *****************************************************************************/ -int main(int argc, char *argv[]) { - int r; - int ipc_status; - - /* SEF local startup. */ +int main(int argc, char *argv[]) +{ env_setargs(argc, argv); - sef_local_startup(); - while (TRUE) { - if ((r = netdriver_receive (ANY, &m, &ipc_status)) != OK) - panic("orinoco: netdriver_receive failed"); + netdriver_task(&or_table); - if (is_ipc_notify(ipc_status)) { - switch (_ENDPOINT_P(m.m_source)) { - case CLOCK: - or_watchdog_f(NULL); - break; - case HARDWARE: - do_hard_int(); - if (int_event_check) - check_int_events(); - break ; - case TTY_PROC_NR: - or_dump(&m); - break; - default: - panic("orinoco: illegal notify from: %d", - m.m_source); - } - - /* done, get new message */ - continue; - } - - switch (m.m_type) { - case DL_WRITEV_S: - or_writev_s (&m, FALSE); - break; - case DL_READV_S: - or_readv_s (&m, FALSE); - break; - case DL_CONF: - or_init (&m); - break; - case DL_GETSTAT_S: - or_getstat_s (&m); - break; - default: - panic("orinoco: illegal message: %d", m.m_type); - } - } -} - -/*===========================================================================* - * 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 *info) -{ -/* Initialize the orinoco driver. */ - long v; - int fkeys, sfkeys, r; - - system_hz = sys_hz(); - - v = 0; - (void) env_parse("instance", "d", 0, &v, 0, 255); - or_instance = (int) v; - - /* Observe some function key for debug dumps. */ - fkeys = sfkeys = 0; bit_set(sfkeys, 11); - if ((r=fkey_map(&fkeys, &sfkeys)) != OK) - printf("Warning: orinoco couldn't observe F-key(s): %d\n",r); - - /* Announce we are up! */ - netdriver_announce(); - - return(OK); -} - -/*===========================================================================* - * sef_cb_signal_handler * - *===========================================================================*/ -static void sef_cb_signal_handler(int signo) -{ - t_or *orp; - - /* Only check for termination signal, ignore anything else. */ - if (signo != SIGTERM) return; - - orp = &or_state; - - if (orp->or_mode == OR_M_ENABLED) { - /* TODO: send a signal to the card to shut it down */ - } - exit(0); + return 0; } /***************************************************************************** - * check_int_events * + * or_other * * * - * If a hard interrupt message came in, call the or_check_ints for the right * - * card * + * * + * Process miscellaneous messages * *****************************************************************************/ -static void check_int_events(void) { - t_or *orp; - - /* the interrupt message doesn't contain information about the port, try - * to find it */ - orp = &or_state; - - if (orp->or_mode != OR_M_ENABLED) - return; - if (!orp->or_got_int) - return; - orp->or_got_int = 0; - assert (orp->or_flags & OR_F_ENABLED); - or_check_ints (orp); - +static void or_other(const message *m_ptr, int ipc_status) +{ + if (is_ipc_notify(ipc_status) && m_ptr->m_source == TTY_PROC_NR) + or_dump(); } /***************************************************************************** - * do_hard_int * + * or_stop * + * * + * Stop the card * + *****************************************************************************/ +static void or_stop(void) +{ + t_or *orp; + + orp = &or_state; + + /* TODO: send a signal to the card to shut it down */ +} + +/***************************************************************************** + * or_intr * * * * Process the interrupts which the card generated * *****************************************************************************/ -static void do_hard_int(void) +static void or_intr(unsigned int __unused mask) { + t_or *orp; int s; + orp = &or_state; + /* Run interrupt handler at driver level. */ - or_handler(&or_state); + or_handler(orp); /* Reenable interrupts for this hook. */ - if ((s=sys_irqenable(&or_state.or_hook_id)) != OK) { - printf("orinoco: error, couldn't enable"); - printf(" interrupts: %d\n", s); - } + if ((s=sys_irqenable(&orp->or_hook_id)) != OK) + printf("orinoco: error, couldn't enable interrupts: %d\n", s); + + /* Perform tasks based on the flagged conditions. */ + or_check_ints(orp); } /***************************************************************************** @@ -342,42 +206,36 @@ static void do_hard_int(void) * Sometime the card gets screwed, behaving erratically. Solution: reset the * * card. This is actually largely redoing the initialization * *****************************************************************************/ -static void or_reset() { - static clock_t last_reset, now; +static void or_reset(void) +{ + static clock_t last_reset, now; t_or *orp; int i, r; if (OK != (r = getticks(&now))) panic("orinoco: getuptime() failed: %d", r); - if(now - last_reset < system_hz * 10) { + if(now - last_reset < sys_hz() * 10) { printf("Resetting card too often. Going to reset driver\n"); exit(1); } last_reset = now; - + orp = &or_state; - if(orp->or_mode == OR_M_DISABLED) - printf("orinoco instance %d is disabled\n", or_instance); - - if(orp->or_mode != OR_M_ENABLED) { - return; - } - - orp->or_need_reset = 0; - or_init_hw(orp); + orp->or_need_reset = FALSE; + or_init_hw(orp, NULL); orp->rx_last = orp->rx_first = 0; for(i = 0; i < NR_RX_BUFS; i++) { orp->rx_length[0] = 0; } - if(orp->or_flags & OR_F_SEND_AVAIL) { - orp->or_tx.ret_busy = FALSE; - orp->or_send_int = TRUE; - } + if (orp->or_tx.ret_busy) + orp->or_tx_busy--; + orp->or_tx.ret_busy = FALSE; + orp->or_send_int = TRUE; } /***************************************************************************** @@ -386,24 +244,17 @@ static void or_reset() { * Dump interesting information about the card on F-key pressed. * * Not implemented yet * *****************************************************************************/ -static void or_dump (message *m) - { +static void or_dump(void) +{ t_or *orp; int sfkeys; orp = &or_state; - if(orp->or_mode == OR_M_DISABLED) { - printf("%s is disabled\n", orp->or_name); - } - - if(orp->or_mode != OR_M_ENABLED) - return; - if(OK != fkey_events(NULL, &sfkeys)) { printf("Contacting the TTY failed\n"); } - + if(bit_isset(sfkeys, 11)) { print_linkstatus(orp, orp->last_linkstatus); } @@ -412,88 +263,34 @@ static void or_dump (message *m) /***************************************************************************** * or_init * * * - * The main initialization function, called when a DL_INIT message comes in. * + * The main initialization function, called at startup. * *****************************************************************************/ -static void or_init (message * mp) { +static int or_init(unsigned int instance, ether_addr_t *addr) +{ + int fkeys, sfkeys, r; t_or *orp; - message reply; - static int first_time = 1; - - if (first_time) { - first_time = 0; - or_pci_conf (); /* Configure PCI devices. */ - - /* Use a synchronous alarm instead of a watchdog timer. */ - sys_setalarm(system_hz, 0); - } orp = &or_state; - if (orp->or_mode == OR_M_DISABLED) { - /* Initialize the orp structure */ - or_init_struct (orp); - if (orp->or_mode == OR_M_DISABLED) { - reply.m_type = DL_CONF_REPLY; - reply.m_netdrv_net_dl_conf.stat = ENXIO; - mess_reply (mp, &reply); - return; - } - if (orp->or_mode == OR_M_ENABLED) { - /* initialize card, hardware/firmware */ - orp->or_flags |= OR_F_ENABLED; - or_init_hw (orp); - } - } + /* Initialize the orp structure */ + or_init_struct(orp, instance); - assert (orp->or_mode == OR_M_ENABLED); - assert (orp->or_flags & OR_F_ENABLED); - - /* Not supported by the driver yet, but set a couple of options: - * multicasting, promiscuity, broadcasting, depending on the users - * needs */ - orp->or_flags &= ~(OR_F_PROMISC | OR_F_MULTI | OR_F_BROAD); - if (mp->m_net_netdrv_dl_conf.mode & DL_PROMISC_REQ) - orp->or_flags |= OR_F_PROMISC; - if (mp->m_net_netdrv_dl_conf.mode & DL_MULTI_REQ) - orp->or_flags |= OR_F_MULTI; - if (mp->m_net_netdrv_dl_conf.mode & DL_BROAD_REQ) - orp->or_flags |= OR_F_BROAD; - - or_rec_mode (orp); - - /* reply the caller that the configuration succeeded */ - reply.m_type = DL_CONF_REPLY; - reply.m_netdrv_net_dl_conf.stat = OK; - memcpy(reply.m_netdrv_net_dl_conf.hw_addr, orp->or_address.ea_addr, - sizeof(reply.m_netdrv_net_dl_conf.hw_addr)); - mess_reply (mp, &reply); -} - -/***************************************************************************** - * or_pci_conf * - * * - * Configure the pci related issues of the card, e.g. finding out where the * - * card is in the pci configuration, it's assigned irq, etc. This can be * - * done if the boot monitor is provided with information, or the pci bus * - * can be searched (at the end: or_probe function) * - *****************************************************************************/ -static void or_pci_conf () { - t_or *orp; - - /* extract information from the boot monitor about the pci - * configuration if provided */ - orp = &or_state; - - strncpy (orp->or_name, OR_NAME, sizeof(OR_NAME)); - orp->or_name[sizeof(OR_NAME) - 2] = or_instance + '0'; - orp->or_seen = FALSE; - - /* Initialize the pci bus, bridges and cards, if not yet done */ - pci_init (); - /* Try to find out where the card is in the pci bus */ - if (or_probe (orp, or_instance)) - orp->or_seen = TRUE; + if (!or_probe(orp, instance)) + return ENXIO; + + /* initialize card, hardware/firmware */ + or_init_hw(orp, addr); + + /* Use a synchronous alarm instead of a watchdog timer. */ + sys_setalarm(sys_hz(), 0); + + /* Observe some function key for debug dumps. */ + fkeys = sfkeys = 0; bit_set(sfkeys, 11); + if ((r=fkey_map(&fkeys, &sfkeys)) != OK) + printf("Warning: orinoco couldn't observe F-key(s): %d\n",r); + + return OK; } /***************************************************************************** @@ -502,7 +299,7 @@ static void or_pci_conf () { * Try to find the card based on information provided by pci and get irq and * * bar * *****************************************************************************/ -static int or_probe (t_or * orp, int skip) +static int or_probe(t_or * orp, unsigned int skip) { u8_t ilr; u32_t bar; @@ -510,88 +307,51 @@ static int or_probe (t_or * orp, int skip) u16_t vid, did; int r, devind; + pci_init(); + /* Start looking from the beginning */ - r = pci_first_dev (&devind, &vid, &did); + r = pci_first_dev(&devind, &vid, &did); if (r == 0) - return (0); + return FALSE; /* Skip as many instances as requested */ while (skip--) { - r = pci_next_dev (&devind, &vid, &did); + r = pci_next_dev(&devind, &vid, &did); if (!r) - return (0); + return FALSE; } /* Get the name as advertised by pci */ - dname = pci_dev_name (vid, did); + dname = pci_dev_name(vid, did); if (!dname) dname = "unknown device"; - printf ("%s: %s (%04x/%04x) at %s\n", - orp->or_name, dname, vid, did, pci_slot_name (devind)); + printf("%s: %s (%04x/%04x) at %s\n", + orp->or_name, dname, vid, did, pci_slot_name(devind)); - pci_reserve (devind); + pci_reserve(devind); - orp->devind = devind; /* Get the irq */ - ilr = pci_attr_r8 (devind, PCI_ILR); + ilr = pci_attr_r8(devind, PCI_ILR); orp->or_irq = ilr; - /* Get the base address */ - bar = or_get_bar (devind, orp); - orp->or_base_port = bar; + /* Map registers into memory */ + bar = or_get_bar(devind, orp); + + orp->hw.locmem = vm_map_phys(SELF, (void *)bar, PAGE_SIZE); + if (orp->hw.locmem == MAP_FAILED) + panic("or_probe: vm_map_phys failed"); - map_hw_buffer(orp); return TRUE; } -/***************************************************************************** - * map_hw_buffer * - * * - * Map the memory mapped registers into user space memory * - *****************************************************************************/ -static void map_hw_buffer(t_or *orp) -{ - int r; - size_t o, size; - char *buf, *abuf; - hermes_t *hw = &(orp->hw); - - /* This way, the buffer will be at least PAGE_SIZE big: see - * calculation with the offset */ - size = 2 * PAGE_SIZE; - - buf = (char *)malloc(size); - if(buf == NULL) - panic("map_hw_buffer: cannot malloc size: %d", size); - - /* Let the mapped memory by PAGE_SIZE aligned */ - o = PAGE_SIZE - ((vir_bytes)buf % PAGE_SIZE); - abuf = buf + o; - -#if 0 - r = sys_vm_map(SELF, 1, (vir_bytes)abuf, - 1 * PAGE_SIZE, (phys_bytes)orp->or_base_port); -#else - r = ENOSYS; -#endif - - if(r!=OK) - panic("map_hw_buffer: sys_vm_map failed: %d", r); - - - hw->locmem = abuf; -} - - - /***************************************************************************** * or_get_bar * * * - * Get the base address from pci (from Base Address Register) and find out * + * Get the base address from pci (from Base Address Register) and find out * * whether the card is memory mapped or in I/O space. Currently, only * * memmory mapped is supported. * *****************************************************************************/ -static u32_t or_get_bar (int devind, t_or * orp) +static u32_t or_get_bar(int devind, t_or * orp) { u32_t bar; int is_iospace; @@ -599,11 +359,11 @@ static u32_t or_get_bar (int devind, t_or * orp) /* bit 1 off the PCI_BAR register indicates whether the cards registers * are mapped in io-space or shared memory */ - is_iospace = pci_attr_r32 (devind, PCI_BAR) & 1; + is_iospace = pci_attr_r32(devind, PCI_BAR) & 1; if (is_iospace) { /* read where the base address is in I/O space */ - bar = pci_attr_r32 (devind, PCI_BAR) & 0xffffffe0; + bar = pci_attr_r32(devind, PCI_BAR) & 0xffffffe0; if ((bar & 0x3ff) >= 0x100 - 32 || bar < 0x400) panic("base address isn't properly configured"); @@ -613,33 +373,32 @@ static u32_t or_get_bar (int devind, t_or * orp) hermes_struct_init (hw, bar, is_iospace, HERMES_16BIT_REGSPACING); - if (debug) { - printf ("%s: using I/O space address 0x%x, IRQ %d\n", - orp->or_name, bar, orp->or_irq); - } +#if VERBOSE + printf ("%s: using I/O space address 0x%x, IRQ %d\n", + orp->or_name, bar, orp->or_irq); +#endif panic("Not implemented yet"); - /* Although we are able to find the desired bar and irq for an - * I/O spaced card, we haven't implemented the right register + /* Although we are able to find the desired bar and irq for an + * I/O spaced card, we haven't implemented the right register * accessing functions. This wouldn't be difficult, but we were * not able to test them. Therefore, give an alert here */ return bar; } else { /* read where the base address is in shared memory */ - bar = pci_attr_r32 (devind, PCI_BAR) & 0xfffffff0; + bar = pci_attr_r32(devind, PCI_BAR) & 0xfffffff0; /* maybe some checking whether the address is legal... */ - /* Memory mapped registers are 2 bytes wide, aligned on 4 + /* Memory mapped registers are 2 bytes wide, aligned on 4 * bytes */ hermes_struct_init (hw, bar, is_iospace, HERMES_32BIT_REGSPACING); - if (debug){ - printf ("%s: using shared memory address", - orp->or_name); - printf (" 0x%x, IRQ %d\n", bar, orp->or_irq); - } +#if VERBOSE + printf ("%s: using shared memory address", orp->or_name); + printf (" 0x%x, IRQ %d\n", bar, orp->or_irq); +#endif return bar; @@ -651,62 +410,44 @@ static u32_t or_get_bar (int devind, t_or * orp) * * * Set the orinoco structure to default values * *****************************************************************************/ -static void or_init_struct (t_or * orp) +static void or_init_struct(t_or * orp, unsigned int instance) { - int i = 0; - static eth_stat_t empty_stat = { 0, 0, 0, 0, 0, 0 }; + int i; - orp->or_mode = OR_M_DISABLED; + memset(orp, 0, sizeof(*orp)); - if (orp->or_seen) - orp->or_mode = OR_M_ENABLED; + strlcpy(orp->or_name, OR_NAME, sizeof(orp->or_name)); + orp->or_name[sizeof(OR_NAME) - 2] = instance + '0'; - if (orp->or_mode != OR_M_ENABLED) - return; - - orp->or_got_int = 0; orp->or_link_up = -1; - orp->or_send_int = 0; - orp->or_clear_rx = 0; - orp->or_tx_alive = 0; - orp->or_need_reset = 0; - orp->or_read_s = 0; - orp->or_tx_head = 0; - orp->or_tx_tail = 0; - orp->connected = 0; - - orp->or_tx.ret_busy = FALSE; orp->or_tx.or_txfid = NO_FID; for(i = 0; i < NR_RX_BUFS; i++) { orp->rxfid[i] = NO_FID; orp->rx_length[i] = 0; } - orp->rx_current = 0; - orp->rx_first = 0; - orp->rx_last = 0; - - orp->or_stat = empty_stat; - orp->or_flags = OR_F_EMPTY; /* Keep an administration in the driver whether the internal buffer is in use. That's what ret_busy is for */ orp->or_tx.ret_busy = FALSE; + orp->or_tx_busy = 0; orp->or_nicbuf_size = IEEE802_11_FRAME_LEN + ETH_HLEN; - } /***************************************************************************** * or_init_hw * * * * Initialize hardware and prepare for intercepting the interrupts. At the * - * end, the card is up and running * + * end, the card is up and running. May be called multiple times. * *****************************************************************************/ -static void or_init_hw (t_or * orp) +static void or_init_hw(t_or * orp, ether_addr_t * addr) { - int i, err, s; +#if VERBOSE + int i; +#endif + int err, s; hermes_t *hw = &(orp->hw); static int first_time = TRUE; @@ -720,19 +461,19 @@ static void or_init_hw (t_or * orp) printf ("error value of hermes_init(): %d\n", err); } - /* Get the MAC address (which is a data item in the card)*/ - or_readrids (hw, orp); + if (first_time) { + /* Get the MAC address (which is a data item in the card)*/ + or_readrids(hw, orp, addr); + } /* Write a few rids to the card, e.g. WEP key*/ or_writerids (hw, orp); - if (debug) { - printf ("%s: Ethernet address ", orp->or_name); - for (i = 0; i < 6; i++) { - printf ("%x%c", orp->or_address.ea_addr[i], - i < 5 ? ':' : '\n'); - } - } +#if VERBOSE + printf ("%s: Ethernet address ", orp->or_name); + for (i = 0; i < 6; i++) + printf("%x%c", addr->ea_addr[i], i < 5 ? ':' : '\n'); +#endif /* Prepare internal TX buffer in the card */ err = hermes_allocate (hw, @@ -745,8 +486,8 @@ static void or_init_hw (t_or * orp) /* Establish event handle */ if(first_time) { - orp->or_hook_id = orp->or_irq; - if ((s=sys_irqsetpolicy(orp->or_irq, 0, + orp->or_hook_id = orp->or_irq; + if ((s=sys_irqsetpolicy(orp->or_irq, 0, &orp->or_hook_id)) != OK) printf("orinoco: couldn't set IRQ policy: %d\n", s); @@ -760,12 +501,10 @@ static void or_init_hw (t_or * orp) /* Enable operation */ err = hermes_docmd_wait (hw, HERMES_CMD_ENABLE, 0, NULL); - if (err) { - printf ("%s: Error %d enabling MAC port\n", orp->or_name, err); - } + if (err) + printf("%s: Error %d enabling MAC port\n", orp->or_name, err); } - /***************************************************************************** * or_readrids * * * @@ -773,17 +512,17 @@ static void or_init_hw (t_or * orp) * is a data item in the firmware, some configuration variable. * * In our case, we are mostly interested in the MAC address for now * *****************************************************************************/ - -static void or_readrids (hermes_t * hw, t_or * orp) +static void or_readrids(hermes_t * hw, t_or * orp, ether_addr_t * addr) { - /* Read the MAC address */ - int err = hermes_read_ltv (hw, USER_BAP, HERMES_RID_CNFOWNMACADDR, - ETH_ALEN, NULL, &orp->or_address); - if (err) { - printf ("%s: failed to read MAC address!\n", orp->or_name); - return; - } + int err; + assert(addr != NULL); + + /* Read the MAC address */ + err = hermes_read_ltv (hw, USER_BAP, HERMES_RID_CNFOWNMACADDR, + ETH_ALEN, NULL, addr); + if (err) + printf("%s: failed to read MAC address!\n", orp->or_name); } /***************************************************************************** @@ -792,18 +531,15 @@ static void or_readrids (hermes_t * hw, t_or * orp) * Write some default rids to the card. A rid (resource identifier) * * is a data item in the firmware, some configuration variable, e.g. WEP key * *****************************************************************************/ -static void or_writerids (hermes_t * hw, t_or * orp) +static void or_writerids(hermes_t * hw, t_or * orp) { int err; struct hermes_idstring idbuf; - u16_t port_type; static char essid[IW_ESSID_MAX_SIZE + 1]; static char wepkey0[LARGE_KEY_LENGTH + 1]; /* Set the MAC port */ - port_type = 1; - err = hermes_write_wordrec (hw, USER_BAP, HERMES_RID_CNFPORTTYPE, - port_type); + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFPORTTYPE, 1); if (err) { printf ("%s: Error %d setting port type\n", orp->or_name, err); return; @@ -827,7 +563,7 @@ static void or_writerids (hermes_t * hw, t_or * orp) HERMES_BYTES_TO_RECLEN (strlen (essid) + 2), &idbuf); if (err) { - printf ("%s: Error %d setting DESIREDSSID\n", + printf ("%s: Error %d setting DESIREDSSID\n", orp->or_name, err); return; } @@ -858,7 +594,8 @@ static void or_writerids (hermes_t * hw, t_or * orp) * It appears that there is a severe bug in setting up WEP. If the driver * * doesnt function properly, please turn WEP off. * *****************************************************************************/ -static void setup_wepkey(t_or *orp, char *wepkey0) { +static void setup_wepkey(t_or *orp, char *wepkey0) +{ int default_key = 0, err = 0; hermes_t *hw = &(orp->hw); @@ -867,40 +604,30 @@ static void setup_wepkey(t_or *orp, char *wepkey0) { default_key); if (err) printf ("%s: Error %d setting the default WEP-key entry\n", - orp->or_name, err); - - err = hermes_write_ltv (hw, USER_BAP, + orp->or_name, err); + + err = hermes_write_ltv (hw, USER_BAP, HERMES_RID_CNFDEFAULTKEY0, HERMES_BYTES_TO_RECLEN(LARGE_KEY_LENGTH), wepkey0); - if (err) + if (err) printf ("%s: Error %d setting the WEP-key0\n", - orp->or_name, err); - - err = hermes_write_wordrec (hw, USER_BAP, + orp->or_name, err); + + err = hermes_write_wordrec (hw, USER_BAP, HERMES_RID_CNFAUTHENTICATION, HERMES_AUTH_OPEN); if (err) printf ("%s: Error %d setting the authentication flag\n", - orp->or_name, err); + orp->or_name, err); - err = hermes_write_wordrec (hw, USER_BAP, + err = hermes_write_wordrec (hw, USER_BAP, HERMES_RID_CNFWEPFLAGS_INTERSIL, HERMES_WEP_PRIVACY_INVOKED); if (err) printf ("%s: Error %d setting the master wep setting flag\n", - orp->or_name, err); - -} + orp->or_name, err); - -/***************************************************************************** - * or_rec_mode * - * * - * Set the desired receive mode, e.g. promiscuous mode. Not implemented yet * - *****************************************************************************/ -static void or_rec_mode (t_or * orp) { - /* TODO */ } /***************************************************************************** @@ -910,12 +637,12 @@ static void or_rec_mode (t_or * orp) { * like EV_INFO and EV_RX have to be handled before an acknowledgement for * * the event is returned to the card. See also the documentation * *****************************************************************************/ -static void or_handler (t_or *orp) +static void or_handler(t_or *orp) { int length; u16_t evstat, events, fid; hermes_t *hw = &(orp->hw); - + beginning: /* Retrieve which kind of event happened */ evstat = hermes_read_reg (hw, HERMES_EVSTAT); @@ -940,8 +667,8 @@ beginning: if (events & HERMES_EV_INFDROP) { events &= ~(HERMES_EV_INFDROP); } - - /* This AP-only event will be asserted at the beacon interval prior to + + /* This AP-only event will be asserted at the beacon interval prior to the DTIM interval */ if (events & HERMES_EV_DTIM) { events &= ~(HERMES_EV_DTIM); @@ -955,7 +682,6 @@ beginning: /* Occurs when the asynchronous transmission process is unsuccessfully completed */ if (events & HERMES_EV_TXEXC) { - /* What buffer generated the event? Represented by an fid */ fid = hermes_read_reg(hw, HERMES_TXCOMPLFID); if(fid == 0xFFFF) { @@ -963,20 +689,17 @@ beginning: printf("unexpected txexc_fid interrupted\n"); } + if (orp->or_tx.ret_busy) + orp->or_tx_busy--; orp->or_tx.ret_busy = FALSE; - if(orp->or_flags & OR_F_SEND_AVAIL) { - orp->or_send_int = TRUE; - if (!orp->or_got_int){ - orp->or_got_int = TRUE; - int_event_check = TRUE; - } - } + orp->or_send_int = TRUE; + orp->or_got_int = TRUE; /* To detect illegal fids */ hermes_write_reg(hw, HERMES_TXCOMPLFID, 0xFFFF); events &= ~(HERMES_EV_TXEXC); - /* We don't do anything else yet. + /* We don't do anything else yet. * Could be used for statistics */ } @@ -991,15 +714,13 @@ beginning: printf("unexpected tx_fid interrupted\n"); } + if (orp->or_tx.ret_busy) + orp->or_tx_busy--; orp->or_tx.ret_busy = FALSE; - if(orp->or_flags & OR_F_SEND_AVAIL) { - orp->or_send_int = TRUE; - if (!orp->or_got_int){ - orp->or_got_int = TRUE; - int_event_check = TRUE; - } - } + orp->or_send_int = TRUE; + orp->or_got_int = TRUE; + orp->or_tx_alive = TRUE; /* To detect illegal fids */ hermes_write_reg(hw, HERMES_TXCOMPLFID, 0xFFFF); @@ -1020,37 +741,35 @@ beginning: if (fid == 0xFFFF){ /* An illegal frame identifier is found. Ignore */ printf("Allocate event on unexpected fid\n"); - return ; + goto next; } /* To be able to detect illegal fids */ hermes_write_reg(hw, HERMES_ALLOCFID, 0xFFFF); - + events &= ~(HERMES_EV_ALLOC); } - - /* Occurs when a frame is received by the asynchronous reception - * process */ - + /* Occurs when a frame is received */ if (events & HERMES_EV_RX) { - orp->or_ev_rx = TRUE; events &= ~(HERMES_EV_RX); - /* If the last buffer is still filled with data, then we don't + /* If the last buffer is still filled with data, then we don't * have any buffers available to store the data */ if(orp->rx_length[orp->rx_last] != 0) { /* indeed, we are going to overwrite information - * in a buffer */ + * in a buffer + */ } /* Which buffer is storing the data (represented by a fid) */ orp->rxfid[orp->rx_last] = hermes_read_reg (hw, HERMES_RXFID); - /* Get the packet from the card and store it in - * orp->rx_buf[orp->rx_last]. The length is returned by this - * function */ + /* Get the packet from the card and store it in + * orp->rx_buf[orp->rx_last]. The length is returned by this + * function + */ length = or_get_recvd_packet(orp, orp->rxfid[orp->rx_last], (orp->rx_buf[orp->rx_last])); @@ -1066,17 +785,14 @@ beginning: orp->rx_last++; orp->rx_last %= NR_RX_BUFS; - if (!orp->or_got_int){ - orp->or_got_int = TRUE; - } - int_event_check = TRUE; + orp->or_got_int = TRUE; } next: - if (events) { + if (events) { printf("Unknown event: 0x%x\n", events); } - /* Acknowledge to the card that the events have been processed. After + /* Acknowledge to the card that the events have been processed. After * this the card will assume we have processed any buffer which were in * use for this event. */ hermes_write_reg (hw, HERMES_EVACK, evstat); @@ -1087,26 +803,22 @@ next: } } - /***************************************************************************** - * or_watchdog_f * + * or_alarm * * * * Will be called regularly to see whether the driver has crashed. If that * * condition is detected, reset the driver and card * *****************************************************************************/ -static void or_watchdog_f(minix_timer_t *tp) +static void or_alarm(clock_t __unused stamp) { t_or *orp; - + /* Use a synchronous alarm instead of a watchdog timer. */ - sys_setalarm(system_hz, 0); + sys_setalarm(sys_hz(), 0); orp = &or_state; - if (orp->or_mode != OR_M_ENABLED) - return; - - if (!(orp->or_flags & OR_F_SEND_AVAIL)) { + if (orp->or_tx_busy == 0) { /* Assume that an idle system is alive */ orp->or_tx_alive= TRUE; return; @@ -1120,39 +832,28 @@ static void or_watchdog_f(minix_timer_t *tp) orp->or_tx_alive= FALSE; return; } - - printf("or_watchdog_f: resetting instance %d\n", or_instance); - + + printf("or_alarm: resetting card\n"); + orp->or_need_reset= TRUE; orp->or_got_int= TRUE; - check_int_events(); + or_check_ints(orp); } /***************************************************************************** - * mess_reply * - *****************************************************************************/ -static void mess_reply (message * req, message * reply_mess) -{ - if (ipc_send(req->m_source, reply_mess) != 0) - panic("orinoco: unable to mess_reply"); - -} - -/***************************************************************************** - * or_writev_s * + * or_send * * * - * Write data which is denoted by the message to the card and send it. * + * Send a packet, if possible * *****************************************************************************/ -static void or_writev_s (message * mp, int from_int) { - int count, size, err, data_len, data_off; - int o, j, n, i, s, p, cps ; +static int or_send(struct netdriver_data *data, size_t size) +{ + size_t p, data_len, data_off; + int err; struct ethhdr *eh; t_or *orp; hermes_t *hw; struct hermes_tx_descriptor desc; - int iov_offset = 0; struct header_struct hdr; - iovec_s_t *iovp; u16_t txfid; /* We need space for the max packet size itself, plus an ethernet @@ -1161,120 +862,72 @@ static void or_writev_s (message * mp, int from_int) { * packets from the card, which has an IO granularity of 16 * bits */ static u8_t databuf[IEEE802_11_DATA_LEN + ETH_HLEN + 2 + 1]; - memset (databuf, 0, IEEE802_11_DATA_LEN + ETH_HLEN + 3); orp = &or_state; - - count = mp->m_net_netdrv_dl_writev_s.count; - - orp->or_client = mp->m_source; hw = &(orp->hw); /* Switch off interrupts. The card is accessable via 2 BAPs, one for - * reading and one for writing. In theory these BAPs should be + * reading and one for writing. In theory these BAPs should be * independent, but in practice, the are not. By switching off the * interrupts of the card, the chances of one interfering with the - * other should be less */ - if (from_int){ - /* We were called with from_int, meaning that the last time we - * were called, no tx buffers were available, and we had to - * suspend. Now, we'll try again to find an empty buffer in the - * card */ - assert (orp->or_flags & OR_F_SEND_AVAIL); - orp->or_flags &= ~OR_F_SEND_AVAIL; - orp->or_send_int = FALSE; - orp->or_tx_alive = TRUE; - } + * other should be less + */ + /* ..except that this is not happening at all here. */ txfid = orp->or_tx.or_txfid; if (orp->or_tx.ret_busy || orp->connected == 0) { /* there is no buffer in the card available */ - assert(!(orp->or_flags & OR_F_SEND_AVAIL)); - /* Remember that there is a packet to be sent available */ - orp->or_flags |= OR_F_SEND_AVAIL; - goto suspend_write_s; + return SUSPEND; } - assert (orp->or_mode == OR_M_ENABLED); - assert (orp->or_flags & OR_F_ENABLED); + /* Copy the data to be sent from the vector to the databuf */ + netdriver_copyin(data, 0, databuf, size); + /* Zero out the rest of the buffer */ + memset(&databuf[size], 0, sizeof(databuf) - size); - /* Copy the data to be send from the vector to the databuf */ - size = 0; - o = 0; - for (i = 0; i < count; i += IOVEC_NR, - iov_offset += IOVEC_NR * sizeof (orp->or_iovec_s[0])) { - - n = IOVEC_NR; - if (i + n > count) - n = count - i; - - cps = sys_safecopyfrom(mp->m_source, - mp->m_net_netdrv_dl_writev_s.grant, iov_offset, - (vir_bytes) orp->or_iovec_s, - n * sizeof(orp->or_iovec_s[0])); - if (cps != OK) - printf("orinoco: sys_safecopyfrom failed: %d\n", cps); - - for (j = 0, iovp = orp->or_iovec_s; j < n; j++, iovp++) { - s = iovp->iov_size; - if (size + s > ETH_MAX_PACK_SIZE_TAGGED) { - printf("Orinoco: invalid pkt size\n"); - } - - cps = sys_safecopyfrom(mp->m_source, iovp->iov_grant, - 0, (vir_bytes) databuf + o, s); - if (cps != OK) - printf("orinoco: sys_safecopyfrom failed:%d\n", - cps); - - size += s; - o += s; - } - } - - assert(size >= ETH_MIN_PACK_SIZE); - - memset (&desc, 0, sizeof (desc)); - /* Reclaim the tx buffer once the data is sent (OK), or it is clear - * that transmission failed (EX). Reclaiming means that we can reuse - * the buffer again for transmission */ + memset(&desc, 0, sizeof(desc)); + /* Reclaim the tx buffer once the data is sent (OK), or it is clear + * that transmission failed (EX). Reclaiming means that we can reuse + * the buffer again for transmission + */ desc.tx_control = HERMES_TXCTRL_TX_OK | HERMES_TXCTRL_TX_EX; - /* Actually, this reclaim bit is the only thing which needs to be set - * in the descriptor */ - err = hermes_bap_pwrite (hw, USER_BAP, &desc, sizeof (desc), txfid, - 0); + /* Actually, this reclaim bit is the only thing which needs to be set + * in the descriptor + */ + err = hermes_bap_pwrite(hw, USER_BAP, &desc, sizeof(desc), txfid, 0); if (err) { printf("hermes_bap_pwrite() descriptor error:resetting card\n"); - /* When this happens, the card is quite confused: it will not - * recover. Reset it */ + /* When this happens, the card is quite confused: it will not + * recover. Reset it + */ or_reset(); - goto fail; + return OK; /* pretend the packet was sent anyway.. */ } eh = (struct ethhdr *) databuf; /* Encapsulate Ethernet-II frames */ - if (ntohs (eh->h_proto) > 1500) { + if (ntohs(eh->h_proto) > 1500) { /* Ethernet-II frame */ data_len = size - ETH_HLEN; data_off = HERMES_802_3_OFFSET + sizeof (hdr); /* 802.3 header */ - memcpy (hdr.dest, eh->h_dest, ETH_ALEN); - memcpy (hdr.src, eh->h_src, ETH_ALEN); - hdr.len = htons (data_len + ENCAPS_OVERHEAD); + memcpy(hdr.dest, eh->h_dest, ETH_ALEN); + memcpy(hdr.src, eh->h_src, ETH_ALEN); + hdr.len = htons(data_len + ENCAPS_OVERHEAD); /* 802.2 header */ - memcpy (&hdr.dsap, &encaps_hdr, sizeof (encaps_hdr)); + memcpy(&hdr.dsap, &encaps_hdr, sizeof (encaps_hdr)); hdr.ethertype = eh->h_proto; - err = hermes_bap_pwrite (hw, USER_BAP, &hdr, sizeof (hdr), + err = hermes_bap_pwrite(hw, USER_BAP, &hdr, sizeof(hdr), txfid, HERMES_802_3_OFFSET); if (err) { - printf ("%s: Error %d writing packet header to BAP\n", + printf("%s: Error %d writing packet header to BAP\n", orp->or_name, err); - goto fail; + return OK; /* pretend the packet was sent anyway.. */ } p = ETH_HLEN; @@ -1286,86 +939,44 @@ static void or_writev_s (message * mp, int from_int) { } /* Round up for odd length packets */ - err = hermes_bap_pwrite (hw, USER_BAP, - (void *) &(databuf[p]), RUP_EVEN (data_len), - txfid, data_off); + err = hermes_bap_pwrite(hw, USER_BAP, (void *) &(databuf[p]), + RUP_EVEN(data_len), txfid, data_off); if (err) { - printf ("hermes_bap_pwrite(data): error %d\n", err); - goto fail; + printf("hermes_bap_pwrite(data): error %d\n", err); + return OK; /* pretend the packet was sent anyway.. */ } - /* this should be before the docmd_wait. Cause otherwise the bit can - be cleared in the handler (if irq's not off) before it is set - and then 1 reset (ret_busy=false) is lost */ + /* this should be before the docmd_wait. Cause otherwise the bit can + * be cleared in the handler (if irq's not off) before it is set + * and then 1 reset (ret_busy=false) is lost + */ orp->or_tx.ret_busy = TRUE; + orp->or_tx_busy++; /* Send the packet which was constructed in txfid */ err = hermes_docmd_wait (hw, HERMES_CMD_TX | HERMES_CMD_RECL, txfid, NULL); if (err) { - printf ("hermes_docmd_wait(TX|RECL): error %d\n", err); + printf("hermes_docmd_wait(TX|RECL): error %d\n", err); /* Mark the buffer as available again */ orp->or_tx.ret_busy = FALSE; - goto fail; - } - -fail: - /* If the interrupt handler called, don't send a reply. The reply - * will be sent after all interrupts are handled. - */ - orp->or_flags |= OR_F_PACK_SENT; - - if (from_int) { - return; + orp->or_tx_busy--; + return OK; /* pretend the packet was sent anyway.. */ } - reply (orp); - return; - -suspend_write_s: - orp->or_tx_mess = *mp; - - reply (orp); - return; + return OK; } - -/***************************************************************************** - * reply * - * * - * Send a message back to the caller, informing it about the data received * - * or sent * - *****************************************************************************/ -static void reply (t_or * orp) { - message reply; - int flags = DL_NOFLAGS, r; - - if (orp->or_flags & OR_F_PACK_SENT) - flags |= DL_PACK_SEND; - if (orp->or_flags & OR_F_PACK_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 = orp->or_read_s; - - r = ipc_send(orp->or_client, &reply); - - if (r < 0) - panic("orinoco: send failed: %d", r); - - orp->or_read_s = 0; - orp->or_flags &= ~(OR_F_PACK_SENT | OR_F_PACK_RECV); -} - - /***************************************************************************** * or_ev_info * * * * Process information which comes in from the card * *****************************************************************************/ -static void or_ev_info (t_or * orp) +static void or_ev_info(t_or * orp) { + struct hermes_tallies_frame tallies; + struct hermes_linkstatus linkstatus; + u16_t newstatus; u16_t infofid; int err, len, type; hermes_t *hw = &orp->hw; @@ -1389,67 +1000,48 @@ static void or_ev_info (t_or * orp) switch (type) { case HERMES_INQ_TALLIES: - { - struct hermes_tallies_frame tallies; - - if (len > sizeof (tallies)) { - printf ("%s: Tallies frame too long ", - orp->or_name); - printf ("(%d bytes)\n", len); - len = sizeof (tallies); - } - hermes_read_words (hw, HERMES_DATA1, - (void *) &tallies, len / 2); - /* TODO: do something with the tallies structure */ + if (len > sizeof(tallies)) { + printf("%s: Tallies frame too long ", orp->or_name); + printf("(%d bytes)\n", len); + len = sizeof (tallies); } + hermes_read_words(hw, HERMES_DATA1, (void *)&tallies, len / 2); + /* TODO: do something with the tallies structure */ break; - case HERMES_INQ_LINKSTATUS: { - u16_t newstatus; - struct hermes_linkstatus linkstatus; + case HERMES_INQ_LINKSTATUS: + if (len != sizeof(linkstatus)) { + printf("%s: Unexpected size for linkstatus ", + orp->or_name); + printf("frame (%d bytes)\n", len); + } - if (len != sizeof (linkstatus)) { - printf ("%s: Unexpected size for linkstatus ", - orp->or_name); - printf ("frame (%d bytes)\n", len); - } + hermes_read_words(hw, HERMES_DATA1, (void *)&linkstatus, + len / 2); + newstatus = linkstatus.linkstatus; - hermes_read_words (hw, HERMES_DATA1, - (void *) &linkstatus, len / 2); - newstatus = linkstatus.linkstatus; - - if ((newstatus == HERMES_LINKSTATUS_CONNECTED) - || (newstatus == HERMES_LINKSTATUS_AP_CHANGE) - || (newstatus == HERMES_LINKSTATUS_AP_IN_RANGE)) { - orp->connected = 1; - - if(orp->or_flags & OR_F_SEND_AVAIL) { - orp->or_send_int = TRUE; + if ((newstatus == HERMES_LINKSTATUS_CONNECTED) + || (newstatus == HERMES_LINKSTATUS_AP_CHANGE) + || (newstatus == HERMES_LINKSTATUS_AP_IN_RANGE)) { + orp->connected = 1; + orp->or_send_int = TRUE; orp->or_got_int = TRUE; - int_event_check = TRUE; + } + else if ((newstatus == HERMES_LINKSTATUS_NOT_CONNECTED) + || (newstatus == HERMES_LINKSTATUS_DISCONNECTED) + || (newstatus == HERMES_LINKSTATUS_AP_OUT_OF_RANGE) + || (newstatus == HERMES_LINKSTATUS_ASSOC_FAILED)) { + orp->connected = 0; } + if (newstatus != orp->last_linkstatus) + print_linkstatus(orp, newstatus); - } - else if ((newstatus == - HERMES_LINKSTATUS_NOT_CONNECTED) - || (newstatus == - HERMES_LINKSTATUS_DISCONNECTED) - || (newstatus == - HERMES_LINKSTATUS_AP_OUT_OF_RANGE) - || (newstatus == - HERMES_LINKSTATUS_ASSOC_FAILED)) { - orp->connected = 0; - } + orp->last_linkstatus = newstatus; - if (newstatus != orp->last_linkstatus) - print_linkstatus(orp, newstatus); - - orp->last_linkstatus = newstatus; - } break; default: - printf ("%s:Unknown information frame received(type %04x).\n", + printf("%s:Unknown information frame received (type %04x).\n", orp->or_name, type); break; } @@ -1460,7 +1052,8 @@ static void or_ev_info (t_or * orp) * * * Process information which comes in from the card * *****************************************************************************/ -static void print_linkstatus (t_or * orp, u16_t status) { +static void print_linkstatus(t_or * orp, u16_t status) +{ int err; u16_t d; char *s; @@ -1492,52 +1085,45 @@ static void print_linkstatus (t_or * orp, u16_t status) { s = "UNKNOWN"; } - printf ("%s: link status: %s, ", orp->or_name, s); + printf("%s: link status: %s, ", orp->or_name, s); - err = hermes_read_wordrec (hw, USER_BAP, - HERMES_RID_CURRENTCHANNEL, &d); + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENTCHANNEL, &d); if (err) { - printf ("%s: Error %d \n", orp->or_name, err); + printf("error %d\n", err); return; } - printf("channel: %d, freq: %ld MHz ", - d, (channel_frequency[d-1])); - + printf("channel: %d, freq: %ld MHz\n", d, (channel_frequency[d-1])); } - /***************************************************************************** * or_check_ints * * * * Process events which have been postponed in the interrupt handler * *****************************************************************************/ -static void or_check_ints (t_or * orp) +static void or_check_ints(t_or * orp) { + if (!orp->or_got_int) + return; + orp->or_got_int = FALSE; + if (orp->or_need_reset) or_reset(); - if ((orp->rx_first!=orp->rx_last) && (orp->or_flags & OR_F_READING)) { - orp->or_ev_rx = 0; - or_readv_s (&orp->or_rx_mess, TRUE); - } - if (orp->or_send_int) { - or_writev_s (&orp->or_tx_mess, TRUE); - } + if (orp->rx_first != orp->rx_last) + netdriver_recv(); - if (orp->or_flags & (OR_F_PACK_SENT | OR_F_PACK_RECV)) { - reply (orp); - } + if (orp->or_send_int) + netdriver_send(); } - /***************************************************************************** * is_ethersnap * * * * is there an LLC and SNAP header in the ethernet packet? The inet task * * isn't very interested in it... * *****************************************************************************/ -static int is_ethersnap(struct header_struct *hdr) { - +static int is_ethersnap(struct header_struct *hdr) +{ /* We de-encapsulate all packets which, a) have SNAP headers * (i.e. SSAP=DSAP=0xaa and CTRL=0x3 in the 802.2 LLC header * and where b) the OUI of the SNAP header is 00:00:00 or @@ -1546,42 +1132,24 @@ static int is_ethersnap(struct header_struct *hdr) { return (memcmp(&hdr->dsap, &encaps_hdr, 5) == 0) && ( (hdr->oui[2] == 0x00) || (hdr->oui[2] == 0xf8) ); } - + /***************************************************************************** - * or_readv_s * + * or_recv * * * - * Copy the data which is stored in orp->rx_buf[orp->rx_first] in the vector * - * which was given with the message *mp * + * Receive a packet, if one is available * *****************************************************************************/ -static void or_readv_s (message * mp, int from_int) +static ssize_t or_recv(struct netdriver_data *data, size_t max) { - int i, j, n, o, s, count, size, cps; - int iov_offset = 0, length; t_or *orp; - iovec_s_t *iovp; u8_t *databuf; + size_t length; orp = &or_state; - orp->or_client = mp->m_source; - count = mp->m_net_netdrv_dl_readv_s.count; + if (orp->rx_first == orp->rx_last) + return SUSPEND; - assert (orp->or_mode == OR_M_ENABLED); - assert (orp->or_flags & OR_F_ENABLED); - - if (!from_int && (orp->rx_first==orp->rx_last)) - - { - /* if we are not called from a hard int (data is not yet available) and - * there are no buffers (or->rx_buf[x]) which contain any data, we cant - * copy any data to the inet server. Goto suspend, and wait for data - * to arrive */ - goto suspend_readv_s; - } - - - - /* and store the pointer to this data in databuf */ + /* store the pointer to this data in databuf */ databuf = &(orp->rx_buf[orp->rx_first][0]); length = orp->rx_length[orp->rx_first]; @@ -1592,94 +1160,36 @@ static void or_readv_s (message * mp, int from_int) orp->rx_first++; orp->rx_first %= NR_RX_BUFS; - o = 0; - /* The data which we want to be copied to the vector starts at - * *databuf and will be copied to the vecor below */ - size = 0; - for (i = 0; i < count; i += IOVEC_NR, - iov_offset += IOVEC_NR * sizeof(orp->or_iovec_s[0])) { - n = IOVEC_NR; - if (i + n > count) - n = count - i; + if (length > max) + length = max; - cps = sys_safecopyfrom(mp->m_source, - mp->m_net_netdrv_dl_readv_s.grant, iov_offset, - (vir_bytes)orp->or_iovec_s, - n * sizeof(orp->or_iovec_s[0])); - if (cps != OK) - panic("orinoco: warning: sys_safecopytp failed: %d", cps); - - for (j = 0, iovp = orp->or_iovec_s; j < n; j++, iovp++) { - s = iovp->iov_size; - if (size + s > length) { - assert (length > size); - s = length - size; - } - cps = sys_safecopyto(mp->m_source, iovp->iov_grant, 0, - (vir_bytes) databuf + o, s); - if (cps != OK) - panic("orinoco: warning: sys_safecopy failed: %d", cps); - - size += s; - if (size == length) - break; - o += s; - } - if (size == length) - break; - } - - assert(size >= length); + netdriver_copyout(data, 0, databuf, length); orp->or_stat.ets_packetR++; - orp->or_read_s = length; - orp->or_flags &= ~OR_F_READING; - orp->or_flags |= OR_F_PACK_RECV; - - if (!from_int) { - /* There was data in the orp->rx_buf[x] which is now copied to - * the inet sever. Tell the inet server */ - reply (orp); - } - - return; -suspend_readv_s: - if (from_int) { - assert (orp->or_flags & OR_F_READING); - /* No need to store any state */ - return; - } - - /* We want to store the message, so that next time when we are called - * by hard int, we know where to copy the received data */ - orp->or_rx_mess = *mp; - assert (!(orp->or_flags & OR_F_READING)); - orp->or_flags |= OR_F_READING; - - reply (orp); + return length; } - /***************************************************************************** * or_get_recvd_packet * * * * The card has received data. Retrieve the data from the card and put it * * in a buffer in the driver (in the orp structure) * *****************************************************************************/ -static int or_get_recvd_packet(t_or *orp, u16_t rxfid, u8_t *databuf) { +static int or_get_recvd_packet(t_or *orp, u16_t rxfid, u8_t *databuf) +{ struct hermes_rx_descriptor desc; hermes_t *hw; struct header_struct hdr; int err, length, offset; u16_t status; - + memset(databuf, 0, IEEE802_11_FRAME_LEN); hw = &(orp->hw); - /* Read the data from the buffer in the card which holds the data. - * First get the descriptor which will tell us whether the packet is + /* Read the data from the buffer in the card which holds the data. + * First get the descriptor which will tell us whether the packet is * healthy*/ err = hermes_bap_pread (hw, IRQ_BAP, &desc, sizeof (desc), rxfid, 0); if (err) { @@ -1716,7 +1226,7 @@ static int or_get_recvd_packet(t_or *orp, u16_t rxfid, u8_t *databuf) { } length = ntohs (hdr.len); - + /* Sanity checks */ if (length < 3) { /* No for even an 802.2 LLC header */ @@ -1748,50 +1258,29 @@ static int or_get_recvd_packet(t_or *orp, u16_t rxfid, u8_t *databuf) { return -1; } - /* Some types of firmware give us the SNAP and OUI headers. Remove these. + /* Some types of firmware give us the SNAP and OUI headers. Remove + * these. */ if (is_ethersnap(&hdr)) { length -= 8; - - memcpy (databuf + ETH_ALEN * 2, - databuf + sizeof(struct header_struct) - 2, + memcpy(databuf + ETH_ALEN * 2, + databuf + sizeof(struct header_struct) - 2, length - ETH_ALEN * 2); } if(length<60) length=60; - + return length; } /***************************************************************************** - * or_getstat_s * + * or_stat * * * * Return the statistics structure. The statistics aren't updated until now, * * so this won't return much interesting yet. * *****************************************************************************/ -static void or_getstat_s (message * mp) { - int r; - eth_stat_t stats; - t_or *orp; - - orp = &or_state; - - assert (orp->or_mode == OR_M_ENABLED); - assert (orp->or_flags & OR_F_ENABLED); - - stats = orp->or_stat; - - r = sys_safecopyto(mp->m_source, mp->m_net_netdrv_dl_getstat_s.grant, - 0, (vir_bytes) &stats, sizeof(stats)); - if(r != OK) { - panic("or_getstat_s: sys_safecopyto failed: %d", r); - } - - mp->m_type = DL_STAT_REPLY; - - r = ipc_send(mp->m_source, mp); - if(r != OK) - panic("orinoco: getstat_s failed: %d", r); +static void or_stat(eth_stat_t *stat) +{ + memcpy(stat, &or_state.or_stat, sizeof(*stat)); } - diff --git a/minix/drivers/net/orinoco/orinoco.h b/minix/drivers/net/orinoco/orinoco.h index 6adb838b5..97c38eb1c 100644 --- a/minix/drivers/net/orinoco/orinoco.h +++ b/minix/drivers/net/orinoco/orinoco.h @@ -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; diff --git a/minix/drivers/net/rtl8139/Makefile b/minix/drivers/net/rtl8139/Makefile index 0cb21b28a..9b114f366 100644 --- a/minix/drivers/net/rtl8139/Makefile +++ b/minix/drivers/net/rtl8139/Makefile @@ -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 diff --git a/minix/drivers/net/rtl8139/liveupdate.c b/minix/drivers/net/rtl8139/liveupdate.c index 9baaab8c0..d824b094b 100644 --- a/minix/drivers/net/rtl8139/liveupdate.c +++ b/minix/drivers/net/rtl8139/liveupdate.c @@ -1,3 +1,5 @@ +/* Code left here for historical purposes only. TODO: move into libnetdriver */ + #include "rtl8139.h" /* State management variables. */ diff --git a/minix/drivers/net/rtl8139/rtl8139.c b/minix/drivers/net/rtl8139/rtl8139.c index 6318d2fd9..2a259e42a 100644 --- a/minix/drivers/net/rtl8139/rtl8139.c +++ b/minix/drivers/net/rtl8139/rtl8139.c @@ -16,7 +16,7 @@ #include "rtl8139.h" -re_t re_state; +static re_t re_state; static int re_instance; @@ -64,225 +64,114 @@ static void my_outl(u16_t port, u32_t value) { #define rl_outw(port, offset, value) (my_outw((port) + (offset), (value))) #define rl_outl(port, offset, value) (my_outl((port) + (offset), (value))) -static void rl_init(message *mp); -static void rl_pci_conf(void); -static int rl_probe(re_t *rep, int skip); -static void rl_conf_hw(re_t *rep); +static int rl_init(unsigned int instance, ether_addr_t *addr); +static int rl_probe(re_t *rep, unsigned int skip); static void rl_init_buf(re_t *rep); -static void rl_init_hw(re_t *rep); +static void rl_init_hw(re_t *rep, ether_addr_t *addr); static void rl_reset_hw(re_t *rep); -static void rl_confaddr(re_t *rep); +static void rl_confaddr(re_t *rep, ether_addr_t *addr); +static void rl_stop(void); static void rl_rec_mode(re_t *rep); -static void rl_readv_s(const message *mp, int from_int); -static void rl_writev_s(const message *mp, int from_int); +static void rl_mode(unsigned int mode); +static ssize_t rl_recv(struct netdriver_data *data, size_t max); +static int rl_send(struct netdriver_data *data, size_t size); +static void rl_intr(unsigned int mask); static void rl_check_ints(re_t *rep); static void rl_report_link(re_t *rep); +#if VERBOSE static void mii_print_techab(u16_t techab); static void mii_print_stat_speed(u16_t stat, u16_t extstat); +#endif static void rl_clear_rx(re_t *rep); static void rl_do_reset(re_t *rep); -static void rl_getstat_s(message *mp); -static void reply(re_t *rep); -static void mess_reply(message *req, message *reply); -static void check_int_events(void); -static void do_hard_int(void); -static void rtl8139_dump(message *m); +static void rl_stat(eth_stat_t *stat); +static void rl_other(const message *m_ptr, int ipc_status); +static void rl_dump(void); #if 0 static void dump_phy(re_t *rep); #endif static int rl_handler(re_t *rep); -static void rl_watchdog_f(minix_timer_t *tp); -static void tell_dev(vir_bytes start, size_t size, int pci_bus, int +static void rl_alarm(clock_t stamp); +static void tell_iommu(vir_bytes start, size_t size, int pci_bus, int pci_dev, int pci_func); -/* The message used in the main loop is made global, so that rl_watchdog_f() - * can change its message type to fake an interrupt message. - */ -static message m; -static int int_event_check; /* set to TRUE if events arrived */ - -static u32_t system_hz; - -/* 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); -EXTERN int sef_cb_lu_prepare(int state); -EXTERN int sef_cb_lu_state_isvalid(int state); -EXTERN void sef_cb_lu_state_dump(int state); +static const struct netdriver rl_table = { + .ndr_init = rl_init, + .ndr_stop = rl_stop, + .ndr_mode = rl_mode, + .ndr_recv = rl_recv, + .ndr_send = rl_send, + .ndr_stat = rl_stat, + .ndr_intr = rl_intr, + .ndr_alarm = rl_alarm, + .ndr_other = rl_other, +}; /*===========================================================================* * main * *===========================================================================*/ int main(int argc, char *argv[]) { - int r; - int ipc_status; - /* SEF local startup. */ env_setargs(argc, argv); - sef_local_startup(); - while (TRUE) - { - if ((r= netdriver_receive(ANY, &m, &ipc_status)) != OK) - panic("netdriver_receive failed: %d", r); + netdriver_task(&rl_table); - if (is_ipc_notify(ipc_status)) { - switch (_ENDPOINT_P(m.m_source)) { - case CLOCK: - /* - * Under MINIX, synchronous alarms are - * used instead of watchdog functions. - * The approach is very different: MINIX - * VMD timeouts are handled within the - * kernel (the watchdog is executed by - * CLOCK), and notify() the driver in - * some cases. MINIX timeouts result in - * a SYN_ALARM message to the driver and - * thus are handled where they should be - * handled. Locally, watchdog functions - * are used again. - */ - rl_watchdog_f(NULL); - break; - case HARDWARE: - do_hard_int(); - if (int_event_check) - check_int_events(); - break ; - case TTY_PROC_NR: - rtl8139_dump(&m); - break; - default: - panic("illegal notify from: %d", - m.m_source); - } - - /* done, get nwe message */ - continue; - } - - switch (m.m_type) - { - case DL_WRITEV_S: rl_writev_s(&m, FALSE); break; - case DL_READV_S: rl_readv_s(&m, FALSE); break; - case DL_CONF: rl_init(&m); break; - case DL_GETSTAT_S: rl_getstat_s(&m); break; - default: - panic("illegal message: %d", m.m_type); - } - } + return 0; } /*===========================================================================* - * sef_local_startup * + * rl_intr * *===========================================================================*/ -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); - sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid); - sef_setcb_lu_state_dump(sef_cb_lu_state_dump); - - /* 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 rtl8139 driver. */ - long v; -#if RTL8139_FKEY - int r, fkeys, sfkeys; -#endif - - system_hz = sys_hz(); - - v = 0; - (void) env_parse("instance", "d", 0, &v, 0, 255); - re_instance = (int) v; - -#if RTL8139_FKEY - /* Observe some function key for debug dumps. */ - fkeys = sfkeys = 0; bit_set(sfkeys, 9); - if ((r=fkey_map(&fkeys, &sfkeys)) != OK) - printf("Warning: RTL8139 couldn't observe Shift+F9 key: %d\n",r); -#endif - - /* Claim buffer memory now. */ - rl_init_buf(&re_state); - - /* Announce we are up! */ - netdriver_announce(); - - return(OK); -} - -/*===========================================================================* - * sef_cb_signal_handler * - *===========================================================================*/ -static void sef_cb_signal_handler(int signo) +static void rl_intr(unsigned int __unused mask) { re_t *rep; - - /* Only check for termination signal, ignore anything else. */ - if (signo != SIGTERM) return; + int s; rep = &re_state; - if (rep->re_mode == REM_ENABLED) - rl_outb(rep->re_base_port, RL_CR, 0); - exit(0); -} + /* Run interrupt handler at driver level. */ + rl_handler(rep); -/*===========================================================================* - * check_int_events * - *===========================================================================*/ -static void check_int_events(void) -{ - re_t *rep; + /* Reenable interrupts for this hook. */ + if ((s = sys_irqenable(&rep->re_hook_id)) != OK) + printf("RTL8139: error, couldn't enable interrupts: %d\n", s); - rep= &re_state; - - if (rep->re_mode != REM_ENABLED) - return; - if (!rep->re_got_int) - return; - rep->re_got_int= 0; - assert(rep->re_flags & REF_ENABLED); + /* Perform tasks based on the flagged conditions. */ rl_check_ints(rep); } /*===========================================================================* - * rtl8139_dump * + * rl_other * *===========================================================================*/ -static void rtl8139_dump(m) -message *m; /* pointer to request message */ +static void rl_other(const message *m_ptr, int ipc_status) +{ + if (is_ipc_notify(ipc_status) && m_ptr->m_source == TTY_PROC_NR) + rl_dump(); +} + +/*===========================================================================* + * rl_stop * + *===========================================================================*/ +static void rl_stop(void) +{ + re_t *rep; + + rep = &re_state; + + rl_outb(rep->re_base_port, RL_CR, 0); +} + +/*===========================================================================* + * rl_dump * + *===========================================================================*/ +static void rl_dump(void) { re_t *rep; rep= &re_state; printf("\n"); - if (rep->re_mode == REM_DISABLED) - printf("Realtek RTL 8139 instance %d is disabled\n", - re_instance); - - if (rep->re_mode != REM_ENABLED) - return; - printf("Realtek RTL 8139 statistics of instance %d:\n", re_instance); printf("recvErr :%8ld\t", rep->re_stat.ets_recvErr); @@ -307,8 +196,6 @@ message *m; /* pointer to request message */ printf("OWC :%8ld\t", rep->re_stat.ets_OWC); - printf("re_flags = 0x%x\n", rep->re_flags); - printf("TSAD: 0x%04x, TSD: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n", rl_inw(rep->re_base_port, RL_TSAD), rl_inl(rep->re_base_port, RL_TSD0+0*4), @@ -322,93 +209,73 @@ message *m; /* pointer to request message */ } /*===========================================================================* - * rl_init * + * rl_mode * *===========================================================================*/ -static void rl_init(mp) -message *mp; +static void rl_mode(unsigned int mode) { - static int first_time= 1; - re_t *rep; - message reply_mess; - - if (first_time) - { - first_time= 0; - rl_pci_conf(); /* Configure PCI devices. */ - - /* Use a synchronous alarm instead of a watchdog timer. */ - sys_setalarm(system_hz, 0); - } rep= &re_state; - if (rep->re_mode == REM_DISABLED) - { - /* This is the default, try to (re)locate the device. */ - rl_conf_hw(rep); - if (rep->re_mode == REM_DISABLED) - { - /* Probe failed, or the device is configured off. */ - reply_mess.m_type= DL_CONF_REPLY; - reply_mess.m_netdrv_net_dl_conf.stat= ENXIO; - mess_reply(mp, &reply_mess); - return; - } - if (rep->re_mode == REM_ENABLED) - rl_init_hw(rep); -#if VERBOSE /* load silently ... can always check status later */ - rl_report_link(rep); -#endif - } - assert(rep->re_mode == REM_ENABLED); - assert(rep->re_flags & REF_ENABLED); - - rep->re_flags &= ~(REF_PROMISC | REF_MULTI | REF_BROAD); - - if (mp->m_net_netdrv_dl_conf.mode & DL_PROMISC_REQ) - rep->re_flags |= REF_PROMISC; - if (mp->m_net_netdrv_dl_conf.mode & DL_MULTI_REQ) - rep->re_flags |= REF_MULTI; - if (mp->m_net_netdrv_dl_conf.mode & DL_BROAD_REQ) - rep->re_flags |= REF_BROAD; + rep->re_mode = mode; rl_rec_mode(rep); - - reply_mess.m_type = DL_CONF_REPLY; - reply_mess.m_netdrv_net_dl_conf.stat = OK; - memcpy(reply_mess.m_netdrv_net_dl_conf.hw_addr, - rep->re_address.ea_addr, - sizeof(reply_mess.m_netdrv_net_dl_conf.hw_addr)); - - mess_reply(mp, &reply_mess); } /*===========================================================================* - * rl_pci_conf * + * rl_init * *===========================================================================*/ -static void rl_pci_conf() +static int rl_init(unsigned int instance, ether_addr_t *addr) { +/* Initialize the rtl8139 driver. */ re_t *rep; +#if RTL8139_FKEY + int r, fkeys, sfkeys; +#endif + /* Initialize driver state. */ rep= &re_state; + memset(rep, 0, sizeof(*rep)); + rep->re_link_up= -1; /* Unknown */ + rep->re_ertxth= RL_TSD_ERTXTH_8; strlcpy(rep->re_name, "rtl8139#0", sizeof(rep->re_name)); - rep->re_name[8] += re_instance; - rep->re_seen= FALSE; + rep->re_name[8] += instance; - pci_init(); + re_instance = instance; - if (rl_probe(rep, re_instance)) - rep->re_seen= TRUE; + /* Try to find a matching device. */ + if (!rl_probe(rep, instance)) + return ENXIO; + + /* Claim buffer memory. */ + rl_init_buf(rep); + + /* Initialize the device we found. */ + rl_init_hw(rep, addr); + +#if VERBOSE + /* Report initial link status. */ + rl_report_link(rep); +#endif + + /* Use a synchronous alarm instead of a watchdog timer. */ + sys_setalarm(sys_hz(), 0); + +#if RTL8139_FKEY + /* Observe some function key for debug dumps. */ + fkeys = sfkeys = 0; bit_set(sfkeys, 9); + if ((r = fkey_map(&fkeys, &sfkeys)) != OK) + printf("Warning: RTL8139 couldn't observe Shift+F9 key: %d\n",r); +#endif + + return OK; } /*===========================================================================* * rl_probe * *===========================================================================*/ -static int rl_probe(rep, skip) -re_t *rep; -int skip; +static int rl_probe(re_t *rep, unsigned int skip) { int r, devind; u16_t cr, vid, did; @@ -418,6 +285,8 @@ int skip; char *dname; #endif + pci_init(); + r= pci_first_dev(&devind, &vid, &did); if (r == 0) return 0; @@ -452,53 +321,18 @@ int skip; ilr= pci_attr_r8(devind, PCI_ILR); rep->re_irq= ilr; - if (debug) - { - printf("%s: using I/O address 0x%lx, IRQ %d\n", - rep->re_name, (unsigned long)bar, ilr); - } +#if VERBOSE + printf("%s: using I/O address 0x%lx, IRQ %d\n", + rep->re_name, (unsigned long)bar, ilr); +#endif return TRUE; } -/*===========================================================================* - * rl_conf_hw * - *===========================================================================*/ -static void rl_conf_hw(rep) -re_t *rep; -{ - static eth_stat_t empty_stat = {0, 0, 0, 0, 0, 0 /* ,... */ }; - - rep->re_mode= REM_DISABLED; /* Superfluous */ - - if (rep->re_seen) - { - /* PCI device is present */ - rep->re_mode= REM_ENABLED; - } - if (rep->re_mode != REM_ENABLED) - return; - - rep->re_flags= REF_EMPTY; - rep->re_link_up= -1; /* Unknown */ - rep->re_got_int= 0; - rep->re_send_int= 0; - rep->re_report_link= 0; - rep->re_clear_rx= 0; - rep->re_need_reset= 0; - rep->re_tx_alive= 0; - rep->re_read_s= 0; - rep->re_tx_head= 0; - rep->re_tx_tail= 0; - rep->re_ertxth= RL_TSD_ERTXTH_8; - rep->re_stat= empty_stat; -} - /*===========================================================================* * rl_init_buf * *===========================================================================*/ -static void rl_init_buf(rep) -re_t *rep; +static void rl_init_buf(re_t *rep) { size_t rx_bufsize, tx_bufsize, tot_bufsize; phys_bytes buf; @@ -517,9 +351,8 @@ re_t *rep; #define BUF_ALIGNMENT (64*1024) - if(!(mallocbuf = alloc_contig(BUF_ALIGNMENT + tot_bufsize, 0, &buf))) { - panic("Couldn't allocate kernel buffer"); - } + if (!(mallocbuf = alloc_contig(BUF_ALIGNMENT + tot_bufsize, 0, &buf))) + panic("Couldn't allocate kernel buffer"); /* click-align mallocced buffer. this is what we used to get * from kmalloc() too. @@ -529,7 +362,7 @@ re_t *rep; buf += BUF_ALIGNMENT - off; } - tell_dev((vir_bytes)mallocbuf, tot_bufsize, 0, 0, 0); + tell_iommu((vir_bytes)mallocbuf, tot_bufsize, 0, 0, 0); for (i= 0; ire_flags = REF_EMPTY; - rep->re_flags |= REF_ENABLED; - - /* Set the interrupt handler. The policy is to only send HARD_INT + /* Set the interrupt handler. The policy is to only send HARD_INT * notifications. Don't reenable interrupts automatically. The id * that is passed back is the interrupt line number. */ - rep->re_hook_id = rep->re_irq; + rep->re_hook_id = rep->re_irq; if ((s=sys_irqsetpolicy(rep->re_irq, 0, &rep->re_hook_id)) != OK) printf("RTL8139: error, couldn't set IRQ policy: %d\n", s); @@ -578,23 +410,19 @@ re_t *rep; } #endif - rl_confaddr(rep); - if (debug) - { - printf("%s: Ethernet address ", rep->re_name); - for (i= 0; i < 6; i++) - { - printf("%x%c", rep->re_address.ea_addr[i], - i < 5 ? ':' : '\n'); - } - } + rl_confaddr(rep, addr); + +#if VERBOSE + printf("%s: Ethernet address ", rep->re_name); + for (i= 0; i < 6; i++) + printf("%x%c", addr->ea_addr[i], i < 5 ? ':' : '\n'); +#endif } /*===========================================================================* * rl_reset_hw * *===========================================================================*/ -static void rl_reset_hw(rep) -re_t *rep; +static void rl_reset_hw(re_t *rep) { port_t port; u32_t t; @@ -660,7 +488,7 @@ re_t *rep; bus_buf= vm_1phys2bus(rep->re_rx_buf); rl_outl(port, RL_RBSTART, bus_buf); - /* Initialize Tx */ + /* Initialize Tx */ for (i= 0; ire_tx[i].ret_busy= FALSE; @@ -670,6 +498,8 @@ re_t *rep; assert(t & RL_TSD_OWN); } + rep->re_tx_busy = 0; + #if 0 dump_phy(rep); #endif @@ -700,8 +530,7 @@ re_t *rep; /*===========================================================================* * rl_confaddr * *===========================================================================*/ -static void rl_confaddr(rep) -re_t *rep; +static void rl_confaddr(re_t *rep, ether_addr_t *addr) { static char eakey[]= RL_ENVVAR "#_EA"; static char eafmt[]= "x:x:x:x:x:x"; @@ -720,7 +549,7 @@ re_t *rep; { if (env_parse(eakey, eafmt, i, &v, 0x00L, 0xFFL) != EP_SET) break; - rep->re_address.ea_addr[i]= v; + addr->ea_addr[i]= v; } if (i != 0 && i != 6) env_panic(eakey); /* It's all or nothing */ @@ -732,25 +561,24 @@ re_t *rep; rl_outb(port, RL_9346CR, RL_9346CR_EEM_CONFIG); w= 0; for (i= 0; i<4; i++) - w |= (rep->re_address.ea_addr[i] << (i*8)); + w |= (addr->ea_addr[i] << (i*8)); rl_outl(port, RL_IDR, w); w= 0; for (i= 4; i<6; i++) - w |= (rep->re_address.ea_addr[i] << ((i-4)*8)); + w |= (addr->ea_addr[i] << ((i-4)*8)); rl_outl(port, RL_IDR+4, w); rl_outb(port, RL_9346CR, RL_9346CR_EEM_NORMAL); } /* Get ethernet address */ for (i= 0; i<6; i++) - rep->re_address.ea_addr[i]= rl_inb(port, RL_IDR+i); + addr->ea_addr[i]= rl_inb(port, RL_IDR+i); } /*===========================================================================* * rl_rec_mode * *===========================================================================*/ -static void rl_rec_mode(rep) -re_t *rep; +static void rl_rec_mode(re_t *rep) { port_t port; u32_t rcr; @@ -758,11 +586,11 @@ re_t *rep; port= rep->re_base_port; rcr= rl_inl(port, RL_RCR); rcr &= ~(RL_RCR_AB|RL_RCR_AM|RL_RCR_APM|RL_RCR_AAP); - if (rep->re_flags & REF_PROMISC) + if (rep->re_mode & NDEV_PROMISC) rcr |= RL_RCR_AB | RL_RCR_AM | RL_RCR_AAP; - if (rep->re_flags & REF_BROAD) + if (rep->re_mode & NDEV_BROAD) rcr |= RL_RCR_AB; - if (rep->re_flags & REF_MULTI) + if (rep->re_mode & NDEV_MULTI) rcr |= RL_RCR_AM; rcr |= RL_RCR_APM; @@ -770,39 +598,28 @@ re_t *rep; } /*===========================================================================* - * rl_readv_s * + * rl_recv * *===========================================================================*/ -static void rl_readv_s(const message *mp, int from_int) +static ssize_t rl_recv(struct netdriver_data *data, size_t max) { - int i, j, n, o, s, s1, count, size; + int o, s; port_t port; unsigned amount, totlen, packlen; u16_t d_start, d_end; - u32_t l, rxstat = 0x12345678; + u32_t l, rxstat; re_t *rep; - iovec_s_t *iovp; - int cps; - int iov_offset = 0; rep= &re_state; - rep->re_client= mp->m_source; - count = mp->m_net_netdrv_dl_readv_s.count; - if (rep->re_clear_rx) - goto suspend; /* Buffer overflow */ - - assert(rep->re_mode == REM_ENABLED); - assert(rep->re_flags & REF_ENABLED); + return SUSPEND; /* Buffer overflow */ port= rep->re_base_port; - /* Assume that the RL_CR_BUFE check was been done by rl_checks_ints - */ - if (!from_int && (rl_inb(port, RL_CR) & RL_CR_BUFE)) + if (rl_inb(port, RL_CR) & RL_CR_BUFE) { /* Receive buffer is empty, suspend */ - goto suspend; + return SUSPEND; } d_start= rl_inw(port, RL_CAPR) + RL_CAPR_DATA_OFF; @@ -811,7 +628,7 @@ static void rl_readv_s(const message *mp, int from_int) #if RX_BUFSIZE <= USHRT_MAX if (d_start >= RX_BUFSIZE) { - printf("rl_readv: strange value in RL_CAPR: 0x%x\n", + printf("rl_recv: strange value in RL_CAPR: 0x%x\n", rl_inw(port, RL_CAPR)); d_start %= RX_BUFSIZE; } @@ -824,14 +641,6 @@ static void rl_readv_s(const message *mp, int from_int) rxstat = *(u32_t *) (rep->v_re_rx_buf + d_start); - if (rep->re_clear_rx) - { -#if 0 - printf("rl_readv: late buffer overflow\n"); -#endif - goto suspend; /* Buffer overflow */ - } - /* Should convert from little endian to host byte order */ if (!(rxstat & RL_RXS_ROK)) @@ -846,7 +655,7 @@ static void rl_readv_s(const message *mp, int from_int) { /* Someting went wrong */ printf( - "rl_readv: bad length (%u) in status 0x%08x at offset 0x%x\n", + "rl_recv: bad length (%u) in status 0x%08x at offset 0x%x\n", totlen, rxstat, d_start); printf( "d_start: 0x%x, d_end: 0x%x, totlen: %d, rxstat: 0x%x\n", @@ -861,106 +670,22 @@ static void rl_readv_s(const message *mp, int from_int) if (totlen+4 > amount) { - printf("rl_readv: packet not yet ready\n"); - goto suspend; + printf("rl_recv: packet not yet ready\n"); + return SUSPEND; } /* Should subtract the CRC */ - packlen= totlen - ETH_CRC_SIZE; + packlen = MIN(totlen - ETH_CRC_SIZE, max); - size= 0; - o= d_start+4; - for (i= 0; ire_iovec_s[0])) - { - n= IOVEC_NR; - if (i+n > count) - n= count-i; + /* Copy out the data. The packet may wrap in the receive buffer. */ + o = (d_start+4) % RX_BUFSIZE; + s = MIN(RX_BUFSIZE - o, packlen); - cps = sys_safecopyfrom(mp->m_source, - mp->m_net_netdrv_dl_readv_s.grant, iov_offset, - (vir_bytes) rep->re_iovec_s, - n * sizeof(rep->re_iovec_s[0])); - if (cps != OK) { - panic("rl_readv_s: sys_safecopyfrom failed: %d", - cps); - } - - for (j= 0, iovp= rep->re_iovec_s; jiov_size; - if (size + s > packlen) - { - assert(packlen > size); - s= packlen-size; - } - -#if 0 - if (sys_umap(mp->m_source, D, iovp->iov_addr, s, &dst_phys) != OK) - panic("umap_local failed"); -#endif - - if (o >= RX_BUFSIZE) - { - o -= RX_BUFSIZE; - assert(o < RX_BUFSIZE); - } - - if (o+s > RX_BUFSIZE) - { - assert(om_source, - iovp->iov_grant, 0, - (vir_bytes) rep->v_re_rx_buf+o, s1); - if (cps != OK) { - panic("rl_readv_s: sys_safecopyto failed: %d", - cps); - } - cps = sys_safecopyto(mp->m_source, - iovp->iov_grant, s1, - (vir_bytes) rep->v_re_rx_buf, s-s1); - if (cps != OK) { - panic("rl_readv_s: sys_safecopyto failed: %d", cps); - } - } - else - { - cps = sys_safecopyto(mp->m_source, - iovp->iov_grant, 0, - (vir_bytes) rep->v_re_rx_buf+o, s); - if (cps != OK) - panic("rl_readv_s: sys_safecopyto failed: %d", cps); - } - - size += s; - if (size == packlen) - break; - o += s; - } - if (size == packlen) - break; - } - if (size < packlen) - { - assert(0); - } - - if (rep->re_clear_rx) - { - /* For some reason the receiver FIFO is not stopped when - * the buffer is full. - */ -#if 0 - printf("rl_readv: later buffer overflow\n"); -#endif - goto suspend; /* Buffer overflow */ - } + netdriver_copyout(data, 0, rep->v_re_rx_buf + o, s); + if (s < packlen) + netdriver_copyout(data, s, rep->v_re_rx_buf, packlen - s); rep->re_stat.ets_packetR++; - rep->re_read_s= packlen; - rep->re_flags= (rep->re_flags & ~REF_READING) | REF_PACK_RECV; /* Avoid overflow in 16-bit computations */ l= d_start; @@ -973,145 +698,41 @@ static void rl_readv_s(const message *mp, int from_int) } rl_outw(port, RL_CAPR, l-RL_CAPR_DATA_OFF); - if (!from_int) - reply(rep); - - return; - -suspend: - if (from_int) - { - assert(rep->re_flags & REF_READING); - - /* No need to store any state */ - return; - } - - rep->re_rx_mess= *mp; - assert(!(rep->re_flags & REF_READING)); - rep->re_flags |= REF_READING; - - reply(rep); + return packlen; } /*===========================================================================* - * rl_writev_s * + * rl_send * *===========================================================================*/ -static void rl_writev_s(const message *mp, int from_int) +static int rl_send(struct netdriver_data *data, size_t size) { - int i, j, n, s, count, size; int tx_head; re_t *rep; - iovec_s_t *iovp; - char *ret; - int cps; - int iov_offset = 0; rep= &re_state; - rep->re_client= mp->m_source; - count = mp->m_net_netdrv_dl_writev_s.count; - - assert(rep->re_mode == REM_ENABLED); - assert(rep->re_flags & REF_ENABLED); - - if (from_int) - { - assert(rep->re_flags & REF_SEND_AVAIL); - rep->re_flags &= ~REF_SEND_AVAIL; - rep->re_send_int= FALSE; - rep->re_tx_alive= TRUE; - } - tx_head= rep->re_tx_head; if (rep->re_tx[tx_head].ret_busy) - { - assert(!(rep->re_flags & REF_SEND_AVAIL)); - rep->re_flags |= REF_SEND_AVAIL; - goto suspend; - } + return SUSPEND; - assert(!(rep->re_flags & REF_SEND_AVAIL)); - assert(!(rep->re_flags & REF_PACK_SENT)); + netdriver_copyin(data, 0, rep->re_tx[tx_head].v_ret_buf, size); - size= 0; - ret = rep->re_tx[tx_head].v_ret_buf; - for (i= 0; ire_iovec_s[0])) - { - n= IOVEC_NR; - if (i+n > count) - n= count-i; - cps = sys_safecopyfrom(mp->m_source, - mp->m_net_netdrv_dl_writev_s.grant, iov_offset, - (vir_bytes) rep->re_iovec_s, - n * sizeof(rep->re_iovec_s[0])); - if (cps != OK) { - panic("rl_writev_s: sys_safecopyfrom failed: %d", cps); - } - - for (j= 0, iovp= rep->re_iovec_s; jiov_size; - if (size + s > ETH_MAX_PACK_SIZE_TAGGED) { - panic("invalid packet size"); - } - cps = sys_safecopyfrom(mp->m_source, iovp->iov_grant, - 0, (vir_bytes) ret, s); - if (cps != OK) { - panic("rl_writev_s: sys_safecopyfrom failed: %d", cps); - } - size += s; - ret += s; - } - } - if (size < ETH_MIN_PACK_SIZE) - panic("invalid packet size: %d", size); - - rl_outl(rep->re_base_port, RL_TSD0+tx_head*4, - rep->re_ertxth | size); + rl_outl(rep->re_base_port, RL_TSD0+tx_head*4, rep->re_ertxth | size); rep->re_tx[tx_head].ret_busy= TRUE; + rep->re_tx_busy++; if (++tx_head == N_TX_BUF) tx_head= 0; assert(tx_head < RL_N_TX); rep->re_tx_head= tx_head; - rep->re_flags |= REF_PACK_SENT; - - /* If the interrupt handler called, don't send a reply. The reply - * will be sent after all interrupts are handled. - */ - if (from_int) - return; - reply(rep); - return; - -suspend: -#if 0 - printf("rl_writev: head %d, tail %d, busy: %d %d %d %d\n", - tx_head, rep->re_tx_tail, - rep->re_tx[0].ret_busy, rep->re_tx[1].ret_busy, - rep->re_tx[2].ret_busy, rep->re_tx[3].ret_busy); - printf("rl_writev: TSD: 0x%x, 0x%x, 0x%x, 0x%x\n", - rl_inl(rep->re_base_port, RL_TSD0+0*4), - rl_inl(rep->re_base_port, RL_TSD0+1*4), - rl_inl(rep->re_base_port, RL_TSD0+2*4), - rl_inl(rep->re_base_port, RL_TSD0+3*4)); -#endif - - if (from_int) - panic("should not be sending"); - - rep->re_tx_mess= *mp; - reply(rep); + return OK; } /*===========================================================================* * rl_check_ints * *===========================================================================*/ -static void rl_check_ints(rep) -re_t *rep; +static void rl_check_ints(re_t *rep) { #if 0 10-1f R/W TSD[0-3] Transmit Status of Descriptor [0-3] @@ -1152,45 +773,41 @@ re_t *rep; 15-0 R RXERCNT Received packet counter #endif - int re_flags; + if (!rep->re_got_int) + return; + rep->re_got_int = FALSE; - re_flags= rep->re_flags; + netdriver_recv(); - if ((re_flags & REF_READING) && - !(rl_inb(rep->re_base_port, RL_CR) & RL_CR_BUFE)) - { - rl_readv_s(&rep->re_rx_mess, TRUE /* from int */); - } if (rep->re_clear_rx) rl_clear_rx(rep); if (rep->re_need_reset) rl_do_reset(rep); - if (rep->re_send_int) - { - rl_writev_s(&rep->re_tx_mess, TRUE /* from int */); + if (rep->re_send_int) { + rep->re_send_int = FALSE; + + netdriver_send(); } - if (rep->re_report_link) - rl_report_link(rep); + if (rep->re_report_link) { + rep->re_report_link = FALSE; - if (rep->re_flags & (REF_PACK_SENT | REF_PACK_RECV)) - reply(rep); + rl_report_link(rep); + } } /*===========================================================================* * rl_report_link * *===========================================================================*/ -static void rl_report_link(rep) -re_t *rep; +static void rl_report_link(re_t *rep) { port_t port; u16_t mii_ctrl, mii_status, mii_ana, mii_anlpa, mii_ane, mii_extstat; u8_t msr; int f, link_up; - rep->re_report_link= FALSE; port= rep->re_base_port; msr= rl_inb(port, RL_MSR); link_up= !(msr & RL_MSR_LINKB); @@ -1250,8 +867,7 @@ re_t *rep; return; } - if (!debug) goto resspeed; - +#if VERBOSE printf("%s: ", rep->re_name); mii_print_stat_speed(mii_status, mii_extstat); printf("\n"); @@ -1293,14 +909,16 @@ re_t *rep; printf("%s: remote cap.: ", rep->re_name); mii_print_techab(mii_anlpa); printf("\n"); - resspeed: +#endif + printf("%s: ", rep->re_name); printf("link up at %d Mbps, ", (msr & RL_MSR_SPEED_10) ? 10 : 100); printf("%s duplex\n", ((mii_ctrl & MII_CTRL_DM) ? "full" : "half")); } +#if VERBOSE static void mii_print_techab(u16_t techab) { int fs, ft; @@ -1469,6 +1087,7 @@ static void mii_print_stat_speed(u16_t stat, u16_t extstat) } } } +#endif /* VERBOSE */ /*===========================================================================* * rl_clear_rx * @@ -1508,98 +1127,32 @@ static void rl_clear_rx(re_t *rep) /*===========================================================================* * rl_do_reset * *===========================================================================*/ -static void rl_do_reset(rep) -re_t *rep; +static void rl_do_reset(re_t *rep) { rep->re_need_reset= FALSE; rl_reset_hw(rep); rl_rec_mode(rep); rep->re_tx_head= 0; - if (rep->re_flags & REF_SEND_AVAIL) - { - rep->re_tx[rep->re_tx_head].ret_busy= FALSE; - rep->re_send_int= TRUE; - } + if (rep->re_tx[rep->re_tx_head].ret_busy) + rep->re_tx_busy--; + rep->re_tx[rep->re_tx_head].ret_busy= FALSE; + rep->re_send_int= TRUE; } /*===========================================================================* - * rl_getstat_s * + * rl_stat * *===========================================================================*/ -static void rl_getstat_s(mp) -message *mp; +static void rl_stat(eth_stat_t *stat) { - int r; - eth_stat_t stats; - re_t *rep; - - rep= &re_state; - - assert(rep->re_mode == REM_ENABLED); - assert(rep->re_flags & REF_ENABLED); - - stats= rep->re_stat; - - r = sys_safecopyto(mp->m_source, mp->m_net_netdrv_dl_getstat_s.grant, - 0, (vir_bytes) &stats, sizeof(stats)); - if (r != OK) - panic("rl_getstat_s: sys_safecopyto failed: %d", r); - - mp->m_type= DL_STAT_REPLY; - r= ipc_send(mp->m_source, mp); - if (r != OK) - panic("rl_getstat_s: ipc_send failed: %d", r); -} - -/*===========================================================================* - * reply * - *===========================================================================*/ -static void reply(rep) -re_t *rep; -{ - message reply; - int flags; - int r; - - flags = DL_NOFLAGS; - if (rep->re_flags & REF_PACK_SENT) - flags |= DL_PACK_SEND; - if (rep->re_flags & REF_PACK_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 = rep->re_read_s; - - r= ipc_send(rep->re_client, &reply); - - if (r < 0) { - printf("RTL8139 tried sending to %d, type %d\n", - rep->re_client, reply.m_type); - panic("ipc_send failed: %d", r); - } - - rep->re_read_s = 0; - rep->re_flags &= ~(REF_PACK_SENT | REF_PACK_RECV); -} - -/*===========================================================================* - * mess_reply * - *===========================================================================*/ -static void mess_reply(req, reply_mess) -message *req; -message *reply_mess; -{ - if (ipc_send(req->m_source, reply_mess) != OK) - panic("unable to mess_reply"); + memcpy(stat, &re_state.re_stat, sizeof(*stat)); } #if 0 /*===========================================================================* * dump_phy * *===========================================================================*/ -static void dump_phy(rep) -re_t *rep; +static void dump_phy(re_t *rep) { port_t port; u32_t t; @@ -1693,21 +1246,6 @@ re_t *rep; } #endif -/*===========================================================================* - * do_hard_int * - *===========================================================================*/ -static void do_hard_int(void) -{ - int s; - - /* Run interrupt handler at driver level. */ - rl_handler(&re_state); - - /* Reenable interrupts for this hook. */ - if ((s=sys_irqenable(&re_state.re_hook_id)) != OK) - printf("RTL8139: error, couldn't enable interrupts: %d\n", s); -} - /*===========================================================================* * rl_handler * *===========================================================================*/ @@ -1716,10 +1254,6 @@ static int rl_handler(re_t *rep) int i, port, tx_head, tx_tail, link_up; u16_t isr, tsad; u32_t tsd, tcr, ertxth; -#if 0 - u8_t cr; -#endif - int_event_check = FALSE; /* disable check by default */ port= rep->re_base_port; @@ -1746,7 +1280,6 @@ static int rl_handler(re_t *rep) { rep->re_report_link= TRUE; rep->re_got_int= TRUE; - int_event_check = TRUE; } } if (isr & RL_IMR_RXOVW) @@ -1756,40 +1289,14 @@ static int rl_handler(re_t *rep) /* Clear the receive buffer */ rep->re_clear_rx= TRUE; rep->re_got_int= TRUE; - int_event_check = TRUE; } if (isr & (RL_ISR_RER | RL_ISR_ROK)) { isr &= ~(RL_ISR_RER | RL_ISR_ROK); - if (!rep->re_got_int && (rep->re_flags & REF_READING)) - { - rep->re_got_int= TRUE; - int_event_check = TRUE; - } + rep->re_got_int= TRUE; } -#if 0 - if ((isr & (RL_ISR_TER | RL_ISR_TOK)) && - (rep->re_flags & REF_SEND_AVAIL) && - (rep->re_tx[0].ret_busy || rep->re_tx[1].ret_busy || - rep->re_tx[2].ret_busy || rep->re_tx[3].ret_busy)) - - { - printf( - "rl_handler, SEND_AVAIL: tx_head %d, tx_tail %d, busy: %d %d %d %d\n", - rep->re_tx_head, rep->re_tx_tail, - rep->re_tx[0].ret_busy, rep->re_tx[1].ret_busy, - rep->re_tx[2].ret_busy, rep->re_tx[3].ret_busy); - printf( - "rl_handler: TSAD: 0x%04x, TSD: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n", - rl_inw(port, RL_TSAD), - rl_inl(port, RL_TSD0+0*4), - rl_inl(port, RL_TSD0+1*4), - rl_inl(port, RL_TSD0+2*4), - rl_inl(port, RL_TSD0+3*4)); - } -#endif if ((isr & (RL_ISR_TER | RL_ISR_TOK)) || 1) { isr &= ~(RL_ISR_TER | RL_ISR_TOK); @@ -1798,41 +1305,6 @@ static int rl_handler(re_t *rep) if (tsad & (RL_TSAD_TABT0|RL_TSAD_TABT1| RL_TSAD_TABT2|RL_TSAD_TABT3)) { -#if 0 - /* Do we need a watch dog? */ - /* Just reset the whole chip */ - rep->re_need_reset= TRUE; - rep->re_got_int= TRUE; - int_event_check = TRUE; -#elif 0 - /* Reset transmitter */ - rep->re_stat.ets_transAb++; - - cr= rl_inb(port, RL_CR); - cr &= ~RL_CR_TE; - rl_outb(port, RL_CR, cr); - SPIN_UNTIL(!(rl_inb(port, RL_CR) & RL_CR_TE), 1000000); - if (rl_inb(port, RL_CR) & RL_CR_TE) { - panic("cannot disable transmitter"); - } - rl_outb(port, RL_CR, cr | RL_CR_TE); - - tcr= rl_inl(port, RL_TCR); - rl_outl(port, RL_TCR, tcr | RL_TCR_IFG_STD); - - printf("rl_handler: reset after abort\n"); - - if (rep->re_flags & REF_SEND_AVAIL) - { - printf("rl_handler: REF_SEND_AVAIL\n"); - rep->re_send_int= TRUE; - rep->re_got_int= TRUE; - int_event_check = TRUE; - } - for (i= 0; i< N_TX_BUF; i++) - rep->re_tx[i].ret_busy= FALSE; - rep->re_tx_head= 0; -#else printf("rl_handler, TABT, tasd = 0x%04x\n", tsad); @@ -1862,7 +1334,6 @@ static int rl_handler(re_t *rep) rep->re_stat.ets_transAb++; tcr= rl_inl(port, RL_TCR); rl_outl(port, RL_TCR, tcr | RL_TCR_CLRABT); -#endif } /* Transmit completed */ @@ -1923,7 +1394,8 @@ static int rl_handler(re_t *rep) /* Increase ERTXTH */ ertxth= tsd + (1 << RL_TSD_ERTXTH_S); ertxth &= RL_TSD_ERTXTH_M; - if (debug && ertxth > rep->re_ertxth) +#if VERBOSE + if (ertxth > rep->re_ertxth) { printf("%s: new ertxth: %d bytes\n", rep->re_name, @@ -1931,19 +1403,18 @@ static int rl_handler(re_t *rep) 32); rep->re_ertxth= ertxth; } +#endif } rep->re_tx[tx_tail].ret_busy= FALSE; + rep->re_tx_busy--; #if 0 - if (rep->re_flags & REF_SEND_AVAIL) - { printf("TSD%d: %08lx\n", tx_tail, tsd); printf( - "rl_handler: head %d, tail %d, busy: %d %d %d %d\n", + "rl_handler: head %d, tail %d, busy: %d %d %d %d\n", tx_head, tx_tail, - rep->re_tx[0].ret_busy, rep->re_tx[1].ret_busy, + rep->re_tx[0].ret_busy, rep->re_tx[1].ret_busy, rep->re_tx[2].ret_busy, rep->re_tx[3].ret_busy); - } #endif if (++tx_tail >= N_TX_BUF) @@ -1951,18 +1422,9 @@ static int rl_handler(re_t *rep) assert(tx_tail < RL_N_TX); rep->re_tx_tail= tx_tail; - if (rep->re_flags & REF_SEND_AVAIL) - { -#if 0 - printf("rl_handler: REF_SEND_AVAIL\n"); -#endif - rep->re_send_int= TRUE; - if (!rep->re_got_int) - { - rep->re_got_int= TRUE; - int_event_check = TRUE; - } - } + rep->re_send_int= TRUE; + rep->re_got_int= TRUE; + rep->re_tx_alive= TRUE; } assert(i < 2*N_TX_BUF); } @@ -1976,20 +1438,19 @@ static int rl_handler(re_t *rep) } /*===========================================================================* - * rl_watchdog_f * + * rl_alarm * *===========================================================================*/ -static void rl_watchdog_f(tp) -minix_timer_t *tp; +static void rl_alarm(clock_t __unused stamp) { re_t *rep; + /* Use a synchronous alarm instead of a watchdog timer. */ - sys_setalarm(system_hz, 0); + sys_setalarm(sys_hz(), 0); rep= &re_state; - if (rep->re_mode != REM_ENABLED) - return; - if (!(rep->re_flags & REF_SEND_AVAIL)) + assert(rep->re_tx_busy >= 0 && rep->re_tx_busy <= N_TX_BUF); + if (rep->re_tx_busy == 0) { /* Assume that an idle system is alive */ rep->re_tx_alive= TRUE; @@ -2000,7 +1461,7 @@ minix_timer_t *tp; rep->re_tx_alive= FALSE; return; } - printf("rl_watchdog_f: resetting instance %d\n", re_instance); + printf("rl_alarm: resetting instance %d\n", re_instance); printf("TSAD: 0x%04x, TSD: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n", rl_inw(rep->re_base_port, RL_TSAD), rl_inl(rep->re_base_port, RL_TSD0+0*4), @@ -2013,242 +1474,13 @@ minix_timer_t *tp; rep->re_tx[2].ret_busy, rep->re_tx[3].ret_busy); rep->re_need_reset= TRUE; rep->re_got_int= TRUE; - - check_int_events(); + + rl_check_ints(rep); } -#if 0 - -static void rtl_init(struct dpeth *dep); -static u16_t get_ee_word(dpeth_t *dep, int a); -static void ee_wen(dpeth_t *dep); -static void set_ee_word(dpeth_t *dep, int a, u16_t w); -static void ee_wds(dpeth_t *dep); - -static void rtl_init(dep) -dpeth_t *dep; -{ - u8_t reg_a, reg_b, cr, config0, config2, config3; - int i; - char val[128]; - - printf("rtl_init called\n"); - ne_init(dep); - - /* ID */ - outb_reg0(dep, DP_CR, CR_PS_P0); - reg_a = inb_reg0(dep, DP_DUM1); - reg_b = inb_reg0(dep, DP_DUM2); - - printf("rtl_init: '%c', '%c'\n", reg_a, reg_b); - - outb_reg0(dep, DP_CR, CR_PS_P3); - config0 = inb_reg3(dep, 3); - config2 = inb_reg3(dep, 5); - config3 = inb_reg3(dep, 6); - outb_reg0(dep, DP_CR, CR_PS_P0); - - printf("rtl_init: config 0/2/3 = %x/%x/%x\n", - config0, config2, config3); - - if (0 == sys_getkenv("RTL8029FD",9+1, val, sizeof(val))) - { - printf("rtl_init: setting full-duplex mode\n"); - outb_reg0(dep, DP_CR, CR_PS_P3); - - cr= inb_reg3(dep, 1); - outb_reg3(dep, 1, cr | 0xc0); - - outb_reg3(dep, 6, config3 | 0x40); - config3 = inb_reg3(dep, 6); - - config2= inb_reg3(dep, 5); - outb_reg3(dep, 5, config2 | 0x20); - config2= inb_reg3(dep, 5); - - outb_reg3(dep, 1, cr); - - outb_reg0(dep, DP_CR, CR_PS_P0); - - printf("rtl_init: config 2 = %x\n", config2); - printf("rtl_init: config 3 = %x\n", config3); - } - - for (i= 0; i<64; i++) - printf("%x ", get_ee_word(dep, i)); - printf("\n"); - - if (0 == sys_getkenv("RTL8029MN",9+1, val, sizeof(val))) - { - ee_wen(dep); - - set_ee_word(dep, 0x78/2, 0x10ec); - set_ee_word(dep, 0x7A/2, 0x8029); - set_ee_word(dep, 0x7C/2, 0x10ec); - set_ee_word(dep, 0x7E/2, 0x8029); - - ee_wds(dep); - - assert(get_ee_word(dep, 0x78/2) == 0x10ec); - assert(get_ee_word(dep, 0x7A/2) == 0x8029); - assert(get_ee_word(dep, 0x7C/2) == 0x10ec); - assert(get_ee_word(dep, 0x7E/2) == 0x8029); - } - - if (0 == sys_getkenv("RTL8029XXX",10+1, val, sizeof(val))) - { - ee_wen(dep); - - set_ee_word(dep, 0x76/2, 0x8029); - - ee_wds(dep); - - assert(get_ee_word(dep, 0x76/2) == 0x8029); - } -} - -static u16_t get_ee_word(dep, a) -dpeth_t *dep; -int a; -{ - int b, i, cmd; - u16_t w; - - outb_reg0(dep, DP_CR, CR_PS_P3); /* Bank 3 */ - - /* Switch to 9346 mode and enable CS */ - outb_reg3(dep, 1, 0x80 | 0x8); - - cmd= 0x180 | (a & 0x3f); /* 1 1 0 a5 a4 a3 a2 a1 a0 */ - for (i= 8; i >= 0; i--) - { - b= (cmd & (1 << i)); - b= (b ? 2 : 0); - - /* Cmd goes out on the rising edge of the clock */ - outb_reg3(dep, 1, 0x80 | 0x8 | b); - outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b); - } - outb_reg3(dep, 1, 0x80 | 0x8); /* End of cmd */ - - w= 0; - for (i= 0; i<16; i++) - { - w <<= 1; - - /* Data is shifted out on the rising edge. Read at the - * falling edge. - */ - outb_reg3(dep, 1, 0x80 | 0x8 | 0x4); - outb_reg3(dep, 1, 0x80 | 0x8 | b); - b= inb_reg3(dep, 1); - w |= (b & 1); - } - - outb_reg3(dep, 1, 0x80); /* drop CS */ - outb_reg3(dep, 1, 0x00); /* back to normal */ - outb_reg0(dep, DP_CR, CR_PS_P0); /* back to bank 0 */ - - return w; -} - -static void ee_wen(dep) -dpeth_t *dep; -{ - int b, i, cmd; - u16_t w; - - outb_reg0(dep, DP_CR, CR_PS_P3); /* Bank 3 */ - - /* Switch to 9346 mode and enable CS */ - outb_reg3(dep, 1, 0x80 | 0x8); - - cmd= 0x130; /* 1 0 0 1 1 x x x x */ - for (i= 8; i >= 0; i--) - { - b= (cmd & (1 << i)); - b= (b ? 2 : 0); - - /* Cmd goes out on the rising edge of the clock */ - outb_reg3(dep, 1, 0x80 | 0x8 | b); - outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b); - } - outb_reg3(dep, 1, 0x80 | 0x8); /* End of cmd */ - outb_reg3(dep, 1, 0x80); /* Drop CS */ - /* micro_delay(1); */ /* Is this required? */ -} - -static void set_ee_word(dpeth_t *dep, int a, u16_t w) -dpeth_t *dep; -int a; -u16_t w; -{ - int b, i, cmd; - - outb_reg3(dep, 1, 0x80 | 0x8); /* Set CS */ - - cmd= 0x140 | (a & 0x3f); /* 1 0 1 a5 a4 a3 a2 a1 a0 */ - for (i= 8; i >= 0; i--) - { - b= (cmd & (1 << i)); - b= (b ? 2 : 0); - - /* Cmd goes out on the rising edge of the clock */ - outb_reg3(dep, 1, 0x80 | 0x8 | b); - outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b); - } - for (i= 15; i >= 0; i--) - { - b= (w & (1 << i)); - b= (b ? 2 : 0); - - /* Cmd goes out on the rising edge of the clock */ - outb_reg3(dep, 1, 0x80 | 0x8 | b); - outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b); - } - outb_reg3(dep, 1, 0x80 | 0x8); /* End of data */ - outb_reg3(dep, 1, 0x80); /* Drop CS */ - /* micro_delay(1); */ /* Is this required? */ - outb_reg3(dep, 1, 0x80 | 0x8); /* Set CS */ - SPIN_UNTIL(inb_reg3(dep, 1) & 1, 10000); - if (!(inb_reg3(dep, 1) & 1)) - panic("device remains busy"); -} - -static void ee_wds(dep) -dpeth_t *dep; -{ - int b, i, cmd; - u16_t w; - - outb_reg0(dep, DP_CR, CR_PS_P3); /* Bank 3 */ - - /* Switch to 9346 mode and enable CS */ - outb_reg3(dep, 1, 0x80 | 0x8); - - cmd= 0x100; /* 1 0 0 0 0 x x x x */ - for (i= 8; i >= 0; i--) - { - b= (cmd & (1 << i)); - b= (b ? 2 : 0); - - /* Cmd goes out on the rising edge of the clock */ - outb_reg3(dep, 1, 0x80 | 0x8 | b); - outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b); - } - outb_reg3(dep, 1, 0x80 | 0x8); /* End of cmd */ - outb_reg3(dep, 1, 0x80); /* Drop CS */ - outb_reg3(dep, 1, 0x00); /* back to normal */ - outb_reg0(dep, DP_CR, CR_PS_P0); /* back to bank 0 */ -} -#endif - -static void tell_dev(buf, size, pci_bus, pci_dev, pci_func) -vir_bytes buf; -size_t size; -int pci_bus; -int pci_dev; -int pci_func; +/* TODO: obviously this needs a lot of work. */ +static void tell_iommu(vir_bytes buf, size_t size, int pci_bus, int pci_dev, + int pci_func) { int r; endpoint_t dev_e; @@ -2258,9 +1490,8 @@ int pci_func; if (r != OK) { #if 0 - printf( - "rtl8139`tell_dev: ds_retrieve_label_endpt failed for 'amddev': %d\n", - r); + printf("rtl8139`tell_dev: ds_retrieve_label_endpt failed " + "for 'amddev': %d\n", r); #endif return; } diff --git a/minix/drivers/net/rtl8139/rtl8139.h b/minix/drivers/net/rtl8139/rtl8139.h index 85d472ce2..19b995287 100644 --- a/minix/drivers/net/rtl8139/rtl8139.h +++ b/minix/drivers/net/rtl8139/rtl8139.h @@ -6,32 +6,9 @@ Created: Aug 2003 by Philip Homburg #include #include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include - -#include -#include +#include #include -#include -#include -#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 $ diff --git a/minix/drivers/net/rtl8169/Makefile b/minix/drivers/net/rtl8169/Makefile index e45e7843f..f68d31910 100644 --- a/minix/drivers/net/rtl8169/Makefile +++ b/minix/drivers/net/rtl8169/Makefile @@ -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 diff --git a/minix/drivers/net/rtl8169/rtl8169.c b/minix/drivers/net/rtl8169/rtl8169.c index 420736e30..47c7bcab9 100644 --- a/minix/drivers/net/rtl8169/rtl8169.c +++ b/minix/drivers/net/rtl8169/rtl8169.c @@ -9,39 +9,19 @@ #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include - -#include #include -#include -#include "kernel/const.h" -#include "kernel/config.h" -#include "kernel/type.h" - -#define VERBOSE 0 /* display message during init */ #include "rtl8169.h" -#define IOVEC_NR 16 /* I/O vectors are handled IOVEC_NR entries at a time. */ +#define VERBOSE 0 /* display message during init */ -#define RE_DTCC_VALUE 600 /* DTCC Update after every 10 minutes */ +#define RE_DTCC_VALUE 600 /* DTCC Update once every 10 minutes */ #define RX_CONFIG_MASK 0xff7e1880 /* Clears the bits supported by chip */ -#define RE_INTR_MASK (RL_IMR_TDU | RL_IMR_FOVW | RL_IMR_PUN | RL_IMR_RDU | RL_IMR_TER | RL_IMR_TOK | RL_IMR_RER | RL_IMR_ROK) +#define RE_INTR_MASK (RL_IMR_TDU | RL_IMR_FOVW | RL_IMR_PUN | RL_IMR_RDU | \ + RL_IMR_TER | RL_IMR_TOK | RL_IMR_RER | RL_IMR_ROK) #define RL_ENVVAR "RTLETH" /* Configuration */ @@ -63,14 +43,14 @@ typedef struct re_dtcc u32_t TxEr_high; /* high 32-bits of Tx errors */ u32_t RxEr; /* Rx errors */ u16_t MissPkt; /* Missed packets */ - u16_t FAE; /* Frame Aignment Error packets (MII mode only) */ - u32_t Tx1Col; /* Tx Ok packets with only 1 collision happened before Tx Ok */ - u32_t TxMCol; /* Tx Ok packets with > 1 and < 16 collisions happened before Tx Ok */ - u32_t RxOkPhy_low; /* low 32-bits of Rx Ok packets with physical addr destination ID */ - u32_t RxOkPhy_high; /* high 32-bits of Rx Ok packets with physical addr destination ID */ - u32_t RxOkBrd_low; /* low 32-bits of Rx Ok packets with broadcast destination ID */ - u32_t RxOkBrd_high; /* high 32-bits of Rx Ok packets with broadcast destination ID */ - u32_t RxOkMul; /* Rx Ok Packets with multicast destination ID */ + u16_t FAE; /* Frame Alignment Error packets (MII only) */ + u32_t Tx1Col; /* Tx Ok packets with 1 collision before Tx */ + u32_t TxMCol; /* Tx Ok packets with 2..15 collisions */ + u32_t RxOkPhy_low; /* low 32-bits of Rx Ok packets for us */ + u32_t RxOkPhy_high; /* high 32-bits of Rx Ok packets for us */ + u32_t RxOkBrd_low; /* low 32-bits of Rx Ok broadcast packets */ + u32_t RxOkBrd_high; /* high 32-bits of Rx Ok broadcast packets */ + u32_t RxOkMul; /* Rx Ok multicast packets */ u16_t TxAbt; /* Tx abort packets */ u16_t TxUndrn; /* Tx underrun packets */ } re_dtcc; @@ -79,27 +59,22 @@ typedef struct re { port_t re_base_port; int re_irq; int re_mode; - int re_flags; - endpoint_t re_client; int re_link_up; int re_got_int; int re_send_int; int re_report_link; int re_need_reset; int re_tx_alive; - int setup; u32_t re_mac; - char *re_model; + const char *re_model; /* Rx */ int re_rx_head; struct { - int ret_busy; phys_bytes ret_buf; char *v_ret_buf; } re_rx[N_RX_DESC]; - vir_bytes re_read_s; re_desc *re_rx_desc; /* Rx descriptor buffer */ phys_bytes p_rx_desc; /* Rx descriptor buffer physical */ @@ -112,38 +87,16 @@ typedef struct re { } re_tx[N_TX_DESC]; re_desc *re_tx_desc; /* Tx descriptor buffer */ phys_bytes p_tx_desc; /* Tx descriptor buffer physical */ + int re_tx_busy; /* how many Tx descriptors are busy? */ - /* 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; phys_bytes dtcc_buf; /* Dump Tally Counter buffer physical */ re_dtcc *v_dtcc_buf; /* Dump Tally Counter buffer */ u32_t dtcc_counter; /* DTCC update counter */ - ether_addr_t re_address; - message re_rx_mess; - message re_tx_mess; char re_name[sizeof("rtl8169#n")]; - iovec_t re_iovec[IOVEC_NR]; - iovec_s_t re_iovec_s[IOVEC_NR]; u32_t interrupts; -} -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; static re_t re_state; @@ -202,167 +155,102 @@ static void my_outl(u16_t port, u32_t value) #define rl_outw(port, offset, value) (my_outw((port) + (offset), (value))) #define rl_outl(port, offset, value) (my_outl((port) + (offset), (value))) -static void rl_init(message *mp); -static void rl_pci_conf(void); -static int rl_probe(re_t *rep, int skip); -static void rl_conf_hw(re_t *rep); +static int rl_init(unsigned int instance, ether_addr_t *addr); +static int rl_probe(re_t *rep, unsigned int skip); static void rl_init_buf(re_t *rep); -static void rl_init_hw(re_t *rep); +static void rl_init_hw(re_t *rep, ether_addr_t *addr); static void rl_reset_hw(re_t *rep); -static void rl_confaddr(re_t *rep); +static void rl_confaddr(re_t *rep, ether_addr_t *addr); +static void rl_stop(void); static void rl_rec_mode(re_t *rep); -static void rl_readv_s(const message *mp, int from_int); -static void rl_writev_s(const message *mp, int from_int); +static void rl_mode(unsigned int mode); +static ssize_t rl_recv(struct netdriver_data *data, size_t max); +static int rl_send(struct netdriver_data *data, size_t size); +static void rl_intr(unsigned int mask); static void rl_check_ints(re_t *rep); -static void rl_report_link(re_t *rep); static void rl_do_reset(re_t *rep); -static void rl_getstat_s(message *mp); -static void reply(re_t *rep); -static void mess_reply(message *req, message *reply); -static void check_int_events(void); -static void do_hard_int(void); +static void rl_stat(eth_stat_t *stat); +#if VERBOSE +static void rl_report_link(re_t *rep); static void dump_phy(const re_t *rep); +#endif static void rl_handler(re_t *rep); -static void rl_watchdog_f(minix_timer_t *tp); +static void rl_alarm(clock_t stamp); -/* - * The message used in the main loop is made global, so that rl_watchdog_f() - * can change its message type to fake an interrupt message. - */ -static message m; -static int int_event_check; /* set to TRUE if events arrived */ - -u32_t system_hz; - -/* 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); +static const struct netdriver rl_table = { + .ndr_init = rl_init, + .ndr_stop = rl_stop, + .ndr_mode = rl_mode, + .ndr_recv = rl_recv, + .ndr_send = rl_send, + .ndr_stat = rl_stat, + .ndr_intr = rl_intr, + .ndr_alarm = rl_alarm +}; /*===========================================================================* * main * *===========================================================================*/ int main(int argc, char *argv[]) { - int r; - int ipc_status; - - /* SEF local startup. */ env_setargs(argc, argv); - sef_local_startup(); - while (TRUE) { - if ((r = netdriver_receive(ANY, &m, &ipc_status)) != OK) - panic("netdriver_receive failed: %d", r); + netdriver_task(&rl_table); - if (is_ipc_notify(ipc_status)) { - switch (_ENDPOINT_P(m.m_source)) { - case CLOCK: - /* - * Under MINIX, synchronous alarms are used - * instead of watchdog functions. - * The approach is very different: MINIX VMD - * timeouts are handled within the kernel - * (the watchdog is executed by CLOCK), and - * notify() the driver in some cases. MINIX - * timeouts result in a SYN_ALARM message to - * the driver and thus are handled where they - * should be handled. Locally, watchdog - * functions are used again. - */ - rl_watchdog_f(NULL); - break; - case HARDWARE: - do_hard_int(); - if (int_event_check) { - check_int_events(); - } - break ; - default: - panic("illegal notify from: %d", m.m_type); - } - - /* done, get nwe message */ - continue; - } - - switch (m.m_type) { - case DL_WRITEV_S: rl_writev_s(&m, FALSE); break; - case DL_READV_S: rl_readv_s(&m, FALSE); break; - case DL_CONF: rl_init(&m); break; - case DL_GETSTAT_S: rl_getstat_s(&m); break; - default: - panic("illegal message: %d", m.m_type); - } - } + return 0; } /*===========================================================================* - * sef_local_startup * + * rl_init * *===========================================================================*/ -static void sef_local_startup() -{ - /* Register init callbacks. */ - sef_setcb_init_fresh(sef_cb_init_fresh); - sef_setcb_init_lu(sef_cb_init_fresh); - sef_setcb_init_restart(sef_cb_init_fresh); - - /* Register live update callbacks. */ - sef_setcb_lu_prepare(sef_cb_lu_prepare_always_ready); - sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid_workfree); - - /* Register signal callbacks. */ - sef_setcb_signal_handler(sef_cb_signal_handler); - - /* Let SEF perform startup. */ - sef_startup(); -} - -/*===========================================================================* - * sef_cb_init_fresh * - *===========================================================================*/ -static int sef_cb_init_fresh(int type, sef_init_info_t *UNUSED(info)) +static int rl_init(unsigned int instance, ether_addr_t *addr) { /* Initialize the rtl8169 driver. */ - long v; + re_t *rep; - system_hz = sys_hz(); + /* Initialize driver state. */ + rep = &re_state; + memset(rep, 0, sizeof(*rep)); - v = 0; - (void) env_parse("instance", "d", 0, &v, 0, 255); - re_instance = (int) v; + strlcpy(rep->re_name, "rtl8169#0", sizeof(rep->re_name)); + rep->re_name[8] += re_instance; + + re_instance = instance; + + /* Try to find a matching device. */ + if (!rl_probe(rep, instance)) + return ENXIO; /* Claim buffer memory now. */ rl_init_buf(&re_state); - /* Announce we are up! */ - netdriver_announce(); + /* Initialize the device we found. */ + rl_init_hw(rep, addr); - return(OK); + /* Use a synchronous alarm instead of a watchdog timer. */ + sys_setalarm(sys_hz(), 0); + + return OK; } /*===========================================================================* - * sef_cb_signal_handler * + * rl_stop * *===========================================================================*/ -static void sef_cb_signal_handler(int signo) +static void rl_stop(void) { re_t *rep; - /* Only check for termination signal, ignore anything else. */ - if (signo != SIGTERM) return; - rep = &re_state; - if (rep->re_mode == REM_ENABLED) - rl_outb(rep->re_base_port, RL_CR, RL_CR_RST); - exit(0); + rl_outb(rep->re_base_port, RL_CR, RL_CR_RST); } static void mdio_write(u16_t port, int regaddr, int value) { int i; - rl_outl(port, RL_PHYAR, 0x80000000 | (regaddr & 0x1F) << 16 | (value & 0xFFFF)); + rl_outl(port, RL_PHYAR, + 0x80000000 | (regaddr & 0x1F) << 16 | (value & 0xFFFF)); for (i = 20; i > 0; i--) { /* @@ -396,24 +284,6 @@ static int mdio_read(u16_t port, int regaddr) return value; } -/*===========================================================================* - * check_int_events * - *===========================================================================*/ -static void check_int_events(void) -{ - re_t *rep; - - rep = &re_state; - - if (rep->re_mode != REM_ENABLED) - return; - if (!rep->re_got_int) - return; - rep->re_got_int = 0; - assert(rep->re_flags & REF_ENABLED); - rl_check_ints(rep); -} - static void rtl8169_update_stat(re_t *rep) { port_t port; @@ -454,12 +324,6 @@ static void rtl8169_dump(void) rep = &re_state; printf("\n"); - if (rep->re_mode == REM_DISABLED) - printf("Realtek RTL 8169 instance %d is disabled\n", - re_instance); - - if (rep->re_mode != REM_ENABLED) - return; rtl8169_update_stat(rep); @@ -484,135 +348,75 @@ static void rtl8169_dump(void) printf("fifoUnder :%8ld\t", rep->re_stat.ets_fifoUnder); printf("fifoOver :%8ld\t", rep->re_stat.ets_fifoOver); printf("OWC :%8ld\n", rep->re_stat.ets_OWC); - printf("interrupts :%8lu\n", rep->interrupts); + printf("interrupts :%8u\n", rep->interrupts); printf("\nRealtek RTL 8169 Tally Counters:\n"); dtcc = rep->v_dtcc_buf; if (dtcc->TxOk_high) - printf("TxOk :%8ld%08ld\t", dtcc->TxOk_high, dtcc->TxOk_low); + printf("TxOk :%8u%08u\t", + dtcc->TxOk_high, dtcc->TxOk_low); else - printf("TxOk :%16lu\t", dtcc->TxOk_low); + printf("TxOk :%16u\t", dtcc->TxOk_low); if (dtcc->RxOk_high) - printf("RxOk :%8ld%08ld\n", dtcc->RxOk_high, dtcc->RxOk_low); + printf("RxOk :%8u%08u\n", + dtcc->RxOk_high, dtcc->RxOk_low); else - printf("RxOk :%16lu\n", dtcc->RxOk_low); + printf("RxOk :%16u\n", dtcc->RxOk_low); if (dtcc->TxEr_high) - printf("TxEr :%8ld%08ld\t", dtcc->TxEr_high, dtcc->TxEr_low); + printf("TxEr :%8u%08u\t", + dtcc->TxEr_high, dtcc->TxEr_low); else - printf("TxEr :%16ld\t", dtcc->TxEr_low); + printf("TxEr :%16u\t", dtcc->TxEr_low); - printf("RxEr :%16ld\n", dtcc->RxEr); + printf("RxEr :%16u\n", dtcc->RxEr); - printf("Tx1Col :%16ld\t", dtcc->Tx1Col); - printf("TxMCol :%16ld\n", dtcc->TxMCol); + printf("Tx1Col :%16u\t", dtcc->Tx1Col); + printf("TxMCol :%16u\n", dtcc->TxMCol); if (dtcc->RxOkPhy_high) - printf("RxOkPhy :%8ld%08ld\t", dtcc->RxOkPhy_high, dtcc->RxOkPhy_low); + printf("RxOkPhy :%8u%08u\t", + dtcc->RxOkPhy_high, dtcc->RxOkPhy_low); else - printf("RxOkPhy :%16ld\t", dtcc->RxOkPhy_low); + printf("RxOkPhy :%16u\t", dtcc->RxOkPhy_low); if (dtcc->RxOkBrd_high) - printf("RxOkBrd :%8ld%08ld\n", dtcc->RxOkBrd_high, dtcc->RxOkBrd_low); + printf("RxOkBrd :%8u%08u\n", + dtcc->RxOkBrd_high, dtcc->RxOkBrd_low); else - printf("RxOkBrd :%16ld\n", dtcc->RxOkBrd_low); + printf("RxOkBrd :%16u\n", dtcc->RxOkBrd_low); - printf("RxOkMul :%16ld\t", dtcc->RxOkMul); + printf("RxOkMul :%16u\t", dtcc->RxOkMul); printf("MissPkt :%16d\n", dtcc->MissPkt); printf("\nRealtek RTL 8169 Miscellaneous Info:\n"); - printf("re_flags : 0x%08x\n", rep->re_flags); printf("tx_head :%8d busy %d\t", rep->re_tx_head, rep->re_tx[rep->re_tx_head].ret_busy); } #endif /*===========================================================================* - * do_init * + * rl_mode * *===========================================================================*/ -static void rl_init(mp) -message *mp; +static void rl_mode(unsigned int mode) { - static int first_time = 1; - re_t *rep; - message reply_mess; - - if (first_time) { - first_time = 0; - rl_pci_conf(); /* Configure PCI devices. */ - - /* Use a synchronous alarm instead of a watchdog timer. */ - sys_setalarm(system_hz, 0); - } rep = &re_state; - if (rep->re_mode == REM_DISABLED) { - /* This is the default, try to (re)locate the device. */ - rl_conf_hw(rep); - if (rep->re_mode == REM_DISABLED) { - /* Probe failed, or the device is configured off. */ - reply_mess.m_type = DL_CONF_REPLY; - reply_mess.m_netdrv_net_dl_conf.stat = ENXIO; - mess_reply(mp, &reply_mess); - return; - } - if (rep->re_mode == REM_ENABLED) - rl_init_hw(rep); - } - assert(rep->re_mode == REM_ENABLED); - assert(rep->re_flags & REF_ENABLED); - - rep->re_flags &= ~(REF_PROMISC | REF_MULTI | REF_BROAD); - - if (mp->m_net_netdrv_dl_conf.mode & DL_PROMISC_REQ) - rep->re_flags |= REF_PROMISC; - if (mp->m_net_netdrv_dl_conf.mode & DL_MULTI_REQ) - rep->re_flags |= REF_MULTI; - if (mp->m_net_netdrv_dl_conf.mode & DL_BROAD_REQ) - rep->re_flags |= REF_BROAD; + rep->re_mode = mode; rl_rec_mode(rep); - - reply_mess.m_type = DL_CONF_REPLY; - reply_mess.m_netdrv_net_dl_conf.stat = OK; - memcpy(reply_mess.m_netdrv_net_dl_conf.hw_addr, - rep->re_address.ea_addr, - sizeof(reply_mess.m_netdrv_net_dl_conf.hw_addr)); - - mess_reply(mp, &reply_mess); -} - -/*===========================================================================* - * rl_pci_conf * - *===========================================================================*/ -static void rl_pci_conf() -{ - re_t *rep; - - rep = &re_state; - - strlcpy(rep->re_name, "rtl8169#0", sizeof(rep->re_name)); - rep->re_name[8] += re_instance; - rep->re_seen = FALSE; - - pci_init(); - - if (rl_probe(rep, re_instance)) - rep->re_seen = TRUE; } /*===========================================================================* * rl_probe * *===========================================================================*/ -static int rl_probe(rep, skip) -re_t *rep; -int skip; +static int rl_probe(re_t *rep, unsigned int skip) { int r, devind; u16_t vid, did; @@ -622,6 +426,8 @@ int skip; char *dname; #endif + pci_init(); + r = pci_first_dev(&devind, &vid, &did); if (r == 0) return 0; @@ -657,40 +463,10 @@ int skip; return TRUE; } -/*===========================================================================* - * rl_conf_hw * - *===========================================================================*/ -static void rl_conf_hw(rep) -re_t *rep; -{ - static eth_stat_t empty_stat = {0, 0, 0, 0, 0, 0 /* ,... */ }; - - rep->re_mode = REM_DISABLED; /* Superfluous */ - - if (rep->re_seen) - rep->re_mode = REM_ENABLED; /* PCI device is present */ - if (rep->re_mode != REM_ENABLED) - return; - - rep->re_flags = REF_EMPTY; - rep->re_link_up = 0; - rep->re_got_int = 0; - rep->re_send_int = 0; - rep->re_report_link = 0; - rep->re_need_reset = 0; - rep->re_tx_alive = 0; - rep->re_rx_head = 0; - rep->re_read_s = 0; - rep->re_tx_head = 0; - rep->re_stat = empty_stat; - rep->dtcc_counter = 0; -} - /*===========================================================================* * rl_init_buf * *===========================================================================*/ -static void rl_init_buf(rep) -re_t *rep; +static void rl_init_buf(re_t *rep) { size_t rx_bufsize, tx_bufsize, rx_descsize, tx_descsize, tot_bufsize; struct re_desc *desc; @@ -698,8 +474,6 @@ re_t *rep; char *mallocbuf; int d; - assert(!rep->setup); - /* Allocate receive and transmit descriptors */ rx_descsize = (N_RX_DESC * sizeof(struct re_desc)); tx_descsize = (N_TX_DESC * sizeof(struct re_desc)); @@ -742,10 +516,12 @@ re_t *rep; mallocbuf += rx_bufsize; /* Setting Rx descriptor */ - if (d == (N_RX_DESC - 1)) /* Last descriptor? if so, set the EOR bit */ - desc->status = DESC_EOR | DESC_OWN | (RX_BUFSIZE & DESC_RX_LENMASK); + if (d == (N_RX_DESC - 1)) /* Last descriptor: set EOR bit */ + desc->status = DESC_EOR | DESC_OWN | + (RX_BUFSIZE & DESC_RX_LENMASK); else - desc->status = DESC_OWN | (RX_BUFSIZE & DESC_RX_LENMASK); + desc->status = DESC_OWN | + (RX_BUFSIZE & DESC_RX_LENMASK); desc->addr_low = rep->re_rx[d].ret_buf; desc++; @@ -762,28 +538,23 @@ re_t *rep; desc->addr_low = rep->re_tx[d].ret_buf; desc++; } + rep->re_tx_busy = 0; /* Dump Tally Counter buffer */ rep->dtcc_buf = buf; rep->v_dtcc_buf = (re_dtcc *)mallocbuf; - - rep->setup = 1; } /*===========================================================================* * rl_init_hw * *===========================================================================*/ -static void rl_init_hw(rep) -re_t *rep; +static void rl_init_hw(re_t *rep, ether_addr_t *addr) { int s; #if VERBOSE int i; #endif - rep->re_flags = REF_EMPTY; - rep->re_flags |= REF_ENABLED; - /* * Set the interrupt handler. The policy is to only send HARD_INT * notifications. Don't reenable interrupts automatically. The id @@ -803,11 +574,12 @@ re_t *rep; rep->re_name, rep->re_model, rep->re_mac); #endif - rl_confaddr(rep); + rl_confaddr(rep, addr); + #if VERBOSE printf("%s: Ethernet address ", rep->re_name); for (i = 0; i < 6; i++) { - printf("%x%c", rep->re_address.ea_addr[i], + printf("%x%c", addr->ea_addr[i], i < 5 ? ':' : '\n'); } #endif @@ -920,8 +692,7 @@ static void rtl8169scd_phy_config(port_t port) /*===========================================================================* * rl_reset_hw * *===========================================================================*/ -static void rl_reset_hw(rep) -re_t *rep; +static void rl_reset_hw(re_t *rep) { port_t port; u32_t t; @@ -996,7 +767,8 @@ re_t *rep; micro_delay(100); } - t = mdio_read(port, MII_CTRL) | MII_CTRL_ANE | MII_CTRL_DM | MII_CTRL_SP_1000; + t = mdio_read(port, MII_CTRL); + t |= MII_CTRL_ANE | MII_CTRL_DM | MII_CTRL_SP_1000; mdio_write(port, MII_CTRL, t); t = mdio_read(port, MII_ANA); @@ -1056,12 +828,10 @@ re_t *rep; /*===========================================================================* * rl_confaddr * *===========================================================================*/ -static void rl_confaddr(rep) -re_t *rep; +static void rl_confaddr(re_t *rep, ether_addr_t *addr) { static char eakey[] = RL_ENVVAR "#_EA"; static char eafmt[] = "x:x:x:x:x:x"; - int i; port_t port; u32_t w; @@ -1075,7 +845,7 @@ re_t *rep; for (i = 0; i < 6; i++) { if (env_parse(eakey, eafmt, i, &v, 0x00L, 0xFFL) != EP_SET) break; - rep->re_address.ea_addr[i] = v; + addr->ea_addr[i] = v; } if (i != 0 && i != 6) @@ -1087,25 +857,24 @@ re_t *rep; rl_outb(port, RL_9346CR, RL_9346CR_EEM_CONFIG); w = 0; for (i = 0; i < 4; i++) - w |= (rep->re_address.ea_addr[i] << (i * 8)); + w |= (addr->ea_addr[i] << (i * 8)); rl_outl(port, RL_IDR, w); w = 0; for (i = 4; i < 6; i++) - w |= (rep->re_address.ea_addr[i] << ((i-4) * 8)); + w |= (addr->ea_addr[i] << ((i-4) * 8)); rl_outl(port, RL_IDR + 4, w); rl_outb(port, RL_9346CR, RL_9346CR_EEM_NORMAL); } /* Get ethernet address */ for (i = 0; i < 6; i++) - rep->re_address.ea_addr[i] = rl_inb(port, RL_IDR+i); + addr->ea_addr[i] = rl_inb(port, RL_IDR+i); } /*===========================================================================* * rl_rec_mode * *===========================================================================*/ -static void rl_rec_mode(rep) -re_t *rep; +static void rl_rec_mode(re_t *rep) { port_t port; u32_t rcr; @@ -1119,279 +888,127 @@ re_t *rep; rcr = rl_inl(port, RL_RCR); rcr &= ~(RL_RCR_AB | RL_RCR_AM | RL_RCR_APM | RL_RCR_AAP); - if (rep->re_flags & REF_PROMISC) + if (rep->re_mode & NDEV_PROMISC) rcr |= RL_RCR_AB | RL_RCR_AM | RL_RCR_AAP; - if (rep->re_flags & REF_BROAD) + if (rep->re_mode & NDEV_BROAD) rcr |= RL_RCR_AB; - if (rep->re_flags & REF_MULTI) + if (rep->re_mode & NDEV_MULTI) rcr |= RL_RCR_AM; rcr |= RL_RCR_APM; rl_outl(port, RL_RCR, RL_RCR_RXFTH_UNLIM | RL_RCR_MXDMA_1024 | rcr); } -void transmittest(re_t *rep) -{ - int tx_head; - int ipc_status; - - tx_head = rep->re_tx_head; - - if(rep->re_tx[tx_head].ret_busy) { - do { - message m; - int r; - if ((r = netdriver_receive(ANY, &m, &ipc_status)) != OK) - panic("netdriver_receive failed: %d", r); - } while(m.m_source != HARDWARE); - assert(!(rep->re_flags & REF_SEND_AVAIL)); - rep->re_flags |= REF_SEND_AVAIL; - } - - return; -} - /*===========================================================================* - * rl_readv_s * + * rl_recv * *===========================================================================*/ -static void rl_readv_s(const message *mp, int from_int) +static ssize_t rl_recv(struct netdriver_data *data, size_t max) { - int i, j, n, s, count, size, index; + int index; port_t port; unsigned totlen, packlen; re_desc *desc; - u32_t rxstat = 0x12345678; + u32_t rxstat; re_t *rep; - iovec_s_t *iovp; - int cps; - int iov_offset = 0; rep = &re_state; - rep->re_client = mp->m_source; - count = mp->m_net_netdrv_dl_readv_s.count; - - assert(rep->re_mode == REM_ENABLED); - assert(rep->re_flags & REF_ENABLED); - port = rep->re_base_port; - /* - * Assume that the RL_CR_BUFE check was been done by rl_checks_ints - */ - if (!from_int && (rl_inb(port, RL_CR) & RL_CR_BUFE)) - goto suspend; /* Receive buffer is empty, suspend */ + if (rl_inb(port, RL_CR) & RL_CR_BUFE) + return SUSPEND; /* Receive buffer is empty, suspend */ index = rep->re_rx_head; desc = rep->re_rx_desc; desc += index; -readvs_loop: - rxstat = desc->status; - if (rxstat & DESC_OWN) - goto suspend; + for (;;) { + rxstat = desc->status; - if (rxstat & DESC_RX_CRC) - rep->re_stat.ets_CRCerr++; + if (rxstat & DESC_OWN) + return SUSPEND; + + if (rxstat & DESC_RX_CRC) + rep->re_stat.ets_CRCerr++; + + if ((rxstat & (DESC_FS | DESC_LS)) == (DESC_FS | DESC_LS)) + break; - if ((rxstat & (DESC_FS | DESC_LS)) != (DESC_FS | DESC_LS)) { #if VERBOSE - printf("rl_readv_s: packet is fragmented\n"); + printf("rl_recv: packet is fragmented\n"); #endif /* Fix the fragmented packet */ if (index == N_RX_DESC - 1) { - desc->status = DESC_EOR | DESC_OWN | (RX_BUFSIZE & DESC_RX_LENMASK); + desc->status = DESC_EOR | DESC_OWN | + (RX_BUFSIZE & DESC_RX_LENMASK); index = 0; desc = rep->re_rx_desc; } else { - desc->status = DESC_OWN | (RX_BUFSIZE & DESC_RX_LENMASK); + desc->status = DESC_OWN | + (RX_BUFSIZE & DESC_RX_LENMASK); index++; desc++; } - goto readvs_loop; /* Loop until we get correct packet */ + /* Loop until we get correct packet */ } totlen = rxstat & DESC_RX_LENMASK; if (totlen < 8 || totlen > 2 * ETH_MAX_PACK_SIZE) { /* Someting went wrong */ - printf("rl_readv_s: bad length (%u) in status 0x%08x\n", + printf("rl_recv: bad length (%u) in status 0x%08x\n", totlen, rxstat); panic(NULL); } /* Should subtract the CRC */ packlen = totlen - ETH_CRC_SIZE; + if (packlen > max) + packlen = max; - size = 0; - for (i = 0; i < count; i += IOVEC_NR, - iov_offset += IOVEC_NR * sizeof(rep->re_iovec_s[0])) - { - n = IOVEC_NR; - if (i + n > count) - n = count-i; - cps = sys_safecopyfrom(mp->m_source, - mp->m_net_netdrv_dl_readv_s.grant, iov_offset, - (vir_bytes) rep->re_iovec_s, - n * sizeof(rep->re_iovec_s[0])); - if (cps != OK) { - panic("rl_readv_s: sys_safecopyfrom failed: %d", cps); - } - - for (j = 0, iovp = rep->re_iovec_s; j < n; j++, iovp++) { - s = iovp->iov_size; - if (size + s > packlen) { - assert(packlen > size); - s = packlen-size; - } - - cps = sys_safecopyto(mp->m_source, iovp->iov_grant, 0, - (vir_bytes) rep->re_rx[index].v_ret_buf + size, s); - if (cps != OK) - panic("rl_readv_s: sys_safecopyto failed: %d", cps); - - size += s; - if (size == packlen) - break; - } - if (size == packlen) - break; - } - if (size < packlen) - assert(0); + netdriver_copyout(data, 0, rep->re_rx[index].v_ret_buf, packlen); rep->re_stat.ets_packetR++; - rep->re_read_s = packlen; + if (index == N_RX_DESC - 1) { - desc->status = DESC_EOR | DESC_OWN | (RX_BUFSIZE & DESC_RX_LENMASK); + desc->status = DESC_EOR | DESC_OWN | + (RX_BUFSIZE & DESC_RX_LENMASK); index = 0; } else { - desc->status = DESC_OWN | (RX_BUFSIZE & DESC_RX_LENMASK); + desc->status = DESC_OWN | (RX_BUFSIZE & DESC_RX_LENMASK); index++; } rep->re_rx_head = index; assert(rep->re_rx_head < N_RX_DESC); - rep->re_flags = (rep->re_flags & ~REF_READING) | REF_PACK_RECV; - if (!from_int) - reply(rep); - - return; - -suspend: - if (from_int) { - assert(rep->re_flags & REF_READING); - - /* No need to store any state */ - return; - } - - rep->re_rx_mess = *mp; - assert(!(rep->re_flags & REF_READING)); - rep->re_flags |= REF_READING; - - reply(rep); + return packlen; } /*===========================================================================* - * rl_writev_s * + * rl_send * *===========================================================================*/ -static void rl_writev_s(const message *mp, int from_int) +static int rl_send(struct netdriver_data *data, size_t size) { - int i, j, n, s, count, size; int tx_head; re_t *rep; - iovec_s_t *iovp; re_desc *desc; - char *ret; - int cps; - int iov_offset = 0; rep = &re_state; - rep->re_client = mp->m_source; - count = mp->m_net_netdrv_dl_writev_s.count; - assert(rep->setup); - - assert(rep->re_mode == REM_ENABLED); - assert(rep->re_flags & REF_ENABLED); - - if (from_int) { - assert(rep->re_flags & REF_SEND_AVAIL); - rep->re_flags &= ~REF_SEND_AVAIL; - rep->re_send_int = FALSE; - rep->re_tx_alive = TRUE; - } - tx_head = rep->re_tx_head; desc = rep->re_tx_desc; desc += tx_head; - if(!desc || !rep->re_tx_desc) { - printf("desc %p, re_tx_desc %p, tx_head %d, setup %d\n", - desc, rep->re_tx_desc, tx_head, rep->setup); - } - + assert(desc); assert(rep->re_tx_desc); assert(rep->re_tx_head >= 0 && rep->re_tx_head < N_TX_DESC); - assert(desc); + if (rep->re_tx[tx_head].ret_busy) + return SUSPEND; - if (rep->re_tx[tx_head].ret_busy) { - assert(!(rep->re_flags & REF_SEND_AVAIL)); - rep->re_flags |= REF_SEND_AVAIL; - if (rep->re_tx[tx_head].ret_busy) - goto suspend; - - /* - * Race condition, the interrupt handler may clear re_busy - * before we got a chance to set REF_SEND_AVAIL. Checking - * ret_busy twice should be sufficient. - */ -#if VERBOSE - printf("rl_writev_s: race detected\n"); -#endif - rep->re_flags &= ~REF_SEND_AVAIL; - rep->re_send_int = FALSE; - } - - assert(!(rep->re_flags & REF_SEND_AVAIL)); - assert(!(rep->re_flags & REF_PACK_SENT)); - - size = 0; - ret = rep->re_tx[tx_head].v_ret_buf; - for (i = 0; i < count; i += IOVEC_NR, - iov_offset += IOVEC_NR * sizeof(rep->re_iovec_s[0])) - { - n = IOVEC_NR; - if (i + n > count) - n = count - i; - cps = sys_safecopyfrom(mp->m_source, - mp->m_net_netdrv_dl_writev_s.grant, iov_offset, - (vir_bytes) rep->re_iovec_s, - n * sizeof(rep->re_iovec_s[0])); - if (cps != OK) { - panic("rl_writev_s: sys_safecopyfrom failed: %d", cps); - } - - for (j = 0, iovp = rep->re_iovec_s; j < n; j++, iovp++) { - s = iovp->iov_size; - if (size + s > ETH_MAX_PACK_SIZE_TAGGED) - panic("invalid packet size"); - - cps = sys_safecopyfrom(mp->m_source, iovp->iov_grant, - 0, (vir_bytes) ret, s); - if (cps != OK) { - panic("rl_writev_s: sys_safecopyfrom failed: %d", cps); - } - size += s; - ret += s; - } - } - assert(desc); - if (size < ETH_MIN_PACK_SIZE) - panic("invalid packet size: %d", size); + netdriver_copyin(data, 0, rep->re_tx[tx_head].v_ret_buf, size); rep->re_tx[tx_head].ret_busy = TRUE; + rep->re_tx_busy++; if (tx_head == N_TX_DESC - 1) { desc->status = DESC_EOR | DESC_OWN | DESC_FS | DESC_LS | size; @@ -1405,67 +1022,45 @@ static void rl_writev_s(const message *mp, int from_int) rep->re_tx_head = tx_head; rl_outl(rep->re_base_port, RL_TPPOLL, RL_TPPOLL_NPQ); - rep->re_flags |= REF_PACK_SENT; - /* - * If the interrupt handler called, don't send a reply. The reply - * will be sent after all interrupts are handled. - */ - if (from_int) - return; - reply(rep); - return; - -suspend: - if (from_int) - panic("should not be sending"); - - rep->re_tx_mess = *mp; - reply(rep); + return OK; } /*===========================================================================* * rl_check_ints * *===========================================================================*/ -static void rl_check_ints(rep) -re_t *rep; +static void rl_check_ints(re_t *rep) { - int re_flags; + if (!rep->re_got_int) + return; + rep->re_got_int = FALSE; - re_flags = rep->re_flags; - - if ((re_flags & REF_READING) && - !(rl_inb(rep->re_base_port, RL_CR) & RL_CR_BUFE)) - { - assert(rep->re_rx_mess.m_type == DL_READV_S); - rl_readv_s(&rep->re_rx_mess, TRUE /* from int */); - } + netdriver_recv(); if (rep->re_need_reset) rl_do_reset(rep); if (rep->re_send_int) { - assert(rep->re_tx_mess.m_type == DL_WRITEV_S); - rl_writev_s(&rep->re_tx_mess, TRUE /* from int */); + rep->re_send_int = FALSE; + + netdriver_send(); } if (rep->re_report_link) { rep->re_report_link = FALSE; +#if VERBOSE rl_report_link(rep); +#endif } - - if (rep->re_flags & (REF_PACK_SENT | REF_PACK_RECV)) - reply(rep); } /*===========================================================================* * rl_report_link * *===========================================================================*/ -static void rl_report_link(rep) -re_t *rep; -{ #if VERBOSE +static void rl_report_link(re_t *rep) +{ port_t port; u8_t mii_status; @@ -1494,102 +1089,38 @@ re_t *rep; else printf(", half duplex"); printf("\n"); -#endif dump_phy(rep); } +#endif /*===========================================================================* * rl_do_reset * *===========================================================================*/ -static void rl_do_reset(rep) -re_t *rep; +static void rl_do_reset(re_t *rep) { rep->re_need_reset = FALSE; rl_reset_hw(rep); rl_rec_mode(rep); rep->re_tx_head = 0; - if (rep->re_flags & REF_SEND_AVAIL) { - rep->re_tx[rep->re_tx_head].ret_busy = FALSE; - rep->re_send_int = TRUE; - } + if (rep->re_tx[rep->re_tx_head].ret_busy) + rep->re_tx_busy--; + rep->re_tx[rep->re_tx_head].ret_busy = FALSE; + rep->re_send_int = TRUE; } /*===========================================================================* - * rl_getstat_s * + * rl_stat * *===========================================================================*/ -static void rl_getstat_s(mp) -message *mp; +static void rl_stat(eth_stat_t *stat) { - int r; - eth_stat_t stats; - re_t *rep; - - rep = &re_state; - - assert(rep->re_mode == REM_ENABLED); - assert(rep->re_flags & REF_ENABLED); - - stats = rep->re_stat; - - r = sys_safecopyto(mp->m_source, mp->m_net_netdrv_dl_getstat_s.grant, - 0, (vir_bytes) &stats, sizeof(stats)); - if (r != OK) - panic("rl_getstat_s: sys_safecopyto failed: %d", r); - - mp->m_type = DL_STAT_REPLY; - r = ipc_send(mp->m_source, mp); - if (r != OK) - panic("rl_getstat_s: ipc_send failed: %d", r); -} - -/*===========================================================================* - * reply * - *===========================================================================*/ -static void reply(rep) -re_t *rep; -{ - message reply; - int flags; - int r; - - flags = DL_NOFLAGS; - if (rep->re_flags & REF_PACK_SENT) - flags |= DL_PACK_SEND; - if (rep->re_flags & REF_PACK_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 = rep->re_read_s; - - r = ipc_send(rep->re_client, &reply); - - if (r < 0) { - printf("RTL8169 tried sending to %d, type %d\n", - rep->re_client, reply.m_type); - panic("ipc_send failed: %d", r); - } - - rep->re_read_s = 0; - rep->re_flags &= ~(REF_PACK_SENT | REF_PACK_RECV); -} - -/*===========================================================================* - * mess_reply * - *===========================================================================*/ -static void mess_reply(req, reply_mess) -message *req; -message *reply_mess; -{ - if (ipc_send(req->m_source, reply_mess) != OK) - panic("unable to mess_reply"); + memcpy(stat, &re_state.re_stat, sizeof(*stat)); } +#if VERBOSE static void dump_phy(const re_t *rep) { -#if VERBOSE port_t port; u32_t t; @@ -1765,19 +1296,28 @@ static void dump_phy(const re_t *rep) printf(" 1000BaseT-HD"); printf("\n"); } -#endif } +#endif -static void do_hard_int(void) +/*===========================================================================* + * rl_intr * + *===========================================================================*/ +static void rl_intr(unsigned int __unused mask) { + re_t *rep; int s; + rep = &re_state; + /* Run interrupt handler at driver level. */ - rl_handler(&re_state); + rl_handler(rep); /* Reenable interrupts for this hook. */ - if ((s = sys_irqenable(&re_state.re_hook_id)) != OK) + if ((s = sys_irqenable(&rep->re_hook_id)) != OK) printf("RTL8169: error, couldn't enable interrupts: %d\n", s); + + /* Perform tasks based on the flagged conditions. */ + rl_check_ints(rep); } /*===========================================================================* @@ -1788,7 +1328,6 @@ static void rl_handler(re_t *rep) int i, port, tx_head, tx_tail, link_up; u16_t isr; re_desc *desc; - int_event_check = FALSE; /* disable check by default */ port = rep->re_base_port; @@ -1816,7 +1355,6 @@ static void rl_handler(re_t *rep) if (link_up != rep->re_link_up) { rep->re_report_link = TRUE; rep->re_got_int = TRUE; - int_event_check = TRUE; } } @@ -1825,10 +1363,7 @@ static void rl_handler(re_t *rep) rep->re_stat.ets_recvErr++; isr &= ~(RL_ISR_RDU | RL_ISR_RER | RL_ISR_ROK); - if (!rep->re_got_int && (rep->re_flags & REF_READING)) { - rep->re_got_int = TRUE; - int_event_check = TRUE; - } + rep->re_got_int = TRUE; } if ((isr & (RL_ISR_TDU | RL_ISR_TER | RL_ISR_TOK)) || 1) { @@ -1864,18 +1399,15 @@ static void rl_handler(re_t *rep) rep->re_stat.ets_packetT++; rep->re_tx[tx_tail].ret_busy = FALSE; + rep->re_tx_busy--; if (++tx_tail >= N_TX_DESC) tx_tail = 0; assert(tx_tail < N_TX_DESC); - if (rep->re_flags & REF_SEND_AVAIL) { - rep->re_send_int = TRUE; - if (!rep->re_got_int) { - rep->re_got_int = TRUE; - int_event_check = TRUE; - } - } + rep->re_send_int = TRUE; + rep->re_got_int = TRUE; + rep->re_tx_alive = TRUE; } assert(i < 2 * N_TX_DESC); } @@ -1889,40 +1421,36 @@ static void rl_handler(re_t *rep) } /*===========================================================================* - * rl_watchdog_f * + * rl_alarm * *===========================================================================*/ -static void rl_watchdog_f(tp) -minix_timer_t *tp; +static void rl_alarm(clock_t __unused stamp) { re_t *rep; + /* Use a synchronous alarm instead of a watchdog timer. */ - sys_setalarm(system_hz, 0); + sys_setalarm(sys_hz(), 0); rep = &re_state; - if (rep->re_mode != REM_ENABLED) - return; - /* Should collect statistics */ if (!(++rep->dtcc_counter % RE_DTCC_VALUE)) rtl8169_update_stat(rep); - if (!(rep->re_flags & REF_SEND_AVAIL)) { - /* Assume that an idle system is alive */ - rep->re_tx_alive = TRUE; + assert(rep->re_tx_busy >= 0 && rep->re_tx_busy <= N_TX_DESC); + if (rep->re_tx_busy == 0) { + /* Assume that an idle system is alive */ + rep->re_tx_alive = TRUE; return; } if (rep->re_tx_alive) { rep->re_tx_alive = FALSE; return; } - printf("rl_watchdog_f: resetting instance %d mode 0x%x flags 0x%x\n", - re_instance, rep->re_mode, rep->re_flags); + printf("rl_alarm: resetting instance %d\n", re_instance); printf("tx_head :%8d busy %d\t", rep->re_tx_head, rep->re_tx[rep->re_tx_head].ret_busy); rep->re_need_reset = TRUE; rep->re_got_int = TRUE; - check_int_events(); + rl_check_ints(rep); } - diff --git a/minix/drivers/net/virtio_net/virtio_net.c b/minix/drivers/net/virtio_net/virtio_net.c index e7daa1a6e..9ba7313a4 100644 --- a/minix/drivers/net/virtio_net/virtio_net.c +++ b/minix/drivers/net/virtio_net/virtio_net.c @@ -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; } diff --git a/minix/drivers/storage/virtio_blk/virtio_blk.c b/minix/drivers/storage/virtio_blk/virtio_blk.c index 4583101c7..d7a3c7338 100644 --- a/minix/drivers/storage/virtio_blk/virtio_blk.c +++ b/minix/drivers/storage/virtio_blk/virtio_blk.c @@ -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); } diff --git a/minix/include/minix/netdriver.h b/minix/include/minix/netdriver.h index 58ce47564..693855838 100644 --- a/minix/include/minix/netdriver.h +++ b/minix/include/minix/netdriver.h @@ -5,9 +5,63 @@ #include #include +#include -/* 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 +#include + +/* 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 */ diff --git a/minix/include/minix/virtio.h b/minix/include/minix/virtio.h index aec6d4b89..aee338e1c 100644 --- a/minix/include/minix/virtio.h +++ b/minix/include/minix/virtio.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); diff --git a/minix/lib/libnetdriver/Makefile b/minix/lib/libnetdriver/Makefile index 2c670a4ca..a0abb86fd 100644 --- a/minix/lib/libnetdriver/Makefile +++ b/minix/lib/libnetdriver/Makefile @@ -6,6 +6,6 @@ CPPFLAGS+= -D_MINIX_SYSTEM LIB= netdriver -SRCS= netdriver.c +SRCS= netdriver.c portio.c .include diff --git a/minix/lib/libnetdriver/netdriver.c b/minix/lib/libnetdriver/netdriver.c index 51adcf2a5..bdea11df6 100644 --- a/minix/lib/libnetdriver/netdriver.c +++ b/minix/lib/libnetdriver/netdriver.c @@ -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 #include #include #include +#include -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 + * 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); + } +} diff --git a/minix/lib/libnetdriver/netdriver.h b/minix/lib/libnetdriver/netdriver.h new file mode 100644 index 000000000..24b9c5cc0 --- /dev/null +++ b/minix/lib/libnetdriver/netdriver.h @@ -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 */ diff --git a/minix/lib/libnetdriver/portio.c b/minix/lib/libnetdriver/portio.c new file mode 100644 index 000000000..432166f29 --- /dev/null +++ b/minix/lib/libnetdriver/portio.c @@ -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 +#include +#include + +#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); + } +} diff --git a/minix/lib/libvirtio/virtio.c b/minix/lib/libvirtio/virtio.c index 1ff715a04..95c64cbe0 100644 --- a/minix/lib/libvirtio/virtio.c +++ b/minix/lib/libvirtio/virtio.c @@ -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; } diff --git a/minix/net/Makefile b/minix/net/Makefile index 3a589825b..223f74188 100644 --- a/minix/net/Makefile +++ b/minix/net/Makefile @@ -6,6 +6,8 @@ SUBDIR+= inet . if ${MKLWIP} == "yes" SUBDIR+= lwip . endif # ${MKLWIP} == "yes" + +SUBDIR+= uds .endif # ${MKIMAGEONLY} == "no" .include diff --git a/minix/drivers/net/uds/Makefile b/minix/net/uds/Makefile similarity index 100% rename from minix/drivers/net/uds/Makefile rename to minix/net/uds/Makefile diff --git a/minix/drivers/net/uds/ioc_uds.c b/minix/net/uds/ioc_uds.c similarity index 100% rename from minix/drivers/net/uds/ioc_uds.c rename to minix/net/uds/ioc_uds.c diff --git a/minix/drivers/net/uds/uds.c b/minix/net/uds/uds.c similarity index 100% rename from minix/drivers/net/uds/uds.c rename to minix/net/uds/uds.c diff --git a/minix/drivers/net/uds/uds.h b/minix/net/uds/uds.h similarity index 100% rename from minix/drivers/net/uds/uds.h rename to minix/net/uds/uds.h