xref: /illumos-gate/usr/src/cmd/bhyve/pci_e82545.c (revision 84659b24a533984de271059abf9a1092835d15a9)
14c87aefeSPatrick Mooney /*
24c87aefeSPatrick Mooney  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
34c87aefeSPatrick Mooney  *
44c87aefeSPatrick Mooney  * Copyright (c) 2016 Alexander Motin <mav@FreeBSD.org>
54c87aefeSPatrick Mooney  * Copyright (c) 2015 Peter Grehan <grehan@freebsd.org>
64c87aefeSPatrick Mooney  * Copyright (c) 2013 Jeremiah Lott, Avere Systems
74c87aefeSPatrick Mooney  * All rights reserved.
84c87aefeSPatrick Mooney  *
94c87aefeSPatrick Mooney  * Redistribution and use in source and binary forms, with or without
104c87aefeSPatrick Mooney  * modification, are permitted provided that the following conditions
114c87aefeSPatrick Mooney  * are met:
124c87aefeSPatrick Mooney  * 1. Redistributions of source code must retain the above copyright
134c87aefeSPatrick Mooney  *    notice, this list of conditions and the following disclaimer
144c87aefeSPatrick Mooney  *    in this position and unchanged.
154c87aefeSPatrick Mooney  * 2. Redistributions in binary form must reproduce the above copyright
164c87aefeSPatrick Mooney  *    notice, this list of conditions and the following disclaimer in the
174c87aefeSPatrick Mooney  *    documentation and/or other materials provided with the distribution.
184c87aefeSPatrick Mooney  *
194c87aefeSPatrick Mooney  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
204c87aefeSPatrick Mooney  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
214c87aefeSPatrick Mooney  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
224c87aefeSPatrick Mooney  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
234c87aefeSPatrick Mooney  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
244c87aefeSPatrick Mooney  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
254c87aefeSPatrick Mooney  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
264c87aefeSPatrick Mooney  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
274c87aefeSPatrick Mooney  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
284c87aefeSPatrick Mooney  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
294c87aefeSPatrick Mooney  * SUCH DAMAGE.
304c87aefeSPatrick Mooney  */
314c87aefeSPatrick Mooney 
324c87aefeSPatrick Mooney #include <sys/cdefs.h>
334c87aefeSPatrick Mooney __FBSDID("$FreeBSD$");
344c87aefeSPatrick Mooney 
354c87aefeSPatrick Mooney #include <sys/types.h>
364c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM
374c87aefeSPatrick Mooney #include <sys/capsicum.h>
384c87aefeSPatrick Mooney #endif
394c87aefeSPatrick Mooney #include <sys/limits.h>
404c87aefeSPatrick Mooney #include <sys/ioctl.h>
414c87aefeSPatrick Mooney #include <sys/uio.h>
424c87aefeSPatrick Mooney #include <net/ethernet.h>
434c87aefeSPatrick Mooney #include <netinet/in.h>
444c87aefeSPatrick Mooney #include <netinet/tcp.h>
454c87aefeSPatrick Mooney #ifndef	__FreeBSD__
464c87aefeSPatrick Mooney #include <sys/filio.h>
474c87aefeSPatrick Mooney #endif
484c87aefeSPatrick Mooney 
494c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM
504c87aefeSPatrick Mooney #include <capsicum_helpers.h>
514c87aefeSPatrick Mooney #endif
524c87aefeSPatrick Mooney #include <err.h>
534c87aefeSPatrick Mooney #include <errno.h>
544c87aefeSPatrick Mooney #include <fcntl.h>
554c87aefeSPatrick Mooney #include <md5.h>
564c87aefeSPatrick Mooney #include <stdio.h>
574c87aefeSPatrick Mooney #include <stdlib.h>
584c87aefeSPatrick Mooney #include <string.h>
594c87aefeSPatrick Mooney #include <sysexits.h>
604c87aefeSPatrick Mooney #include <unistd.h>
614c87aefeSPatrick Mooney #include <pthread.h>
624c87aefeSPatrick Mooney #include <pthread_np.h>
634c87aefeSPatrick Mooney 
644c87aefeSPatrick Mooney #include "e1000_regs.h"
654c87aefeSPatrick Mooney #include "e1000_defines.h"
664c87aefeSPatrick Mooney #include "mii.h"
674c87aefeSPatrick Mooney 
684c87aefeSPatrick Mooney #include "bhyverun.h"
694c87aefeSPatrick Mooney #include "pci_emul.h"
704c87aefeSPatrick Mooney #include "mevent.h"
71*84659b24SMichael Zeller #include "net_utils.h"
724c87aefeSPatrick Mooney 
734c87aefeSPatrick Mooney /* Hardware/register definitions XXX: move some to common code. */
744c87aefeSPatrick Mooney #define E82545_VENDOR_ID_INTEL			0x8086
754c87aefeSPatrick Mooney #define E82545_DEV_ID_82545EM_COPPER		0x100F
764c87aefeSPatrick Mooney #define E82545_SUBDEV_ID			0x1008
774c87aefeSPatrick Mooney 
784c87aefeSPatrick Mooney #define E82545_REVISION_4			4
794c87aefeSPatrick Mooney 
804c87aefeSPatrick Mooney #define E82545_MDIC_DATA_MASK			0x0000FFFF
814c87aefeSPatrick Mooney #define E82545_MDIC_OP_MASK			0x0c000000
824c87aefeSPatrick Mooney #define E82545_MDIC_IE				0x20000000
834c87aefeSPatrick Mooney 
844c87aefeSPatrick Mooney #define E82545_EECD_FWE_DIS	0x00000010 /* Flash writes disabled */
854c87aefeSPatrick Mooney #define E82545_EECD_FWE_EN	0x00000020 /* Flash writes enabled */
864c87aefeSPatrick Mooney #define E82545_EECD_FWE_MASK	0x00000030 /* Flash writes mask */
874c87aefeSPatrick Mooney 
884c87aefeSPatrick Mooney #define E82545_BAR_REGISTER			0
894c87aefeSPatrick Mooney #define E82545_BAR_REGISTER_LEN			(128*1024)
904c87aefeSPatrick Mooney #define E82545_BAR_FLASH			1
914c87aefeSPatrick Mooney #define E82545_BAR_FLASH_LEN			(64*1024)
924c87aefeSPatrick Mooney #define E82545_BAR_IO				2
934c87aefeSPatrick Mooney #define E82545_BAR_IO_LEN			8
944c87aefeSPatrick Mooney 
954c87aefeSPatrick Mooney #define E82545_IOADDR				0x00000000
964c87aefeSPatrick Mooney #define E82545_IODATA				0x00000004
974c87aefeSPatrick Mooney #define E82545_IO_REGISTER_MAX			0x0001FFFF
984c87aefeSPatrick Mooney #define E82545_IO_FLASH_BASE			0x00080000
994c87aefeSPatrick Mooney #define E82545_IO_FLASH_MAX			0x000FFFFF
1004c87aefeSPatrick Mooney 
1014c87aefeSPatrick Mooney #define E82545_ARRAY_ENTRY(reg, offset)		(reg + (offset<<2))
1024c87aefeSPatrick Mooney #define E82545_RAR_MAX				15
1034c87aefeSPatrick Mooney #define E82545_MTA_MAX				127
1044c87aefeSPatrick Mooney #define E82545_VFTA_MAX				127
1054c87aefeSPatrick Mooney 
1064c87aefeSPatrick Mooney /* Slightly modified from the driver versions, hardcoded for 3 opcode bits,
1074c87aefeSPatrick Mooney  * followed by 6 address bits.
1084c87aefeSPatrick Mooney  * TODO: make opcode bits and addr bits configurable?
1094c87aefeSPatrick Mooney  * NVM Commands - Microwire */
1104c87aefeSPatrick Mooney #define E82545_NVM_OPCODE_BITS	3
1114c87aefeSPatrick Mooney #define E82545_NVM_ADDR_BITS	6
1124c87aefeSPatrick Mooney #define E82545_NVM_DATA_BITS	16
1134c87aefeSPatrick Mooney #define E82545_NVM_OPADDR_BITS	(E82545_NVM_OPCODE_BITS + E82545_NVM_ADDR_BITS)
1144c87aefeSPatrick Mooney #define E82545_NVM_ADDR_MASK	((1 << E82545_NVM_ADDR_BITS)-1)
1154c87aefeSPatrick Mooney #define E82545_NVM_OPCODE_MASK	\
1164c87aefeSPatrick Mooney     (((1 << E82545_NVM_OPCODE_BITS) - 1) << E82545_NVM_ADDR_BITS)
1174c87aefeSPatrick Mooney #define E82545_NVM_OPCODE_READ	(0x6 << E82545_NVM_ADDR_BITS)	/* read */
1184c87aefeSPatrick Mooney #define E82545_NVM_OPCODE_WRITE	(0x5 << E82545_NVM_ADDR_BITS)	/* write */
1194c87aefeSPatrick Mooney #define E82545_NVM_OPCODE_ERASE	(0x7 << E82545_NVM_ADDR_BITS)	/* erase */
1204c87aefeSPatrick Mooney #define	E82545_NVM_OPCODE_EWEN	(0x4 << E82545_NVM_ADDR_BITS)	/* wr-enable */
1214c87aefeSPatrick Mooney 
1224c87aefeSPatrick Mooney #define	E82545_NVM_EEPROM_SIZE	64 /* 64 * 16-bit values == 128K */
1234c87aefeSPatrick Mooney 
1244c87aefeSPatrick Mooney #define E1000_ICR_SRPD		0x00010000
1254c87aefeSPatrick Mooney 
1264c87aefeSPatrick Mooney /* This is an arbitrary number.  There is no hard limit on the chip. */
1274c87aefeSPatrick Mooney #define I82545_MAX_TXSEGS	64
1284c87aefeSPatrick Mooney 
1294c87aefeSPatrick Mooney /* Legacy receive descriptor */
1304c87aefeSPatrick Mooney struct e1000_rx_desc {
1314c87aefeSPatrick Mooney 	uint64_t buffer_addr;	/* Address of the descriptor's data buffer */
1324c87aefeSPatrick Mooney 	uint16_t length;	/* Length of data DMAed into data buffer */
1334c87aefeSPatrick Mooney 	uint16_t csum;		/* Packet checksum */
1344c87aefeSPatrick Mooney 	uint8_t	 status;       	/* Descriptor status */
1354c87aefeSPatrick Mooney 	uint8_t  errors;	/* Descriptor Errors */
1364c87aefeSPatrick Mooney 	uint16_t special;
1374c87aefeSPatrick Mooney };
1384c87aefeSPatrick Mooney 
1394c87aefeSPatrick Mooney /* Transmit descriptor types */
1404c87aefeSPatrick Mooney #define	E1000_TXD_MASK		(E1000_TXD_CMD_DEXT | 0x00F00000)
1414c87aefeSPatrick Mooney #define E1000_TXD_TYP_L		(0)
1424c87aefeSPatrick Mooney #define E1000_TXD_TYP_C		(E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_C)
1434c87aefeSPatrick Mooney #define E1000_TXD_TYP_D		(E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D)
1444c87aefeSPatrick Mooney 
1454c87aefeSPatrick Mooney /* Legacy transmit descriptor */
1464c87aefeSPatrick Mooney struct e1000_tx_desc {
1474c87aefeSPatrick Mooney 	uint64_t buffer_addr;   /* Address of the descriptor's data buffer */
1484c87aefeSPatrick Mooney 	union {
1494c87aefeSPatrick Mooney 		uint32_t data;
1504c87aefeSPatrick Mooney 		struct {
1514c87aefeSPatrick Mooney 			uint16_t length;  /* Data buffer length */
1524c87aefeSPatrick Mooney 			uint8_t  cso;  /* Checksum offset */
1534c87aefeSPatrick Mooney 			uint8_t  cmd;  /* Descriptor control */
1544c87aefeSPatrick Mooney 		} flags;
1554c87aefeSPatrick Mooney 	} lower;
1564c87aefeSPatrick Mooney 	union {
1574c87aefeSPatrick Mooney 		uint32_t data;
1584c87aefeSPatrick Mooney 		struct {
1594c87aefeSPatrick Mooney 			uint8_t status; /* Descriptor status */
1604c87aefeSPatrick Mooney 			uint8_t css;  /* Checksum start */
1614c87aefeSPatrick Mooney 			uint16_t special;
1624c87aefeSPatrick Mooney 		} fields;
1634c87aefeSPatrick Mooney 	} upper;
1644c87aefeSPatrick Mooney };
1654c87aefeSPatrick Mooney 
1664c87aefeSPatrick Mooney /* Context descriptor */
1674c87aefeSPatrick Mooney struct e1000_context_desc {
1684c87aefeSPatrick Mooney 	union {
1694c87aefeSPatrick Mooney 		uint32_t ip_config;
1704c87aefeSPatrick Mooney 		struct {
1714c87aefeSPatrick Mooney 			uint8_t ipcss;  /* IP checksum start */
1724c87aefeSPatrick Mooney 			uint8_t ipcso;  /* IP checksum offset */
1734c87aefeSPatrick Mooney 			uint16_t ipcse;  /* IP checksum end */
1744c87aefeSPatrick Mooney 		} ip_fields;
1754c87aefeSPatrick Mooney 	} lower_setup;
1764c87aefeSPatrick Mooney 	union {
1774c87aefeSPatrick Mooney 		uint32_t tcp_config;
1784c87aefeSPatrick Mooney 		struct {
1794c87aefeSPatrick Mooney 			uint8_t tucss;  /* TCP checksum start */
1804c87aefeSPatrick Mooney 			uint8_t tucso;  /* TCP checksum offset */
1814c87aefeSPatrick Mooney 			uint16_t tucse;  /* TCP checksum end */
1824c87aefeSPatrick Mooney 		} tcp_fields;
1834c87aefeSPatrick Mooney 	} upper_setup;
1844c87aefeSPatrick Mooney 	uint32_t cmd_and_length;
1854c87aefeSPatrick Mooney 	union {
1864c87aefeSPatrick Mooney 		uint32_t data;
1874c87aefeSPatrick Mooney 		struct {
1884c87aefeSPatrick Mooney 			uint8_t status;  /* Descriptor status */
1894c87aefeSPatrick Mooney 			uint8_t hdr_len;  /* Header length */
1904c87aefeSPatrick Mooney 			uint16_t mss;  /* Maximum segment size */
1914c87aefeSPatrick Mooney 		} fields;
1924c87aefeSPatrick Mooney 	} tcp_seg_setup;
1934c87aefeSPatrick Mooney };
1944c87aefeSPatrick Mooney 
1954c87aefeSPatrick Mooney /* Data descriptor */
1964c87aefeSPatrick Mooney struct e1000_data_desc {
1974c87aefeSPatrick Mooney 	uint64_t buffer_addr;  /* Address of the descriptor's buffer address */
1984c87aefeSPatrick Mooney 	union {
1994c87aefeSPatrick Mooney 		uint32_t data;
2004c87aefeSPatrick Mooney 		struct {
2014c87aefeSPatrick Mooney 			uint16_t length;  /* Data buffer length */
2024c87aefeSPatrick Mooney 			uint8_t typ_len_ext;
2034c87aefeSPatrick Mooney 			uint8_t cmd;
2044c87aefeSPatrick Mooney 		} flags;
2054c87aefeSPatrick Mooney 	} lower;
2064c87aefeSPatrick Mooney 	union {
2074c87aefeSPatrick Mooney 		uint32_t data;
2084c87aefeSPatrick Mooney 		struct {
2094c87aefeSPatrick Mooney 			uint8_t status;  /* Descriptor status */
2104c87aefeSPatrick Mooney 			uint8_t popts;  /* Packet Options */
2114c87aefeSPatrick Mooney 			uint16_t special;
2124c87aefeSPatrick Mooney 		} fields;
2134c87aefeSPatrick Mooney 	} upper;
2144c87aefeSPatrick Mooney };
2154c87aefeSPatrick Mooney 
2164c87aefeSPatrick Mooney union e1000_tx_udesc {
2174c87aefeSPatrick Mooney 	struct e1000_tx_desc td;
2184c87aefeSPatrick Mooney 	struct e1000_context_desc cd;
2194c87aefeSPatrick Mooney 	struct e1000_data_desc dd;
2204c87aefeSPatrick Mooney };
2214c87aefeSPatrick Mooney 
2224c87aefeSPatrick Mooney /* Tx checksum info for a packet. */
2234c87aefeSPatrick Mooney struct ck_info {
2244c87aefeSPatrick Mooney 	int	ck_valid;	/* ck_info is valid */
2254c87aefeSPatrick Mooney 	uint8_t	ck_start;	/* start byte of cksum calcuation */
2264c87aefeSPatrick Mooney 	uint8_t	ck_off;		/* offset of cksum insertion */
2274c87aefeSPatrick Mooney 	uint16_t ck_len;	/* length of cksum calc: 0 is to packet-end */
2284c87aefeSPatrick Mooney };
2294c87aefeSPatrick Mooney 
2304c87aefeSPatrick Mooney /*
2314c87aefeSPatrick Mooney  * Debug printf
2324c87aefeSPatrick Mooney  */
2334c87aefeSPatrick Mooney static int e82545_debug = 0;
2344c87aefeSPatrick Mooney #define DPRINTF(msg,params...) if (e82545_debug) fprintf(stderr, "e82545: " msg, params)
2354c87aefeSPatrick Mooney #define WPRINTF(msg,params...) fprintf(stderr, "e82545: " msg, params)
2364c87aefeSPatrick Mooney 
2374c87aefeSPatrick Mooney #define	MIN(a,b) (((a)<(b))?(a):(b))
2384c87aefeSPatrick Mooney #define	MAX(a,b) (((a)>(b))?(a):(b))
2394c87aefeSPatrick Mooney 
2404c87aefeSPatrick Mooney /* s/w representation of the RAL/RAH regs */
2414c87aefeSPatrick Mooney struct  eth_uni {
2424c87aefeSPatrick Mooney 	int		eu_valid;
2434c87aefeSPatrick Mooney 	int		eu_addrsel;
2444c87aefeSPatrick Mooney 	struct ether_addr eu_eth;
2454c87aefeSPatrick Mooney };
2464c87aefeSPatrick Mooney 
2474c87aefeSPatrick Mooney 
2484c87aefeSPatrick Mooney struct e82545_softc {
2494c87aefeSPatrick Mooney 	struct pci_devinst *esc_pi;
2504c87aefeSPatrick Mooney 	struct vmctx	*esc_ctx;
2514c87aefeSPatrick Mooney 	struct mevent   *esc_mevp;
2524c87aefeSPatrick Mooney 	struct mevent   *esc_mevpitr;
2534c87aefeSPatrick Mooney 	pthread_mutex_t	esc_mtx;
2544c87aefeSPatrick Mooney 	struct ether_addr esc_mac;
2554c87aefeSPatrick Mooney 	int		esc_tapfd;
2564c87aefeSPatrick Mooney 
2574c87aefeSPatrick Mooney 	/* General */
2584c87aefeSPatrick Mooney 	uint32_t	esc_CTRL;	/* x0000 device ctl */
2594c87aefeSPatrick Mooney 	uint32_t	esc_FCAL;	/* x0028 flow ctl addr lo */
2604c87aefeSPatrick Mooney 	uint32_t	esc_FCAH;	/* x002C flow ctl addr hi */
2614c87aefeSPatrick Mooney 	uint32_t	esc_FCT;	/* x0030 flow ctl type */
2624c87aefeSPatrick Mooney 	uint32_t	esc_VET;	/* x0038 VLAN eth type */
2634c87aefeSPatrick Mooney 	uint32_t	esc_FCTTV;	/* x0170 flow ctl tx timer */
2644c87aefeSPatrick Mooney 	uint32_t	esc_LEDCTL;	/* x0E00 LED control */
2654c87aefeSPatrick Mooney 	uint32_t	esc_PBA;	/* x1000 pkt buffer allocation */
2664c87aefeSPatrick Mooney 
2674c87aefeSPatrick Mooney 	/* Interrupt control */
2684c87aefeSPatrick Mooney 	int		esc_irq_asserted;
2694c87aefeSPatrick Mooney 	uint32_t	esc_ICR;	/* x00C0 cause read/clear */
2704c87aefeSPatrick Mooney 	uint32_t	esc_ITR;	/* x00C4 intr throttling */
2714c87aefeSPatrick Mooney 	uint32_t	esc_ICS;	/* x00C8 cause set */
2724c87aefeSPatrick Mooney 	uint32_t	esc_IMS;	/* x00D0 mask set/read */
2734c87aefeSPatrick Mooney 	uint32_t	esc_IMC;	/* x00D8 mask clear */
2744c87aefeSPatrick Mooney 
2754c87aefeSPatrick Mooney 	/* Transmit */
2764c87aefeSPatrick Mooney 	union e1000_tx_udesc *esc_txdesc;
2774c87aefeSPatrick Mooney 	struct e1000_context_desc esc_txctx;
2784c87aefeSPatrick Mooney 	pthread_t	esc_tx_tid;
2794c87aefeSPatrick Mooney 	pthread_cond_t	esc_tx_cond;
2804c87aefeSPatrick Mooney 	int		esc_tx_enabled;
2814c87aefeSPatrick Mooney 	int		esc_tx_active;
2824c87aefeSPatrick Mooney 	uint32_t	esc_TXCW;	/* x0178 transmit config */
2834c87aefeSPatrick Mooney 	uint32_t	esc_TCTL;	/* x0400 transmit ctl */
2844c87aefeSPatrick Mooney 	uint32_t	esc_TIPG;	/* x0410 inter-packet gap */
2854c87aefeSPatrick Mooney 	uint16_t	esc_AIT;	/* x0458 Adaptive Interframe Throttle */
2864c87aefeSPatrick Mooney 	uint64_t	esc_tdba;      	/* verified 64-bit desc table addr */
2874c87aefeSPatrick Mooney 	uint32_t	esc_TDBAL;	/* x3800 desc table addr, low bits */
2884c87aefeSPatrick Mooney 	uint32_t	esc_TDBAH;	/* x3804 desc table addr, hi 32-bits */
2894c87aefeSPatrick Mooney 	uint32_t	esc_TDLEN;	/* x3808 # descriptors in bytes */
2904c87aefeSPatrick Mooney 	uint16_t	esc_TDH;	/* x3810 desc table head idx */
2914c87aefeSPatrick Mooney 	uint16_t	esc_TDHr;	/* internal read version of TDH */
2924c87aefeSPatrick Mooney 	uint16_t	esc_TDT;	/* x3818 desc table tail idx */
2934c87aefeSPatrick Mooney 	uint32_t	esc_TIDV;	/* x3820 intr delay */
2944c87aefeSPatrick Mooney 	uint32_t	esc_TXDCTL;	/* x3828 desc control */
2954c87aefeSPatrick Mooney 	uint32_t	esc_TADV;	/* x382C intr absolute delay */
2964c87aefeSPatrick Mooney 
2974c87aefeSPatrick Mooney 	/* L2 frame acceptance */
2984c87aefeSPatrick Mooney 	struct eth_uni	esc_uni[16];	/* 16 x unicast MAC addresses */
2994c87aefeSPatrick Mooney 	uint32_t	esc_fmcast[128]; /* Multicast filter bit-match */
3004c87aefeSPatrick Mooney 	uint32_t	esc_fvlan[128]; /* VLAN 4096-bit filter */
3014c87aefeSPatrick Mooney 
3024c87aefeSPatrick Mooney 	/* Receive */
3034c87aefeSPatrick Mooney 	struct e1000_rx_desc *esc_rxdesc;
3044c87aefeSPatrick Mooney 	pthread_cond_t	esc_rx_cond;
3054c87aefeSPatrick Mooney 	int		esc_rx_enabled;
3064c87aefeSPatrick Mooney 	int		esc_rx_active;
3074c87aefeSPatrick Mooney 	int		esc_rx_loopback;
3084c87aefeSPatrick Mooney 	uint32_t	esc_RCTL;	/* x0100 receive ctl */
3094c87aefeSPatrick Mooney 	uint32_t	esc_FCRTL;	/* x2160 flow cntl thresh, low */
3104c87aefeSPatrick Mooney 	uint32_t	esc_FCRTH;	/* x2168 flow cntl thresh, hi */
3114c87aefeSPatrick Mooney 	uint64_t	esc_rdba;	/* verified 64-bit desc table addr */
3124c87aefeSPatrick Mooney 	uint32_t	esc_RDBAL;	/* x2800 desc table addr, low bits */
3134c87aefeSPatrick Mooney 	uint32_t	esc_RDBAH;	/* x2804 desc table addr, hi 32-bits*/
3144c87aefeSPatrick Mooney 	uint32_t	esc_RDLEN;	/* x2808 #descriptors */
3154c87aefeSPatrick Mooney 	uint16_t	esc_RDH;	/* x2810 desc table head idx */
3164c87aefeSPatrick Mooney 	uint16_t	esc_RDT;	/* x2818 desc table tail idx */
3174c87aefeSPatrick Mooney 	uint32_t	esc_RDTR;	/* x2820 intr delay */
3184c87aefeSPatrick Mooney 	uint32_t	esc_RXDCTL;	/* x2828 desc control */
3194c87aefeSPatrick Mooney 	uint32_t	esc_RADV;	/* x282C intr absolute delay */
3204c87aefeSPatrick Mooney 	uint32_t	esc_RSRPD;	/* x2C00 recv small packet detect */
3214c87aefeSPatrick Mooney 	uint32_t	esc_RXCSUM;     /* x5000 receive cksum ctl */
3224c87aefeSPatrick Mooney 
3234c87aefeSPatrick Mooney 	/* IO Port register access */
3244c87aefeSPatrick Mooney 	uint32_t io_addr;
3254c87aefeSPatrick Mooney 
3264c87aefeSPatrick Mooney 	/* Shadow copy of MDIC */
3274c87aefeSPatrick Mooney 	uint32_t mdi_control;
3284c87aefeSPatrick Mooney 	/* Shadow copy of EECD */
3294c87aefeSPatrick Mooney 	uint32_t eeprom_control;
3304c87aefeSPatrick Mooney 	/* Latest NVM in/out */
3314c87aefeSPatrick Mooney 	uint16_t nvm_data;
3324c87aefeSPatrick Mooney 	uint16_t nvm_opaddr;
3334c87aefeSPatrick Mooney 	/* stats */
3344c87aefeSPatrick Mooney 	uint32_t missed_pkt_count; /* dropped for no room in rx queue */
3354c87aefeSPatrick Mooney 	uint32_t pkt_rx_by_size[6];
3364c87aefeSPatrick Mooney 	uint32_t pkt_tx_by_size[6];
3374c87aefeSPatrick Mooney 	uint32_t good_pkt_rx_count;
3384c87aefeSPatrick Mooney 	uint32_t bcast_pkt_rx_count;
3394c87aefeSPatrick Mooney 	uint32_t mcast_pkt_rx_count;
3404c87aefeSPatrick Mooney 	uint32_t good_pkt_tx_count;
3414c87aefeSPatrick Mooney 	uint32_t bcast_pkt_tx_count;
3424c87aefeSPatrick Mooney 	uint32_t mcast_pkt_tx_count;
3434c87aefeSPatrick Mooney 	uint32_t oversize_rx_count;
3444c87aefeSPatrick Mooney 	uint32_t tso_tx_count;
3454c87aefeSPatrick Mooney 	uint64_t good_octets_rx;
3464c87aefeSPatrick Mooney 	uint64_t good_octets_tx;
3474c87aefeSPatrick Mooney 	uint64_t missed_octets; /* counts missed and oversized */
3484c87aefeSPatrick Mooney 
3494c87aefeSPatrick Mooney 	uint8_t nvm_bits:6; /* number of bits remaining in/out */
3504c87aefeSPatrick Mooney 	uint8_t nvm_mode:2;
3514c87aefeSPatrick Mooney #define E82545_NVM_MODE_OPADDR  0x0
3524c87aefeSPatrick Mooney #define E82545_NVM_MODE_DATAIN  0x1
3534c87aefeSPatrick Mooney #define E82545_NVM_MODE_DATAOUT 0x2
3544c87aefeSPatrick Mooney 	/* EEPROM data */
3554c87aefeSPatrick Mooney 	uint16_t eeprom_data[E82545_NVM_EEPROM_SIZE];
3564c87aefeSPatrick Mooney };
3574c87aefeSPatrick Mooney 
3584c87aefeSPatrick Mooney static void e82545_reset(struct e82545_softc *sc, int dev);
3594c87aefeSPatrick Mooney static void e82545_rx_enable(struct e82545_softc *sc);
3604c87aefeSPatrick Mooney static void e82545_rx_disable(struct e82545_softc *sc);
3614c87aefeSPatrick Mooney #ifdef	__FreeBSD__
3624c87aefeSPatrick Mooney static void e82545_tap_callback(int fd, enum ev_type type, void *param);
3634c87aefeSPatrick Mooney #endif
3644c87aefeSPatrick Mooney static void e82545_tx_start(struct e82545_softc *sc);
3654c87aefeSPatrick Mooney static void e82545_tx_enable(struct e82545_softc *sc);
3664c87aefeSPatrick Mooney static void e82545_tx_disable(struct e82545_softc *sc);
3674c87aefeSPatrick Mooney 
3684c87aefeSPatrick Mooney static inline int
3694c87aefeSPatrick Mooney e82545_size_stat_index(uint32_t size)
3704c87aefeSPatrick Mooney {
3714c87aefeSPatrick Mooney 	if (size <= 64) {
3724c87aefeSPatrick Mooney 		return 0;
3734c87aefeSPatrick Mooney 	} else if (size >= 1024) {
3744c87aefeSPatrick Mooney 		return 5;
3754c87aefeSPatrick Mooney 	} else {
3764c87aefeSPatrick Mooney 		/* should be 1-4 */
3774c87aefeSPatrick Mooney 		return (ffs(size) - 6);
3784c87aefeSPatrick Mooney 	}
3794c87aefeSPatrick Mooney }
3804c87aefeSPatrick Mooney 
3814c87aefeSPatrick Mooney static void
3824c87aefeSPatrick Mooney e82545_init_eeprom(struct e82545_softc *sc)
3834c87aefeSPatrick Mooney {
3844c87aefeSPatrick Mooney 	uint16_t checksum, i;
3854c87aefeSPatrick Mooney 
3864c87aefeSPatrick Mooney         /* mac addr */
3874c87aefeSPatrick Mooney 	sc->eeprom_data[NVM_MAC_ADDR] = ((uint16_t)sc->esc_mac.octet[0]) |
3884c87aefeSPatrick Mooney 		(((uint16_t)sc->esc_mac.octet[1]) << 8);
3894c87aefeSPatrick Mooney 	sc->eeprom_data[NVM_MAC_ADDR+1] = ((uint16_t)sc->esc_mac.octet[2]) |
3904c87aefeSPatrick Mooney 		(((uint16_t)sc->esc_mac.octet[3]) << 8);
3914c87aefeSPatrick Mooney 	sc->eeprom_data[NVM_MAC_ADDR+2] = ((uint16_t)sc->esc_mac.octet[4]) |
3924c87aefeSPatrick Mooney 		(((uint16_t)sc->esc_mac.octet[5]) << 8);
3934c87aefeSPatrick Mooney 
3944c87aefeSPatrick Mooney 	/* pci ids */
3954c87aefeSPatrick Mooney 	sc->eeprom_data[NVM_SUB_DEV_ID] = E82545_SUBDEV_ID;
3964c87aefeSPatrick Mooney 	sc->eeprom_data[NVM_SUB_VEN_ID] = E82545_VENDOR_ID_INTEL;
3974c87aefeSPatrick Mooney 	sc->eeprom_data[NVM_DEV_ID] = E82545_DEV_ID_82545EM_COPPER;
3984c87aefeSPatrick Mooney 	sc->eeprom_data[NVM_VEN_ID] = E82545_VENDOR_ID_INTEL;
3994c87aefeSPatrick Mooney 
4004c87aefeSPatrick Mooney 	/* fill in the checksum */
4014c87aefeSPatrick Mooney         checksum = 0;
4024c87aefeSPatrick Mooney 	for (i = 0; i < NVM_CHECKSUM_REG; i++) {
4034c87aefeSPatrick Mooney 		checksum += sc->eeprom_data[i];
4044c87aefeSPatrick Mooney 	}
4054c87aefeSPatrick Mooney 	checksum = NVM_SUM - checksum;
4064c87aefeSPatrick Mooney 	sc->eeprom_data[NVM_CHECKSUM_REG] = checksum;
4074c87aefeSPatrick Mooney 	DPRINTF("eeprom checksum: 0x%x\r\n", checksum);
4084c87aefeSPatrick Mooney }
4094c87aefeSPatrick Mooney 
4104c87aefeSPatrick Mooney static void
4114c87aefeSPatrick Mooney e82545_write_mdi(struct e82545_softc *sc, uint8_t reg_addr,
4124c87aefeSPatrick Mooney 			uint8_t phy_addr, uint32_t data)
4134c87aefeSPatrick Mooney {
4144c87aefeSPatrick Mooney 	DPRINTF("Write mdi reg:0x%x phy:0x%x data: 0x%x\r\n", reg_addr, phy_addr, data);
4154c87aefeSPatrick Mooney }
4164c87aefeSPatrick Mooney 
4174c87aefeSPatrick Mooney static uint32_t
4184c87aefeSPatrick Mooney e82545_read_mdi(struct e82545_softc *sc, uint8_t reg_addr,
4194c87aefeSPatrick Mooney 			uint8_t phy_addr)
4204c87aefeSPatrick Mooney {
4214c87aefeSPatrick Mooney 	//DPRINTF("Read mdi reg:0x%x phy:0x%x\r\n", reg_addr, phy_addr);
4224c87aefeSPatrick Mooney 	switch (reg_addr) {
4234c87aefeSPatrick Mooney 	case PHY_STATUS:
4244c87aefeSPatrick Mooney 		return (MII_SR_LINK_STATUS | MII_SR_AUTONEG_CAPS |
4254c87aefeSPatrick Mooney 			MII_SR_AUTONEG_COMPLETE);
4264c87aefeSPatrick Mooney 	case PHY_AUTONEG_ADV:
4274c87aefeSPatrick Mooney 		return NWAY_AR_SELECTOR_FIELD;
4284c87aefeSPatrick Mooney 	case PHY_LP_ABILITY:
4294c87aefeSPatrick Mooney 		return 0;
4304c87aefeSPatrick Mooney 	case PHY_1000T_STATUS:
4314c87aefeSPatrick Mooney 		return (SR_1000T_LP_FD_CAPS | SR_1000T_REMOTE_RX_STATUS |
4324c87aefeSPatrick Mooney 			SR_1000T_LOCAL_RX_STATUS);
4334c87aefeSPatrick Mooney 	case PHY_ID1:
4344c87aefeSPatrick Mooney 		return (M88E1011_I_PHY_ID >> 16) & 0xFFFF;
4354c87aefeSPatrick Mooney 	case PHY_ID2:
4364c87aefeSPatrick Mooney 		return (M88E1011_I_PHY_ID | E82545_REVISION_4) & 0xFFFF;
4374c87aefeSPatrick Mooney 	default:
4384c87aefeSPatrick Mooney 		DPRINTF("Unknown mdi read reg:0x%x phy:0x%x\r\n", reg_addr, phy_addr);
4394c87aefeSPatrick Mooney 		return 0;
4404c87aefeSPatrick Mooney 	}
4414c87aefeSPatrick Mooney 	/* not reached */
4424c87aefeSPatrick Mooney }
4434c87aefeSPatrick Mooney 
4444c87aefeSPatrick Mooney static void
4454c87aefeSPatrick Mooney e82545_eecd_strobe(struct e82545_softc *sc)
4464c87aefeSPatrick Mooney {
4474c87aefeSPatrick Mooney 	/* Microwire state machine */
4484c87aefeSPatrick Mooney 	/*
4494c87aefeSPatrick Mooney 	DPRINTF("eeprom state machine srtobe "
4504c87aefeSPatrick Mooney 		"0x%x 0x%x 0x%x 0x%x\r\n",
4514c87aefeSPatrick Mooney 		sc->nvm_mode, sc->nvm_bits,
4524c87aefeSPatrick Mooney 		sc->nvm_opaddr, sc->nvm_data);*/
4534c87aefeSPatrick Mooney 
4544c87aefeSPatrick Mooney 	if (sc->nvm_bits == 0) {
4554c87aefeSPatrick Mooney 		DPRINTF("eeprom state machine not expecting data! "
4564c87aefeSPatrick Mooney 			"0x%x 0x%x 0x%x 0x%x\r\n",
4574c87aefeSPatrick Mooney 			sc->nvm_mode, sc->nvm_bits,
4584c87aefeSPatrick Mooney 			sc->nvm_opaddr, sc->nvm_data);
4594c87aefeSPatrick Mooney 		return;
4604c87aefeSPatrick Mooney 	}
4614c87aefeSPatrick Mooney 	sc->nvm_bits--;
4624c87aefeSPatrick Mooney 	if (sc->nvm_mode == E82545_NVM_MODE_DATAOUT) {
4634c87aefeSPatrick Mooney 		/* shifting out */
4644c87aefeSPatrick Mooney 		if (sc->nvm_data & 0x8000) {
4654c87aefeSPatrick Mooney 			sc->eeprom_control |= E1000_EECD_DO;
4664c87aefeSPatrick Mooney 		} else {
4674c87aefeSPatrick Mooney 			sc->eeprom_control &= ~E1000_EECD_DO;
4684c87aefeSPatrick Mooney 		}
4694c87aefeSPatrick Mooney 		sc->nvm_data <<= 1;
4704c87aefeSPatrick Mooney 		if (sc->nvm_bits == 0) {
4714c87aefeSPatrick Mooney 			/* read done, back to opcode mode. */
4724c87aefeSPatrick Mooney 			sc->nvm_opaddr = 0;
4734c87aefeSPatrick Mooney 			sc->nvm_mode = E82545_NVM_MODE_OPADDR;
4744c87aefeSPatrick Mooney 			sc->nvm_bits = E82545_NVM_OPADDR_BITS;
4754c87aefeSPatrick Mooney 		}
4764c87aefeSPatrick Mooney 	} else if (sc->nvm_mode == E82545_NVM_MODE_DATAIN) {
4774c87aefeSPatrick Mooney 		/* shifting in */
4784c87aefeSPatrick Mooney 		sc->nvm_data <<= 1;
4794c87aefeSPatrick Mooney 		if (sc->eeprom_control & E1000_EECD_DI) {
4804c87aefeSPatrick Mooney 			sc->nvm_data |= 1;
4814c87aefeSPatrick Mooney 		}
4824c87aefeSPatrick Mooney 		if (sc->nvm_bits == 0) {
4834c87aefeSPatrick Mooney 			/* eeprom write */
4844c87aefeSPatrick Mooney 			uint16_t op = sc->nvm_opaddr & E82545_NVM_OPCODE_MASK;
4854c87aefeSPatrick Mooney 			uint16_t addr = sc->nvm_opaddr & E82545_NVM_ADDR_MASK;
4864c87aefeSPatrick Mooney 			if (op != E82545_NVM_OPCODE_WRITE) {
4874c87aefeSPatrick Mooney 				DPRINTF("Illegal eeprom write op 0x%x\r\n",
4884c87aefeSPatrick Mooney 					sc->nvm_opaddr);
4894c87aefeSPatrick Mooney 			} else if (addr >= E82545_NVM_EEPROM_SIZE) {
4904c87aefeSPatrick Mooney 				DPRINTF("Illegal eeprom write addr 0x%x\r\n",
4914c87aefeSPatrick Mooney 					sc->nvm_opaddr);
4924c87aefeSPatrick Mooney 			} else {
4934c87aefeSPatrick Mooney 				DPRINTF("eeprom write eeprom[0x%x] = 0x%x\r\n",
4944c87aefeSPatrick Mooney 				addr, sc->nvm_data);
4954c87aefeSPatrick Mooney 				sc->eeprom_data[addr] = sc->nvm_data;
4964c87aefeSPatrick Mooney 			}
4974c87aefeSPatrick Mooney 			/* back to opcode mode */
4984c87aefeSPatrick Mooney 			sc->nvm_opaddr = 0;
4994c87aefeSPatrick Mooney 			sc->nvm_mode = E82545_NVM_MODE_OPADDR;
5004c87aefeSPatrick Mooney 			sc->nvm_bits = E82545_NVM_OPADDR_BITS;
5014c87aefeSPatrick Mooney 		}
5024c87aefeSPatrick Mooney 	} else if (sc->nvm_mode == E82545_NVM_MODE_OPADDR) {
5034c87aefeSPatrick Mooney 		sc->nvm_opaddr <<= 1;
5044c87aefeSPatrick Mooney 		if (sc->eeprom_control & E1000_EECD_DI) {
5054c87aefeSPatrick Mooney 			sc->nvm_opaddr |= 1;
5064c87aefeSPatrick Mooney 		}
5074c87aefeSPatrick Mooney 		if (sc->nvm_bits == 0) {
5084c87aefeSPatrick Mooney 			uint16_t op = sc->nvm_opaddr & E82545_NVM_OPCODE_MASK;
5094c87aefeSPatrick Mooney 			switch (op) {
5104c87aefeSPatrick Mooney 			case E82545_NVM_OPCODE_EWEN:
5114c87aefeSPatrick Mooney 				DPRINTF("eeprom write enable: 0x%x\r\n",
5124c87aefeSPatrick Mooney 					sc->nvm_opaddr);
5134c87aefeSPatrick Mooney 				/* back to opcode mode */
5144c87aefeSPatrick Mooney 				sc->nvm_opaddr = 0;
5154c87aefeSPatrick Mooney 				sc->nvm_mode = E82545_NVM_MODE_OPADDR;
5164c87aefeSPatrick Mooney 				sc->nvm_bits = E82545_NVM_OPADDR_BITS;
5174c87aefeSPatrick Mooney 				break;
5184c87aefeSPatrick Mooney 			case E82545_NVM_OPCODE_READ:
5194c87aefeSPatrick Mooney 			{
5204c87aefeSPatrick Mooney 				uint16_t addr = sc->nvm_opaddr &
5214c87aefeSPatrick Mooney 					E82545_NVM_ADDR_MASK;
5224c87aefeSPatrick Mooney 				sc->nvm_mode = E82545_NVM_MODE_DATAOUT;
5234c87aefeSPatrick Mooney 				sc->nvm_bits = E82545_NVM_DATA_BITS;
5244c87aefeSPatrick Mooney 				if (addr < E82545_NVM_EEPROM_SIZE) {
5254c87aefeSPatrick Mooney 					sc->nvm_data = sc->eeprom_data[addr];
5264c87aefeSPatrick Mooney 					DPRINTF("eeprom read: eeprom[0x%x] = 0x%x\r\n",
5274c87aefeSPatrick Mooney 						addr, sc->nvm_data);
5284c87aefeSPatrick Mooney 				} else {
5294c87aefeSPatrick Mooney 					DPRINTF("eeprom illegal read: 0x%x\r\n",
5304c87aefeSPatrick Mooney 						sc->nvm_opaddr);
5314c87aefeSPatrick Mooney 					sc->nvm_data = 0;
5324c87aefeSPatrick Mooney 				}
5334c87aefeSPatrick Mooney 				break;
5344c87aefeSPatrick Mooney 			}
5354c87aefeSPatrick Mooney 			case E82545_NVM_OPCODE_WRITE:
5364c87aefeSPatrick Mooney 				sc->nvm_mode = E82545_NVM_MODE_DATAIN;
5374c87aefeSPatrick Mooney 				sc->nvm_bits = E82545_NVM_DATA_BITS;
5384c87aefeSPatrick Mooney 				sc->nvm_data = 0;
5394c87aefeSPatrick Mooney 				break;
5404c87aefeSPatrick Mooney 			default:
5414c87aefeSPatrick Mooney 				DPRINTF("eeprom unknown op: 0x%x\r\r",
5424c87aefeSPatrick Mooney 					sc->nvm_opaddr);
5434c87aefeSPatrick Mooney 				/* back to opcode mode */
5444c87aefeSPatrick Mooney 				sc->nvm_opaddr = 0;
5454c87aefeSPatrick Mooney 				sc->nvm_mode = E82545_NVM_MODE_OPADDR;
5464c87aefeSPatrick Mooney 				sc->nvm_bits = E82545_NVM_OPADDR_BITS;
5474c87aefeSPatrick Mooney 			}
5484c87aefeSPatrick Mooney 		}
5494c87aefeSPatrick Mooney 	} else {
5504c87aefeSPatrick Mooney 		DPRINTF("eeprom state machine wrong state! "
5514c87aefeSPatrick Mooney 			"0x%x 0x%x 0x%x 0x%x\r\n",
5524c87aefeSPatrick Mooney 			sc->nvm_mode, sc->nvm_bits,
5534c87aefeSPatrick Mooney 			sc->nvm_opaddr, sc->nvm_data);
5544c87aefeSPatrick Mooney 	}
5554c87aefeSPatrick Mooney }
5564c87aefeSPatrick Mooney 
5574c87aefeSPatrick Mooney #ifdef	__FreeBSD__
5584c87aefeSPatrick Mooney static void
5594c87aefeSPatrick Mooney e82545_itr_callback(int fd, enum ev_type type, void *param)
5604c87aefeSPatrick Mooney {
5614c87aefeSPatrick Mooney 	uint32_t new;
5624c87aefeSPatrick Mooney 	struct e82545_softc *sc = param;
5634c87aefeSPatrick Mooney 
5644c87aefeSPatrick Mooney 	pthread_mutex_lock(&sc->esc_mtx);
5654c87aefeSPatrick Mooney 	new = sc->esc_ICR & sc->esc_IMS;
5664c87aefeSPatrick Mooney 	if (new && !sc->esc_irq_asserted) {
5674c87aefeSPatrick Mooney 		DPRINTF("itr callback: lintr assert %x\r\n", new);
5684c87aefeSPatrick Mooney 		sc->esc_irq_asserted = 1;
5694c87aefeSPatrick Mooney 		pci_lintr_assert(sc->esc_pi);
5704c87aefeSPatrick Mooney 	} else {
5714c87aefeSPatrick Mooney 		mevent_delete(sc->esc_mevpitr);
5724c87aefeSPatrick Mooney 		sc->esc_mevpitr = NULL;
5734c87aefeSPatrick Mooney 	}
5744c87aefeSPatrick Mooney 	pthread_mutex_unlock(&sc->esc_mtx);
5754c87aefeSPatrick Mooney }
5764c87aefeSPatrick Mooney #endif
5774c87aefeSPatrick Mooney 
5784c87aefeSPatrick Mooney static void
5794c87aefeSPatrick Mooney e82545_icr_assert(struct e82545_softc *sc, uint32_t bits)
5804c87aefeSPatrick Mooney {
5814c87aefeSPatrick Mooney 	uint32_t new;
5824c87aefeSPatrick Mooney 
5834c87aefeSPatrick Mooney 	DPRINTF("icr assert: 0x%x\r\n", bits);
5844c87aefeSPatrick Mooney 
5854c87aefeSPatrick Mooney 	/*
5864c87aefeSPatrick Mooney 	 * An interrupt is only generated if bits are set that
5874c87aefeSPatrick Mooney 	 * aren't already in the ICR, these bits are unmasked,
5884c87aefeSPatrick Mooney 	 * and there isn't an interrupt already pending.
5894c87aefeSPatrick Mooney 	 */
5904c87aefeSPatrick Mooney 	new = bits & ~sc->esc_ICR & sc->esc_IMS;
5914c87aefeSPatrick Mooney 	sc->esc_ICR |= bits;
5924c87aefeSPatrick Mooney 
5934c87aefeSPatrick Mooney 	if (new == 0) {
5944c87aefeSPatrick Mooney 		DPRINTF("icr assert: masked %x, ims %x\r\n", new, sc->esc_IMS);
5954c87aefeSPatrick Mooney 	} else if (sc->esc_mevpitr != NULL) {
5964c87aefeSPatrick Mooney 		DPRINTF("icr assert: throttled %x, ims %x\r\n", new, sc->esc_IMS);
5974c87aefeSPatrick Mooney 	} else if (!sc->esc_irq_asserted) {
5984c87aefeSPatrick Mooney 		DPRINTF("icr assert: lintr assert %x\r\n", new);
5994c87aefeSPatrick Mooney 		sc->esc_irq_asserted = 1;
6004c87aefeSPatrick Mooney 		pci_lintr_assert(sc->esc_pi);
6014c87aefeSPatrick Mooney 		if (sc->esc_ITR != 0) {
6024c87aefeSPatrick Mooney #ifdef	__FreeBSD__
6034c87aefeSPatrick Mooney 			sc->esc_mevpitr = mevent_add(
6044c87aefeSPatrick Mooney 			    (sc->esc_ITR + 3905) / 3906,  /* 256ns -> 1ms */
6054c87aefeSPatrick Mooney 			    EVF_TIMER, e82545_itr_callback, sc);
6064c87aefeSPatrick Mooney #endif
6074c87aefeSPatrick Mooney 		}
6084c87aefeSPatrick Mooney 	}
6094c87aefeSPatrick Mooney }
6104c87aefeSPatrick Mooney 
6114c87aefeSPatrick Mooney static void
6124c87aefeSPatrick Mooney e82545_ims_change(struct e82545_softc *sc, uint32_t bits)
6134c87aefeSPatrick Mooney {
6144c87aefeSPatrick Mooney 	uint32_t new;
6154c87aefeSPatrick Mooney 
6164c87aefeSPatrick Mooney 	/*
6174c87aefeSPatrick Mooney 	 * Changing the mask may allow previously asserted
6184c87aefeSPatrick Mooney 	 * but masked interrupt requests to generate an interrupt.
6194c87aefeSPatrick Mooney 	 */
6204c87aefeSPatrick Mooney 	new = bits & sc->esc_ICR & ~sc->esc_IMS;
6214c87aefeSPatrick Mooney 	sc->esc_IMS |= bits;
6224c87aefeSPatrick Mooney 
6234c87aefeSPatrick Mooney 	if (new == 0) {
6244c87aefeSPatrick Mooney 		DPRINTF("ims change: masked %x, ims %x\r\n", new, sc->esc_IMS);
6254c87aefeSPatrick Mooney 	} else if (sc->esc_mevpitr != NULL) {
6264c87aefeSPatrick Mooney 		DPRINTF("ims change: throttled %x, ims %x\r\n", new, sc->esc_IMS);
6274c87aefeSPatrick Mooney 	} else if (!sc->esc_irq_asserted) {
6284c87aefeSPatrick Mooney 		DPRINTF("ims change: lintr assert %x\n\r", new);
6294c87aefeSPatrick Mooney 		sc->esc_irq_asserted = 1;
6304c87aefeSPatrick Mooney 		pci_lintr_assert(sc->esc_pi);
6314c87aefeSPatrick Mooney 		if (sc->esc_ITR != 0) {
6324c87aefeSPatrick Mooney #ifdef	__FreeBSD__
6334c87aefeSPatrick Mooney 			sc->esc_mevpitr = mevent_add(
6344c87aefeSPatrick Mooney 			    (sc->esc_ITR + 3905) / 3906,  /* 256ns -> 1ms */
6354c87aefeSPatrick Mooney 			    EVF_TIMER, e82545_itr_callback, sc);
6364c87aefeSPatrick Mooney #endif
6374c87aefeSPatrick Mooney 		}
6384c87aefeSPatrick Mooney 	}
6394c87aefeSPatrick Mooney }
6404c87aefeSPatrick Mooney 
6414c87aefeSPatrick Mooney static void
6424c87aefeSPatrick Mooney e82545_icr_deassert(struct e82545_softc *sc, uint32_t bits)
6434c87aefeSPatrick Mooney {
6444c87aefeSPatrick Mooney 
6454c87aefeSPatrick Mooney 	DPRINTF("icr deassert: 0x%x\r\n", bits);
6464c87aefeSPatrick Mooney 	sc->esc_ICR &= ~bits;
6474c87aefeSPatrick Mooney 
6484c87aefeSPatrick Mooney 	/*
6494c87aefeSPatrick Mooney 	 * If there are no longer any interrupt sources and there
6504c87aefeSPatrick Mooney 	 * was an asserted interrupt, clear it
6514c87aefeSPatrick Mooney 	 */
6524c87aefeSPatrick Mooney 	if (sc->esc_irq_asserted && !(sc->esc_ICR & sc->esc_IMS)) {
6534c87aefeSPatrick Mooney 		DPRINTF("icr deassert: lintr deassert %x\r\n", bits);
6544c87aefeSPatrick Mooney 		pci_lintr_deassert(sc->esc_pi);
6554c87aefeSPatrick Mooney 		sc->esc_irq_asserted = 0;
6564c87aefeSPatrick Mooney 	}
6574c87aefeSPatrick Mooney }
6584c87aefeSPatrick Mooney 
6594c87aefeSPatrick Mooney static void
6604c87aefeSPatrick Mooney e82545_intr_write(struct e82545_softc *sc, uint32_t offset, uint32_t value)
6614c87aefeSPatrick Mooney {
6624c87aefeSPatrick Mooney 
6634c87aefeSPatrick Mooney 	DPRINTF("intr_write: off %x, val %x\n\r", offset, value);
6644c87aefeSPatrick Mooney 
6654c87aefeSPatrick Mooney 	switch (offset) {
6664c87aefeSPatrick Mooney 	case E1000_ICR:
6674c87aefeSPatrick Mooney 		e82545_icr_deassert(sc, value);
6684c87aefeSPatrick Mooney 		break;
6694c87aefeSPatrick Mooney 	case E1000_ITR:
6704c87aefeSPatrick Mooney 		sc->esc_ITR = value;
6714c87aefeSPatrick Mooney 		break;
6724c87aefeSPatrick Mooney 	case E1000_ICS:
6734c87aefeSPatrick Mooney 		sc->esc_ICS = value;	/* not used: store for debug */
6744c87aefeSPatrick Mooney 		e82545_icr_assert(sc, value);
6754c87aefeSPatrick Mooney 		break;
6764c87aefeSPatrick Mooney 	case E1000_IMS:
6774c87aefeSPatrick Mooney 		e82545_ims_change(sc, value);
6784c87aefeSPatrick Mooney 		break;
6794c87aefeSPatrick Mooney 	case E1000_IMC:
6804c87aefeSPatrick Mooney 		sc->esc_IMC = value;	/* for debug */
6814c87aefeSPatrick Mooney 		sc->esc_IMS &= ~value;
6824c87aefeSPatrick Mooney 		// XXX clear interrupts if all ICR bits now masked
6834c87aefeSPatrick Mooney 		// and interrupt was pending ?
6844c87aefeSPatrick Mooney 		break;
6854c87aefeSPatrick Mooney 	default:
6864c87aefeSPatrick Mooney 		break;
6874c87aefeSPatrick Mooney 	}
6884c87aefeSPatrick Mooney }
6894c87aefeSPatrick Mooney 
6904c87aefeSPatrick Mooney static uint32_t
6914c87aefeSPatrick Mooney e82545_intr_read(struct e82545_softc *sc, uint32_t offset)
6924c87aefeSPatrick Mooney {
6934c87aefeSPatrick Mooney 	uint32_t retval;
6944c87aefeSPatrick Mooney 
6954c87aefeSPatrick Mooney 	retval = 0;
6964c87aefeSPatrick Mooney 
6974c87aefeSPatrick Mooney 	DPRINTF("intr_read: off %x\n\r", offset);
6984c87aefeSPatrick Mooney 
6994c87aefeSPatrick Mooney 	switch (offset) {
7004c87aefeSPatrick Mooney 	case E1000_ICR:
7014c87aefeSPatrick Mooney 		retval = sc->esc_ICR;
7024c87aefeSPatrick Mooney 		sc->esc_ICR = 0;
7034c87aefeSPatrick Mooney 		e82545_icr_deassert(sc, ~0);
7044c87aefeSPatrick Mooney 		break;
7054c87aefeSPatrick Mooney 	case E1000_ITR:
7064c87aefeSPatrick Mooney 		retval = sc->esc_ITR;
7074c87aefeSPatrick Mooney 		break;
7084c87aefeSPatrick Mooney 	case E1000_ICS:
7094c87aefeSPatrick Mooney 		/* write-only register */
7104c87aefeSPatrick Mooney 		break;
7114c87aefeSPatrick Mooney 	case E1000_IMS:
7124c87aefeSPatrick Mooney 		retval = sc->esc_IMS;
7134c87aefeSPatrick Mooney 		break;
7144c87aefeSPatrick Mooney 	case E1000_IMC:
7154c87aefeSPatrick Mooney 		/* write-only register */
7164c87aefeSPatrick Mooney 		break;
7174c87aefeSPatrick Mooney 	default:
7184c87aefeSPatrick Mooney 		break;
7194c87aefeSPatrick Mooney 	}
7204c87aefeSPatrick Mooney 
7214c87aefeSPatrick Mooney 	return (retval);
7224c87aefeSPatrick Mooney }
7234c87aefeSPatrick Mooney 
7244c87aefeSPatrick Mooney static void
7254c87aefeSPatrick Mooney e82545_devctl(struct e82545_softc *sc, uint32_t val)
7264c87aefeSPatrick Mooney {
7274c87aefeSPatrick Mooney 
7284c87aefeSPatrick Mooney 	sc->esc_CTRL = val & ~E1000_CTRL_RST;
7294c87aefeSPatrick Mooney 
7304c87aefeSPatrick Mooney 	if (val & E1000_CTRL_RST) {
7314c87aefeSPatrick Mooney 		DPRINTF("e1k: s/w reset, ctl %x\n", val);
7324c87aefeSPatrick Mooney 		e82545_reset(sc, 1);
7334c87aefeSPatrick Mooney 	}
7344c87aefeSPatrick Mooney 	/* XXX check for phy reset ? */
7354c87aefeSPatrick Mooney }
7364c87aefeSPatrick Mooney 
7374c87aefeSPatrick Mooney static void
7384c87aefeSPatrick Mooney e82545_rx_update_rdba(struct e82545_softc *sc)
7394c87aefeSPatrick Mooney {
7404c87aefeSPatrick Mooney 
7414c87aefeSPatrick Mooney 	/* XXX verify desc base/len within phys mem range */
7424c87aefeSPatrick Mooney 	sc->esc_rdba = (uint64_t)sc->esc_RDBAH << 32 |
7434c87aefeSPatrick Mooney 	    sc->esc_RDBAL;
7444c87aefeSPatrick Mooney 
7454c87aefeSPatrick Mooney 	/* Cache host mapping of guest descriptor array */
7464c87aefeSPatrick Mooney 	sc->esc_rxdesc = paddr_guest2host(sc->esc_ctx,
7474c87aefeSPatrick Mooney 	    sc->esc_rdba, sc->esc_RDLEN);
7484c87aefeSPatrick Mooney }
7494c87aefeSPatrick Mooney 
7504c87aefeSPatrick Mooney static void
7514c87aefeSPatrick Mooney e82545_rx_ctl(struct e82545_softc *sc, uint32_t val)
7524c87aefeSPatrick Mooney {
7534c87aefeSPatrick Mooney 	int on;
7544c87aefeSPatrick Mooney 
7554c87aefeSPatrick Mooney 	on = ((val & E1000_RCTL_EN) == E1000_RCTL_EN);
7564c87aefeSPatrick Mooney 
7574c87aefeSPatrick Mooney 	/* Save RCTL after stripping reserved bits 31:27,24,21,14,11:10,0 */
7584c87aefeSPatrick Mooney 	sc->esc_RCTL = val & ~0xF9204c01;
7594c87aefeSPatrick Mooney 
7604c87aefeSPatrick Mooney 	DPRINTF("rx_ctl - %s RCTL %x, val %x\n",
7614c87aefeSPatrick Mooney 		on ? "on" : "off", sc->esc_RCTL, val);
7624c87aefeSPatrick Mooney 
7634c87aefeSPatrick Mooney 	/* state change requested */
7644c87aefeSPatrick Mooney 	if (on != sc->esc_rx_enabled) {
7654c87aefeSPatrick Mooney 		if (on) {
7664c87aefeSPatrick Mooney 			/* Catch disallowed/unimplemented settings */
7674c87aefeSPatrick Mooney 			//assert(!(val & E1000_RCTL_LBM_TCVR));
7684c87aefeSPatrick Mooney 
7694c87aefeSPatrick Mooney 			if (sc->esc_RCTL & E1000_RCTL_LBM_TCVR) {
7704c87aefeSPatrick Mooney 				sc->esc_rx_loopback = 1;
7714c87aefeSPatrick Mooney 			} else {
7724c87aefeSPatrick Mooney 				sc->esc_rx_loopback = 0;
7734c87aefeSPatrick Mooney 			}
7744c87aefeSPatrick Mooney 
7754c87aefeSPatrick Mooney 			e82545_rx_update_rdba(sc);
7764c87aefeSPatrick Mooney 			e82545_rx_enable(sc);
7774c87aefeSPatrick Mooney 		} else {
7784c87aefeSPatrick Mooney 			e82545_rx_disable(sc);
7794c87aefeSPatrick Mooney 			sc->esc_rx_loopback = 0;
7804c87aefeSPatrick Mooney 			sc->esc_rdba = 0;
7814c87aefeSPatrick Mooney 			sc->esc_rxdesc = NULL;
7824c87aefeSPatrick Mooney 		}
7834c87aefeSPatrick Mooney 	}
7844c87aefeSPatrick Mooney }
7854c87aefeSPatrick Mooney 
7864c87aefeSPatrick Mooney static void
7874c87aefeSPatrick Mooney e82545_tx_update_tdba(struct e82545_softc *sc)
7884c87aefeSPatrick Mooney {
7894c87aefeSPatrick Mooney 
7904c87aefeSPatrick Mooney 	/* XXX verify desc base/len within phys mem range */
7914c87aefeSPatrick Mooney 	sc->esc_tdba = (uint64_t)sc->esc_TDBAH << 32 | sc->esc_TDBAL;
7924c87aefeSPatrick Mooney 
7934c87aefeSPatrick Mooney 	/* Cache host mapping of guest descriptor array */
7944c87aefeSPatrick Mooney 	sc->esc_txdesc = paddr_guest2host(sc->esc_ctx, sc->esc_tdba,
7954c87aefeSPatrick Mooney             sc->esc_TDLEN);
7964c87aefeSPatrick Mooney }
7974c87aefeSPatrick Mooney 
7984c87aefeSPatrick Mooney static void
7994c87aefeSPatrick Mooney e82545_tx_ctl(struct e82545_softc *sc, uint32_t val)
8004c87aefeSPatrick Mooney {
8014c87aefeSPatrick Mooney 	int on;
8024c87aefeSPatrick Mooney 
8034c87aefeSPatrick Mooney 	on = ((val & E1000_TCTL_EN) == E1000_TCTL_EN);
8044c87aefeSPatrick Mooney 
8054c87aefeSPatrick Mooney 	/* ignore TCTL_EN settings that don't change state */
8064c87aefeSPatrick Mooney 	if (on == sc->esc_tx_enabled)
8074c87aefeSPatrick Mooney 		return;
8084c87aefeSPatrick Mooney 
8094c87aefeSPatrick Mooney 	if (on) {
8104c87aefeSPatrick Mooney 		e82545_tx_update_tdba(sc);
8114c87aefeSPatrick Mooney 		e82545_tx_enable(sc);
8124c87aefeSPatrick Mooney 	} else {
8134c87aefeSPatrick Mooney 		e82545_tx_disable(sc);
8144c87aefeSPatrick Mooney 		sc->esc_tdba = 0;
8154c87aefeSPatrick Mooney 		sc->esc_txdesc = NULL;
8164c87aefeSPatrick Mooney 	}
8174c87aefeSPatrick Mooney 
8184c87aefeSPatrick Mooney 	/* Save TCTL value after stripping reserved bits 31:25,23,2,0 */
8194c87aefeSPatrick Mooney 	sc->esc_TCTL = val & ~0xFE800005;
8204c87aefeSPatrick Mooney }
8214c87aefeSPatrick Mooney 
8224c87aefeSPatrick Mooney int
8234c87aefeSPatrick Mooney e82545_bufsz(uint32_t rctl)
8244c87aefeSPatrick Mooney {
8254c87aefeSPatrick Mooney 
8264c87aefeSPatrick Mooney 	switch (rctl & (E1000_RCTL_BSEX | E1000_RCTL_SZ_256)) {
8274c87aefeSPatrick Mooney 	case (E1000_RCTL_SZ_2048): return (2048);
8284c87aefeSPatrick Mooney 	case (E1000_RCTL_SZ_1024): return (1024);
8294c87aefeSPatrick Mooney 	case (E1000_RCTL_SZ_512): return (512);
8304c87aefeSPatrick Mooney 	case (E1000_RCTL_SZ_256): return (256);
8314c87aefeSPatrick Mooney 	case (E1000_RCTL_BSEX|E1000_RCTL_SZ_16384): return (16384);
8324c87aefeSPatrick Mooney 	case (E1000_RCTL_BSEX|E1000_RCTL_SZ_8192): return (8192);
8334c87aefeSPatrick Mooney 	case (E1000_RCTL_BSEX|E1000_RCTL_SZ_4096): return (4096);
8344c87aefeSPatrick Mooney 	}
8354c87aefeSPatrick Mooney 	return (256);	/* Forbidden value. */
8364c87aefeSPatrick Mooney }
8374c87aefeSPatrick Mooney 
8384c87aefeSPatrick Mooney #ifdef	__FreeBSD__
8394c87aefeSPatrick Mooney static uint8_t dummybuf[2048];
8404c87aefeSPatrick Mooney 
8414c87aefeSPatrick Mooney /* XXX one packet at a time until this is debugged */
8424c87aefeSPatrick Mooney static void
8434c87aefeSPatrick Mooney e82545_tap_callback(int fd, enum ev_type type, void *param)
8444c87aefeSPatrick Mooney {
8454c87aefeSPatrick Mooney 	struct e82545_softc *sc = param;
8464c87aefeSPatrick Mooney 	struct e1000_rx_desc *rxd;
8474c87aefeSPatrick Mooney 	struct iovec vec[64];
8484c87aefeSPatrick Mooney 	int left, len, lim, maxpktsz, maxpktdesc, bufsz, i, n, size;
8494c87aefeSPatrick Mooney 	uint32_t cause = 0;
8504c87aefeSPatrick Mooney 	uint16_t *tp, tag, head;
8514c87aefeSPatrick Mooney 
8524c87aefeSPatrick Mooney 	pthread_mutex_lock(&sc->esc_mtx);
8534c87aefeSPatrick Mooney 	DPRINTF("rx_run: head %x, tail %x\r\n", sc->esc_RDH, sc->esc_RDT);
8544c87aefeSPatrick Mooney 
8554c87aefeSPatrick Mooney 	if (!sc->esc_rx_enabled || sc->esc_rx_loopback) {
8564c87aefeSPatrick Mooney 		DPRINTF("rx disabled (!%d || %d) -- packet(s) dropped\r\n",
8574c87aefeSPatrick Mooney 		    sc->esc_rx_enabled, sc->esc_rx_loopback);
8584c87aefeSPatrick Mooney 		while (read(sc->esc_tapfd, dummybuf, sizeof(dummybuf)) > 0) {
8594c87aefeSPatrick Mooney 		}
8604c87aefeSPatrick Mooney 		goto done1;
8614c87aefeSPatrick Mooney 	}
8624c87aefeSPatrick Mooney 	bufsz = e82545_bufsz(sc->esc_RCTL);
8634c87aefeSPatrick Mooney 	maxpktsz = (sc->esc_RCTL & E1000_RCTL_LPE) ? 16384 : 1522;
8644c87aefeSPatrick Mooney 	maxpktdesc = (maxpktsz + bufsz - 1) / bufsz;
8654c87aefeSPatrick Mooney 	size = sc->esc_RDLEN / 16;
8664c87aefeSPatrick Mooney 	head = sc->esc_RDH;
8674c87aefeSPatrick Mooney 	left = (size + sc->esc_RDT - head) % size;
8684c87aefeSPatrick Mooney 	if (left < maxpktdesc) {
8694c87aefeSPatrick Mooney 		DPRINTF("rx overflow (%d < %d) -- packet(s) dropped\r\n",
8704c87aefeSPatrick Mooney 		    left, maxpktdesc);
8714c87aefeSPatrick Mooney 		while (read(sc->esc_tapfd, dummybuf, sizeof(dummybuf)) > 0) {
8724c87aefeSPatrick Mooney 		}
8734c87aefeSPatrick Mooney 		goto done1;
8744c87aefeSPatrick Mooney 	}
8754c87aefeSPatrick Mooney 
8764c87aefeSPatrick Mooney 	sc->esc_rx_active = 1;
8774c87aefeSPatrick Mooney 	pthread_mutex_unlock(&sc->esc_mtx);
8784c87aefeSPatrick Mooney 
8794c87aefeSPatrick Mooney 	for (lim = size / 4; lim > 0 && left >= maxpktdesc; lim -= n) {
8804c87aefeSPatrick Mooney 
8814c87aefeSPatrick Mooney 		/* Grab rx descriptor pointed to by the head pointer */
8824c87aefeSPatrick Mooney 		for (i = 0; i < maxpktdesc; i++) {
8834c87aefeSPatrick Mooney 			rxd = &sc->esc_rxdesc[(head + i) % size];
8844c87aefeSPatrick Mooney 			vec[i].iov_base = paddr_guest2host(sc->esc_ctx,
8854c87aefeSPatrick Mooney 			    rxd->buffer_addr, bufsz);
8864c87aefeSPatrick Mooney 			vec[i].iov_len = bufsz;
8874c87aefeSPatrick Mooney 		}
8884c87aefeSPatrick Mooney 		len = readv(sc->esc_tapfd, vec, maxpktdesc);
8894c87aefeSPatrick Mooney 		if (len <= 0) {
8904c87aefeSPatrick Mooney 			DPRINTF("tap: readv() returned %d\n", len);
8914c87aefeSPatrick Mooney 			goto done;
8924c87aefeSPatrick Mooney 		}
8934c87aefeSPatrick Mooney 
8944c87aefeSPatrick Mooney 		/*
8954c87aefeSPatrick Mooney 		 * Adjust the packet length based on whether the CRC needs
8964c87aefeSPatrick Mooney 		 * to be stripped or if the packet is less than the minimum
8974c87aefeSPatrick Mooney 		 * eth packet size.
8984c87aefeSPatrick Mooney 		 */
8994c87aefeSPatrick Mooney 		if (len < ETHER_MIN_LEN - ETHER_CRC_LEN)
9004c87aefeSPatrick Mooney 			len = ETHER_MIN_LEN - ETHER_CRC_LEN;
9014c87aefeSPatrick Mooney 		if (!(sc->esc_RCTL & E1000_RCTL_SECRC))
9024c87aefeSPatrick Mooney 			len += ETHER_CRC_LEN;
9034c87aefeSPatrick Mooney 		n = (len + bufsz - 1) / bufsz;
9044c87aefeSPatrick Mooney 
9054c87aefeSPatrick Mooney 		DPRINTF("packet read %d bytes, %d segs, head %d\r\n",
9064c87aefeSPatrick Mooney 		    len, n, head);
9074c87aefeSPatrick Mooney 
9084c87aefeSPatrick Mooney 		/* Apply VLAN filter. */
9094c87aefeSPatrick Mooney 		tp = (uint16_t *)vec[0].iov_base + 6;
9104c87aefeSPatrick Mooney 		if ((sc->esc_RCTL & E1000_RCTL_VFE) &&
9114c87aefeSPatrick Mooney 		    (ntohs(tp[0]) == sc->esc_VET)) {
9124c87aefeSPatrick Mooney 			tag = ntohs(tp[1]) & 0x0fff;
9134c87aefeSPatrick Mooney 			if ((sc->esc_fvlan[tag >> 5] &
9144c87aefeSPatrick Mooney 			    (1 << (tag & 0x1f))) != 0) {
9154c87aefeSPatrick Mooney 				DPRINTF("known VLAN %d\r\n", tag);
9164c87aefeSPatrick Mooney 			} else {
9174c87aefeSPatrick Mooney 				DPRINTF("unknown VLAN %d\r\n", tag);
9184c87aefeSPatrick Mooney 				n = 0;
9194c87aefeSPatrick Mooney 				continue;
9204c87aefeSPatrick Mooney 			}
9214c87aefeSPatrick Mooney 		}
9224c87aefeSPatrick Mooney 
9234c87aefeSPatrick Mooney 		/* Update all consumed descriptors. */
9244c87aefeSPatrick Mooney 		for (i = 0; i < n - 1; i++) {
9254c87aefeSPatrick Mooney 			rxd = &sc->esc_rxdesc[(head + i) % size];
9264c87aefeSPatrick Mooney 			rxd->length = bufsz;
9274c87aefeSPatrick Mooney 			rxd->csum = 0;
9284c87aefeSPatrick Mooney 			rxd->errors = 0;
9294c87aefeSPatrick Mooney 			rxd->special = 0;
9304c87aefeSPatrick Mooney 			rxd->status = E1000_RXD_STAT_DD;
9314c87aefeSPatrick Mooney 		}
9324c87aefeSPatrick Mooney 		rxd = &sc->esc_rxdesc[(head + i) % size];
9334c87aefeSPatrick Mooney 		rxd->length = len % bufsz;
9344c87aefeSPatrick Mooney 		rxd->csum = 0;
9354c87aefeSPatrick Mooney 		rxd->errors = 0;
9364c87aefeSPatrick Mooney 		rxd->special = 0;
9374c87aefeSPatrick Mooney 		/* XXX signal no checksum for now */
9384c87aefeSPatrick Mooney 		rxd->status = E1000_RXD_STAT_PIF | E1000_RXD_STAT_IXSM |
9394c87aefeSPatrick Mooney 		    E1000_RXD_STAT_EOP | E1000_RXD_STAT_DD;
9404c87aefeSPatrick Mooney 
9414c87aefeSPatrick Mooney 		/* Schedule receive interrupts. */
9424c87aefeSPatrick Mooney 		if (len <= sc->esc_RSRPD) {
9434c87aefeSPatrick Mooney 			cause |= E1000_ICR_SRPD | E1000_ICR_RXT0;
9444c87aefeSPatrick Mooney 		} else {
9454c87aefeSPatrick Mooney 			/* XXX: RDRT and RADV timers should be here. */
9464c87aefeSPatrick Mooney 			cause |= E1000_ICR_RXT0;
9474c87aefeSPatrick Mooney 		}
9484c87aefeSPatrick Mooney 
9494c87aefeSPatrick Mooney 		head = (head + n) % size;
9504c87aefeSPatrick Mooney 		left -= n;
9514c87aefeSPatrick Mooney 	}
9524c87aefeSPatrick Mooney 
9534c87aefeSPatrick Mooney done:
9544c87aefeSPatrick Mooney 	pthread_mutex_lock(&sc->esc_mtx);
9554c87aefeSPatrick Mooney 	sc->esc_rx_active = 0;
9564c87aefeSPatrick Mooney 	if (sc->esc_rx_enabled == 0)
9574c87aefeSPatrick Mooney 		pthread_cond_signal(&sc->esc_rx_cond);
9584c87aefeSPatrick Mooney 
9594c87aefeSPatrick Mooney 	sc->esc_RDH = head;
9604c87aefeSPatrick Mooney 	/* Respect E1000_RCTL_RDMTS */
9614c87aefeSPatrick Mooney 	left = (size + sc->esc_RDT - head) % size;
9624c87aefeSPatrick Mooney 	if (left < (size >> (((sc->esc_RCTL >> 8) & 3) + 1)))
9634c87aefeSPatrick Mooney 		cause |= E1000_ICR_RXDMT0;
9644c87aefeSPatrick Mooney 	/* Assert all accumulated interrupts. */
9654c87aefeSPatrick Mooney 	if (cause != 0)
9664c87aefeSPatrick Mooney 		e82545_icr_assert(sc, cause);
9674c87aefeSPatrick Mooney done1:
9684c87aefeSPatrick Mooney 	DPRINTF("rx_run done: head %x, tail %x\r\n", sc->esc_RDH, sc->esc_RDT);
9694c87aefeSPatrick Mooney 	pthread_mutex_unlock(&sc->esc_mtx);
9704c87aefeSPatrick Mooney }
9714c87aefeSPatrick Mooney #endif
9724c87aefeSPatrick Mooney 
9734c87aefeSPatrick Mooney static uint16_t
9744c87aefeSPatrick Mooney e82545_carry(uint32_t sum)
9754c87aefeSPatrick Mooney {
9764c87aefeSPatrick Mooney 
9774c87aefeSPatrick Mooney 	sum = (sum & 0xFFFF) + (sum >> 16);
9784c87aefeSPatrick Mooney 	if (sum > 0xFFFF)
9794c87aefeSPatrick Mooney 		sum -= 0xFFFF;
9804c87aefeSPatrick Mooney 	return (sum);
9814c87aefeSPatrick Mooney }
9824c87aefeSPatrick Mooney 
9834c87aefeSPatrick Mooney static uint16_t
9844c87aefeSPatrick Mooney #ifdef __FreeBSD__
9854c87aefeSPatrick Mooney e82545_buf_checksum(uint8_t *buf, int len)
9864c87aefeSPatrick Mooney #else
9874c87aefeSPatrick Mooney e82545_buf_checksum(caddr_t buf, int len)
9884c87aefeSPatrick Mooney #endif
9894c87aefeSPatrick Mooney {
9904c87aefeSPatrick Mooney 	int i;
9914c87aefeSPatrick Mooney 	uint32_t sum = 0;
9924c87aefeSPatrick Mooney 
9934c87aefeSPatrick Mooney 	/* Checksum all the pairs of bytes first... */
9944c87aefeSPatrick Mooney 	for (i = 0; i < (len & ~1U); i += 2)
9954c87aefeSPatrick Mooney 		sum += *((u_int16_t *)(buf + i));
9964c87aefeSPatrick Mooney 
9974c87aefeSPatrick Mooney 	/*
9984c87aefeSPatrick Mooney 	 * If there's a single byte left over, checksum it, too.
9994c87aefeSPatrick Mooney 	 * Network byte order is big-endian, so the remaining byte is
10004c87aefeSPatrick Mooney 	 * the high byte.
10014c87aefeSPatrick Mooney 	 */
10024c87aefeSPatrick Mooney 	if (i < len)
10034c87aefeSPatrick Mooney 		sum += htons(buf[i] << 8);
10044c87aefeSPatrick Mooney 
10054c87aefeSPatrick Mooney 	return (e82545_carry(sum));
10064c87aefeSPatrick Mooney }
10074c87aefeSPatrick Mooney 
10084c87aefeSPatrick Mooney static uint16_t
10094c87aefeSPatrick Mooney e82545_iov_checksum(struct iovec *iov, int iovcnt, int off, int len)
10104c87aefeSPatrick Mooney {
10114c87aefeSPatrick Mooney 	int now, odd;
10124c87aefeSPatrick Mooney 	uint32_t sum = 0, s;
10134c87aefeSPatrick Mooney 
10144c87aefeSPatrick Mooney 	/* Skip completely unneeded vectors. */
10154c87aefeSPatrick Mooney 	while (iovcnt > 0 && iov->iov_len <= off && off > 0) {
10164c87aefeSPatrick Mooney 		off -= iov->iov_len;
10174c87aefeSPatrick Mooney 		iov++;
10184c87aefeSPatrick Mooney 		iovcnt--;
10194c87aefeSPatrick Mooney 	}
10204c87aefeSPatrick Mooney 
10214c87aefeSPatrick Mooney 	/* Calculate checksum of requested range. */
10224c87aefeSPatrick Mooney 	odd = 0;
10234c87aefeSPatrick Mooney 	while (len > 0 && iovcnt > 0) {
10244c87aefeSPatrick Mooney 		now = MIN(len, iov->iov_len - off);
10254c87aefeSPatrick Mooney 		s = e82545_buf_checksum(iov->iov_base + off, now);
10264c87aefeSPatrick Mooney 		sum += odd ? (s << 8) : s;
10274c87aefeSPatrick Mooney 		odd ^= (now & 1);
10284c87aefeSPatrick Mooney 		len -= now;
10294c87aefeSPatrick Mooney 		off = 0;
10304c87aefeSPatrick Mooney 		iov++;
10314c87aefeSPatrick Mooney 		iovcnt--;
10324c87aefeSPatrick Mooney 	}
10334c87aefeSPatrick Mooney 
10344c87aefeSPatrick Mooney 	return (e82545_carry(sum));
10354c87aefeSPatrick Mooney }
10364c87aefeSPatrick Mooney 
10374c87aefeSPatrick Mooney /*
10384c87aefeSPatrick Mooney  * Return the transmit descriptor type.
10394c87aefeSPatrick Mooney  */
10404c87aefeSPatrick Mooney int
10414c87aefeSPatrick Mooney e82545_txdesc_type(uint32_t lower)
10424c87aefeSPatrick Mooney {
10434c87aefeSPatrick Mooney 	int type;
10444c87aefeSPatrick Mooney 
10454c87aefeSPatrick Mooney 	type = 0;
10464c87aefeSPatrick Mooney 
10474c87aefeSPatrick Mooney 	if (lower & E1000_TXD_CMD_DEXT)
10484c87aefeSPatrick Mooney 		type = lower & E1000_TXD_MASK;
10494c87aefeSPatrick Mooney 
10504c87aefeSPatrick Mooney 	return (type);
10514c87aefeSPatrick Mooney }
10524c87aefeSPatrick Mooney 
10534c87aefeSPatrick Mooney static void
10544c87aefeSPatrick Mooney e82545_transmit_checksum(struct iovec *iov, int iovcnt, struct ck_info *ck)
10554c87aefeSPatrick Mooney {
10564c87aefeSPatrick Mooney 	uint16_t cksum;
10574c87aefeSPatrick Mooney 	int cklen;
10584c87aefeSPatrick Mooney 
10594c87aefeSPatrick Mooney 	DPRINTF("tx cksum: iovcnt/s/off/len %d/%d/%d/%d\r\n",
10604c87aefeSPatrick Mooney 	    iovcnt, ck->ck_start, ck->ck_off, ck->ck_len);
10614c87aefeSPatrick Mooney 	cklen = ck->ck_len ? ck->ck_len - ck->ck_start + 1 : INT_MAX;
10624c87aefeSPatrick Mooney 	cksum = e82545_iov_checksum(iov, iovcnt, ck->ck_start, cklen);
10634c87aefeSPatrick Mooney 	*(uint16_t *)((uint8_t *)iov[0].iov_base + ck->ck_off) = ~cksum;
10644c87aefeSPatrick Mooney }
10654c87aefeSPatrick Mooney 
10664c87aefeSPatrick Mooney static void
10674c87aefeSPatrick Mooney e82545_transmit_backend(struct e82545_softc *sc, struct iovec *iov, int iovcnt)
10684c87aefeSPatrick Mooney {
10694c87aefeSPatrick Mooney 
10704c87aefeSPatrick Mooney 	if (sc->esc_tapfd == -1)
10714c87aefeSPatrick Mooney 		return;
10724c87aefeSPatrick Mooney 
10734c87aefeSPatrick Mooney 	(void) writev(sc->esc_tapfd, iov, iovcnt);
10744c87aefeSPatrick Mooney }
10754c87aefeSPatrick Mooney 
10764c87aefeSPatrick Mooney static void
10774c87aefeSPatrick Mooney e82545_transmit_done(struct e82545_softc *sc, uint16_t head, uint16_t tail,
10784c87aefeSPatrick Mooney     uint16_t dsize, int *tdwb)
10794c87aefeSPatrick Mooney {
10804c87aefeSPatrick Mooney 	union e1000_tx_udesc *dsc;
10814c87aefeSPatrick Mooney 
10824c87aefeSPatrick Mooney 	for ( ; head != tail; head = (head + 1) % dsize) {
10834c87aefeSPatrick Mooney 		dsc = &sc->esc_txdesc[head];
10844c87aefeSPatrick Mooney 		if (dsc->td.lower.data & E1000_TXD_CMD_RS) {
10854c87aefeSPatrick Mooney 			dsc->td.upper.data |= E1000_TXD_STAT_DD;
10864c87aefeSPatrick Mooney 			*tdwb = 1;
10874c87aefeSPatrick Mooney 		}
10884c87aefeSPatrick Mooney 	}
10894c87aefeSPatrick Mooney }
10904c87aefeSPatrick Mooney 
10914c87aefeSPatrick Mooney static int
10924c87aefeSPatrick Mooney e82545_transmit(struct e82545_softc *sc, uint16_t head, uint16_t tail,
10934c87aefeSPatrick Mooney     uint16_t dsize, uint16_t *rhead, int *tdwb)
10944c87aefeSPatrick Mooney {
10954c87aefeSPatrick Mooney #ifdef	__FreeBSD__
10964c87aefeSPatrick Mooney 	uint8_t *hdr, *hdrp;
10974c87aefeSPatrick Mooney #else
10984c87aefeSPatrick Mooney 	caddr_t hdr, hdrp;
10994c87aefeSPatrick Mooney #endif
11004c87aefeSPatrick Mooney 	struct iovec iovb[I82545_MAX_TXSEGS + 2];
11014c87aefeSPatrick Mooney 	struct iovec tiov[I82545_MAX_TXSEGS + 2];
11024c87aefeSPatrick Mooney 	struct e1000_context_desc *cd;
11034c87aefeSPatrick Mooney 	struct ck_info ckinfo[2];
11044c87aefeSPatrick Mooney 	struct iovec *iov;
11054c87aefeSPatrick Mooney 	union  e1000_tx_udesc *dsc;
11064c87aefeSPatrick Mooney 	int desc, dtype, len, ntype, iovcnt, tlen, hdrlen, vlen, tcp, tso;
11074c87aefeSPatrick Mooney 	int mss, paylen, seg, tiovcnt, left, now, nleft, nnow, pv, pvoff;
11084c87aefeSPatrick Mooney 	uint32_t tcpsum, tcpseq;
11094c87aefeSPatrick Mooney 	uint16_t ipcs, tcpcs, ipid, ohead;
11104c87aefeSPatrick Mooney 
11114c87aefeSPatrick Mooney 	ckinfo[0].ck_valid = ckinfo[1].ck_valid = 0;
11124c87aefeSPatrick Mooney 	iovcnt = 0;
11134c87aefeSPatrick Mooney 	tlen = 0;
11144c87aefeSPatrick Mooney 	ntype = 0;
11154c87aefeSPatrick Mooney 	tso = 0;
11164c87aefeSPatrick Mooney 	ohead = head;
11174c87aefeSPatrick Mooney 	hdr = NULL;
11184c87aefeSPatrick Mooney 
11194c87aefeSPatrick Mooney 	/* iovb[0/1] may be used for writable copy of headers. */
11204c87aefeSPatrick Mooney 	iov = &iovb[2];
11214c87aefeSPatrick Mooney 
11224c87aefeSPatrick Mooney 	for (desc = 0; ; desc++, head = (head + 1) % dsize) {
11234c87aefeSPatrick Mooney 		if (head == tail) {
11244c87aefeSPatrick Mooney 			*rhead = head;
11254c87aefeSPatrick Mooney 			return (0);
11264c87aefeSPatrick Mooney 		}
11274c87aefeSPatrick Mooney 		dsc = &sc->esc_txdesc[head];
11284c87aefeSPatrick Mooney 		dtype = e82545_txdesc_type(dsc->td.lower.data);
11294c87aefeSPatrick Mooney 
11304c87aefeSPatrick Mooney 		if (desc == 0) {
11314c87aefeSPatrick Mooney 			switch (dtype) {
11324c87aefeSPatrick Mooney 			case E1000_TXD_TYP_C:
11334c87aefeSPatrick Mooney 				DPRINTF("tx ctxt desc idx %d: %016jx "
11344c87aefeSPatrick Mooney 				    "%08x%08x\r\n",
11354c87aefeSPatrick Mooney 				    head, dsc->td.buffer_addr,
11364c87aefeSPatrick Mooney 				    dsc->td.upper.data, dsc->td.lower.data);
11374c87aefeSPatrick Mooney 				/* Save context and return */
11384c87aefeSPatrick Mooney 				sc->esc_txctx = dsc->cd;
11394c87aefeSPatrick Mooney 				goto done;
11404c87aefeSPatrick Mooney 			case E1000_TXD_TYP_L:
11414c87aefeSPatrick Mooney 				DPRINTF("tx legacy desc idx %d: %08x%08x\r\n",
11424c87aefeSPatrick Mooney 				    head, dsc->td.upper.data, dsc->td.lower.data);
11434c87aefeSPatrick Mooney 				/*
11444c87aefeSPatrick Mooney 				 * legacy cksum start valid in first descriptor
11454c87aefeSPatrick Mooney 				 */
11464c87aefeSPatrick Mooney 				ntype = dtype;
11474c87aefeSPatrick Mooney 				ckinfo[0].ck_start = dsc->td.upper.fields.css;
11484c87aefeSPatrick Mooney 				break;
11494c87aefeSPatrick Mooney 			case E1000_TXD_TYP_D:
11504c87aefeSPatrick Mooney 				DPRINTF("tx data desc idx %d: %08x%08x\r\n",
11514c87aefeSPatrick Mooney 				    head, dsc->td.upper.data, dsc->td.lower.data);
11524c87aefeSPatrick Mooney 				ntype = dtype;
11534c87aefeSPatrick Mooney 				break;
11544c87aefeSPatrick Mooney 			default:
11554c87aefeSPatrick Mooney 				break;
11564c87aefeSPatrick Mooney 			}
11574c87aefeSPatrick Mooney 		} else {
11584c87aefeSPatrick Mooney 			/* Descriptor type must be consistent */
11594c87aefeSPatrick Mooney 			assert(dtype == ntype);
11604c87aefeSPatrick Mooney 			DPRINTF("tx next desc idx %d: %08x%08x\r\n",
11614c87aefeSPatrick Mooney 			    head, dsc->td.upper.data, dsc->td.lower.data);
11624c87aefeSPatrick Mooney 		}
11634c87aefeSPatrick Mooney 
11644c87aefeSPatrick Mooney 		len = (dtype == E1000_TXD_TYP_L) ? dsc->td.lower.flags.length :
11654c87aefeSPatrick Mooney 		    dsc->dd.lower.data & 0xFFFFF;
11664c87aefeSPatrick Mooney 
11674c87aefeSPatrick Mooney 		if (len > 0) {
11684c87aefeSPatrick Mooney 			/* Strip checksum supplied by guest. */
11694c87aefeSPatrick Mooney 			if ((dsc->td.lower.data & E1000_TXD_CMD_EOP) != 0 &&
11704c87aefeSPatrick Mooney 			    (dsc->td.lower.data & E1000_TXD_CMD_IFCS) == 0)
11714c87aefeSPatrick Mooney 				len -= 2;
11724c87aefeSPatrick Mooney 			tlen += len;
11734c87aefeSPatrick Mooney 			if (iovcnt < I82545_MAX_TXSEGS) {
11744c87aefeSPatrick Mooney 				iov[iovcnt].iov_base = paddr_guest2host(
11754c87aefeSPatrick Mooney 				    sc->esc_ctx, dsc->td.buffer_addr, len);
11764c87aefeSPatrick Mooney 				iov[iovcnt].iov_len = len;
11774c87aefeSPatrick Mooney 			}
11784c87aefeSPatrick Mooney 			iovcnt++;
11794c87aefeSPatrick Mooney 		}
11804c87aefeSPatrick Mooney 
11814c87aefeSPatrick Mooney 		/*
11824c87aefeSPatrick Mooney 		 * Pull out info that is valid in the final descriptor
11834c87aefeSPatrick Mooney 		 * and exit descriptor loop.
11844c87aefeSPatrick Mooney 		 */
11854c87aefeSPatrick Mooney 		if (dsc->td.lower.data & E1000_TXD_CMD_EOP) {
11864c87aefeSPatrick Mooney 			if (dtype == E1000_TXD_TYP_L) {
11874c87aefeSPatrick Mooney 				if (dsc->td.lower.data & E1000_TXD_CMD_IC) {
11884c87aefeSPatrick Mooney 					ckinfo[0].ck_valid = 1;
11894c87aefeSPatrick Mooney 					ckinfo[0].ck_off =
11904c87aefeSPatrick Mooney 					    dsc->td.lower.flags.cso;
11914c87aefeSPatrick Mooney 					ckinfo[0].ck_len = 0;
11924c87aefeSPatrick Mooney 				}
11934c87aefeSPatrick Mooney 			} else {
11944c87aefeSPatrick Mooney 				cd = &sc->esc_txctx;
11954c87aefeSPatrick Mooney 				if (dsc->dd.lower.data & E1000_TXD_CMD_TSE)
11964c87aefeSPatrick Mooney 					tso = 1;
11974c87aefeSPatrick Mooney 				if (dsc->dd.upper.fields.popts &
11984c87aefeSPatrick Mooney 				    E1000_TXD_POPTS_IXSM)
11994c87aefeSPatrick Mooney 					ckinfo[0].ck_valid = 1;
12004c87aefeSPatrick Mooney 				if (dsc->dd.upper.fields.popts &
12014c87aefeSPatrick Mooney 				    E1000_TXD_POPTS_IXSM || tso) {
12024c87aefeSPatrick Mooney 					ckinfo[0].ck_start =
12034c87aefeSPatrick Mooney 					    cd->lower_setup.ip_fields.ipcss;
12044c87aefeSPatrick Mooney 					ckinfo[0].ck_off =
12054c87aefeSPatrick Mooney 					    cd->lower_setup.ip_fields.ipcso;
12064c87aefeSPatrick Mooney 					ckinfo[0].ck_len =
12074c87aefeSPatrick Mooney 					    cd->lower_setup.ip_fields.ipcse;
12084c87aefeSPatrick Mooney 				}
12094c87aefeSPatrick Mooney 				if (dsc->dd.upper.fields.popts &
12104c87aefeSPatrick Mooney 				    E1000_TXD_POPTS_TXSM)
12114c87aefeSPatrick Mooney 					ckinfo[1].ck_valid = 1;
12124c87aefeSPatrick Mooney 				if (dsc->dd.upper.fields.popts &
12134c87aefeSPatrick Mooney 				    E1000_TXD_POPTS_TXSM || tso) {
12144c87aefeSPatrick Mooney 					ckinfo[1].ck_start =
12154c87aefeSPatrick Mooney 					    cd->upper_setup.tcp_fields.tucss;
12164c87aefeSPatrick Mooney 					ckinfo[1].ck_off =
12174c87aefeSPatrick Mooney 					    cd->upper_setup.tcp_fields.tucso;
12184c87aefeSPatrick Mooney 					ckinfo[1].ck_len =
12194c87aefeSPatrick Mooney 					    cd->upper_setup.tcp_fields.tucse;
12204c87aefeSPatrick Mooney 				}
12214c87aefeSPatrick Mooney 			}
12224c87aefeSPatrick Mooney 			break;
12234c87aefeSPatrick Mooney 		}
12244c87aefeSPatrick Mooney 	}
12254c87aefeSPatrick Mooney 
12264c87aefeSPatrick Mooney 	if (iovcnt > I82545_MAX_TXSEGS) {
12274c87aefeSPatrick Mooney 		WPRINTF("tx too many descriptors (%d > %d) -- dropped\r\n",
12284c87aefeSPatrick Mooney 		    iovcnt, I82545_MAX_TXSEGS);
12294c87aefeSPatrick Mooney 		goto done;
12304c87aefeSPatrick Mooney 	}
12314c87aefeSPatrick Mooney 
12324c87aefeSPatrick Mooney 	hdrlen = vlen = 0;
12334c87aefeSPatrick Mooney 	/* Estimate writable space for VLAN header insertion. */
12344c87aefeSPatrick Mooney 	if ((sc->esc_CTRL & E1000_CTRL_VME) &&
12354c87aefeSPatrick Mooney 	    (dsc->td.lower.data & E1000_TXD_CMD_VLE)) {
12364c87aefeSPatrick Mooney 		hdrlen = ETHER_ADDR_LEN*2;
12374c87aefeSPatrick Mooney 		vlen = ETHER_VLAN_ENCAP_LEN;
12384c87aefeSPatrick Mooney 	}
12394c87aefeSPatrick Mooney 	if (!tso) {
12404c87aefeSPatrick Mooney 		/* Estimate required writable space for checksums. */
12414c87aefeSPatrick Mooney 		if (ckinfo[0].ck_valid)
12424c87aefeSPatrick Mooney 			hdrlen = MAX(hdrlen, ckinfo[0].ck_off + 2);
12434c87aefeSPatrick Mooney 		if (ckinfo[1].ck_valid)
12444c87aefeSPatrick Mooney 			hdrlen = MAX(hdrlen, ckinfo[1].ck_off + 2);
12454c87aefeSPatrick Mooney 		/* Round up writable space to the first vector. */
12464c87aefeSPatrick Mooney 		if (hdrlen != 0 && iov[0].iov_len > hdrlen &&
12474c87aefeSPatrick Mooney 		    iov[0].iov_len < hdrlen + 100)
12484c87aefeSPatrick Mooney 			hdrlen = iov[0].iov_len;
12494c87aefeSPatrick Mooney 	} else {
12504c87aefeSPatrick Mooney 		/* In case of TSO header length provided by software. */
12514c87aefeSPatrick Mooney 		hdrlen = sc->esc_txctx.tcp_seg_setup.fields.hdr_len;
12524c87aefeSPatrick Mooney 	}
12534c87aefeSPatrick Mooney 
12544c87aefeSPatrick Mooney 	/* Allocate, fill and prepend writable header vector. */
12554c87aefeSPatrick Mooney 	if (hdrlen != 0) {
12564c87aefeSPatrick Mooney 		hdr = __builtin_alloca(hdrlen + vlen);
12574c87aefeSPatrick Mooney 		hdr += vlen;
12584c87aefeSPatrick Mooney 		for (left = hdrlen, hdrp = hdr; left > 0;
12594c87aefeSPatrick Mooney 		    left -= now, hdrp += now) {
12604c87aefeSPatrick Mooney 			now = MIN(left, iov->iov_len);
12614c87aefeSPatrick Mooney 			memcpy(hdrp, iov->iov_base, now);
12624c87aefeSPatrick Mooney 			iov->iov_base += now;
12634c87aefeSPatrick Mooney 			iov->iov_len -= now;
12644c87aefeSPatrick Mooney 			if (iov->iov_len == 0) {
12654c87aefeSPatrick Mooney 				iov++;
12664c87aefeSPatrick Mooney 				iovcnt--;
12674c87aefeSPatrick Mooney 			}
12684c87aefeSPatrick Mooney 		}
12694c87aefeSPatrick Mooney 		iov--;
12704c87aefeSPatrick Mooney 		iovcnt++;
12714c87aefeSPatrick Mooney 		iov->iov_base = hdr;
12724c87aefeSPatrick Mooney 		iov->iov_len = hdrlen;
12734c87aefeSPatrick Mooney 	}
12744c87aefeSPatrick Mooney 
12754c87aefeSPatrick Mooney 	/* Insert VLAN tag. */
12764c87aefeSPatrick Mooney 	if (vlen != 0) {
12774c87aefeSPatrick Mooney 		hdr -= ETHER_VLAN_ENCAP_LEN;
12784c87aefeSPatrick Mooney 		memmove(hdr, hdr + ETHER_VLAN_ENCAP_LEN, ETHER_ADDR_LEN*2);
12794c87aefeSPatrick Mooney 		hdrlen += ETHER_VLAN_ENCAP_LEN;
12804c87aefeSPatrick Mooney 		hdr[ETHER_ADDR_LEN*2 + 0] = sc->esc_VET >> 8;
12814c87aefeSPatrick Mooney 		hdr[ETHER_ADDR_LEN*2 + 1] = sc->esc_VET & 0xff;
12824c87aefeSPatrick Mooney 		hdr[ETHER_ADDR_LEN*2 + 2] = dsc->td.upper.fields.special >> 8;
12834c87aefeSPatrick Mooney 		hdr[ETHER_ADDR_LEN*2 + 3] = dsc->td.upper.fields.special & 0xff;
12844c87aefeSPatrick Mooney 		iov->iov_base = hdr;
12854c87aefeSPatrick Mooney 		iov->iov_len += ETHER_VLAN_ENCAP_LEN;
12864c87aefeSPatrick Mooney 		/* Correct checksum offsets after VLAN tag insertion. */
12874c87aefeSPatrick Mooney 		ckinfo[0].ck_start += ETHER_VLAN_ENCAP_LEN;
12884c87aefeSPatrick Mooney 		ckinfo[0].ck_off += ETHER_VLAN_ENCAP_LEN;
12894c87aefeSPatrick Mooney 		if (ckinfo[0].ck_len != 0)
12904c87aefeSPatrick Mooney 			ckinfo[0].ck_len += ETHER_VLAN_ENCAP_LEN;
12914c87aefeSPatrick Mooney 		ckinfo[1].ck_start += ETHER_VLAN_ENCAP_LEN;
12924c87aefeSPatrick Mooney 		ckinfo[1].ck_off += ETHER_VLAN_ENCAP_LEN;
12934c87aefeSPatrick Mooney 		if (ckinfo[1].ck_len != 0)
12944c87aefeSPatrick Mooney 			ckinfo[1].ck_len += ETHER_VLAN_ENCAP_LEN;
12954c87aefeSPatrick Mooney 	}
12964c87aefeSPatrick Mooney 
12974c87aefeSPatrick Mooney 	/* Simple non-TSO case. */
12984c87aefeSPatrick Mooney 	if (!tso) {
12994c87aefeSPatrick Mooney 		/* Calculate checksums and transmit. */
13004c87aefeSPatrick Mooney 		if (ckinfo[0].ck_valid)
13014c87aefeSPatrick Mooney 			e82545_transmit_checksum(iov, iovcnt, &ckinfo[0]);
13024c87aefeSPatrick Mooney 		if (ckinfo[1].ck_valid)
13034c87aefeSPatrick Mooney 			e82545_transmit_checksum(iov, iovcnt, &ckinfo[1]);
13044c87aefeSPatrick Mooney 		e82545_transmit_backend(sc, iov, iovcnt);
13054c87aefeSPatrick Mooney 		goto done;
13064c87aefeSPatrick Mooney 	}
13074c87aefeSPatrick Mooney 
13084c87aefeSPatrick Mooney 	/* Doing TSO. */
13094c87aefeSPatrick Mooney 	tcp = (sc->esc_txctx.cmd_and_length & E1000_TXD_CMD_TCP) != 0;
13104c87aefeSPatrick Mooney 	mss = sc->esc_txctx.tcp_seg_setup.fields.mss;
13114c87aefeSPatrick Mooney 	paylen = (sc->esc_txctx.cmd_and_length & 0x000fffff);
13124c87aefeSPatrick Mooney 	DPRINTF("tx %s segmentation offload %d+%d/%d bytes %d iovs\r\n",
13134c87aefeSPatrick Mooney 	    tcp ? "TCP" : "UDP", hdrlen, paylen, mss, iovcnt);
13144c87aefeSPatrick Mooney 	ipid = ntohs(*(uint16_t *)&hdr[ckinfo[0].ck_start + 4]);
13154c87aefeSPatrick Mooney 	tcpseq = ntohl(*(uint32_t *)&hdr[ckinfo[1].ck_start + 4]);
13164c87aefeSPatrick Mooney 	ipcs = *(uint16_t *)&hdr[ckinfo[0].ck_off];
13174c87aefeSPatrick Mooney 	tcpcs = 0;
13184c87aefeSPatrick Mooney 	if (ckinfo[1].ck_valid)	/* Save partial pseudo-header checksum. */
13194c87aefeSPatrick Mooney 		tcpcs = *(uint16_t *)&hdr[ckinfo[1].ck_off];
13204c87aefeSPatrick Mooney 	pv = 1;
13214c87aefeSPatrick Mooney 	pvoff = 0;
13224c87aefeSPatrick Mooney 	for (seg = 0, left = paylen; left > 0; seg++, left -= now) {
13234c87aefeSPatrick Mooney 		now = MIN(left, mss);
13244c87aefeSPatrick Mooney 
13254c87aefeSPatrick Mooney 		/* Construct IOVs for the segment. */
13264c87aefeSPatrick Mooney 		/* Include whole original header. */
13274c87aefeSPatrick Mooney 		tiov[0].iov_base = hdr;
13284c87aefeSPatrick Mooney 		tiov[0].iov_len = hdrlen;
13294c87aefeSPatrick Mooney 		tiovcnt = 1;
13304c87aefeSPatrick Mooney 		/* Include respective part of payload IOV. */
13314c87aefeSPatrick Mooney 		for (nleft = now; pv < iovcnt && nleft > 0; nleft -= nnow) {
13324c87aefeSPatrick Mooney 			nnow = MIN(nleft, iov[pv].iov_len - pvoff);
13334c87aefeSPatrick Mooney 			tiov[tiovcnt].iov_base = iov[pv].iov_base + pvoff;
13344c87aefeSPatrick Mooney 			tiov[tiovcnt++].iov_len = nnow;
13354c87aefeSPatrick Mooney 			if (pvoff + nnow == iov[pv].iov_len) {
13364c87aefeSPatrick Mooney 				pv++;
13374c87aefeSPatrick Mooney 				pvoff = 0;
13384c87aefeSPatrick Mooney 			} else
13394c87aefeSPatrick Mooney 				pvoff += nnow;
13404c87aefeSPatrick Mooney 		}
13414c87aefeSPatrick Mooney 		DPRINTF("tx segment %d %d+%d bytes %d iovs\r\n",
13424c87aefeSPatrick Mooney 		    seg, hdrlen, now, tiovcnt);
13434c87aefeSPatrick Mooney 
13444c87aefeSPatrick Mooney 		/* Update IP header. */
13454c87aefeSPatrick Mooney 		if (sc->esc_txctx.cmd_and_length & E1000_TXD_CMD_IP) {
13464c87aefeSPatrick Mooney 			/* IPv4 -- set length and ID */
13474c87aefeSPatrick Mooney 			*(uint16_t *)&hdr[ckinfo[0].ck_start + 2] =
13484c87aefeSPatrick Mooney 			    htons(hdrlen - ckinfo[0].ck_start + now);
13494c87aefeSPatrick Mooney 			*(uint16_t *)&hdr[ckinfo[0].ck_start + 4] =
13504c87aefeSPatrick Mooney 			    htons(ipid + seg);
13514c87aefeSPatrick Mooney 		} else {
13524c87aefeSPatrick Mooney 			/* IPv6 -- set length */
13534c87aefeSPatrick Mooney 			*(uint16_t *)&hdr[ckinfo[0].ck_start + 4] =
13544c87aefeSPatrick Mooney 			    htons(hdrlen - ckinfo[0].ck_start - 40 +
13554c87aefeSPatrick Mooney 				  now);
13564c87aefeSPatrick Mooney 		}
13574c87aefeSPatrick Mooney 
13584c87aefeSPatrick Mooney 		/* Update pseudo-header checksum. */
13594c87aefeSPatrick Mooney 		tcpsum = tcpcs;
13604c87aefeSPatrick Mooney 		tcpsum += htons(hdrlen - ckinfo[1].ck_start + now);
13614c87aefeSPatrick Mooney 
13624c87aefeSPatrick Mooney 		/* Update TCP/UDP headers. */
13634c87aefeSPatrick Mooney 		if (tcp) {
13644c87aefeSPatrick Mooney 			/* Update sequence number and FIN/PUSH flags. */
13654c87aefeSPatrick Mooney 			*(uint32_t *)&hdr[ckinfo[1].ck_start + 4] =
13664c87aefeSPatrick Mooney 			    htonl(tcpseq + paylen - left);
13674c87aefeSPatrick Mooney 			if (now < left) {
13684c87aefeSPatrick Mooney 				hdr[ckinfo[1].ck_start + 13] &=
13694c87aefeSPatrick Mooney 				    ~(TH_FIN | TH_PUSH);
13704c87aefeSPatrick Mooney 			}
13714c87aefeSPatrick Mooney 		} else {
13724c87aefeSPatrick Mooney 			/* Update payload length. */
13734c87aefeSPatrick Mooney 			*(uint32_t *)&hdr[ckinfo[1].ck_start + 4] =
13744c87aefeSPatrick Mooney 			    hdrlen - ckinfo[1].ck_start + now;
13754c87aefeSPatrick Mooney 		}
13764c87aefeSPatrick Mooney 
13774c87aefeSPatrick Mooney 		/* Calculate checksums and transmit. */
13784c87aefeSPatrick Mooney 		if (ckinfo[0].ck_valid) {
13794c87aefeSPatrick Mooney 			*(uint16_t *)&hdr[ckinfo[0].ck_off] = ipcs;
13804c87aefeSPatrick Mooney 			e82545_transmit_checksum(tiov, tiovcnt, &ckinfo[0]);
13814c87aefeSPatrick Mooney 		}
13824c87aefeSPatrick Mooney 		if (ckinfo[1].ck_valid) {
13834c87aefeSPatrick Mooney 			*(uint16_t *)&hdr[ckinfo[1].ck_off] =
13844c87aefeSPatrick Mooney 			    e82545_carry(tcpsum);
13854c87aefeSPatrick Mooney 			e82545_transmit_checksum(tiov, tiovcnt, &ckinfo[1]);
13864c87aefeSPatrick Mooney 		}
13874c87aefeSPatrick Mooney 		e82545_transmit_backend(sc, tiov, tiovcnt);
13884c87aefeSPatrick Mooney 	}
13894c87aefeSPatrick Mooney 
13904c87aefeSPatrick Mooney done:
13914c87aefeSPatrick Mooney 	head = (head + 1) % dsize;
13924c87aefeSPatrick Mooney 	e82545_transmit_done(sc, ohead, head, dsize, tdwb);
13934c87aefeSPatrick Mooney 
13944c87aefeSPatrick Mooney 	*rhead = head;
13954c87aefeSPatrick Mooney 	return (desc + 1);
13964c87aefeSPatrick Mooney }
13974c87aefeSPatrick Mooney 
13984c87aefeSPatrick Mooney static void
13994c87aefeSPatrick Mooney e82545_tx_run(struct e82545_softc *sc)
14004c87aefeSPatrick Mooney {
14014c87aefeSPatrick Mooney 	uint32_t cause;
14024c87aefeSPatrick Mooney 	uint16_t head, rhead, tail, size;
14034c87aefeSPatrick Mooney 	int lim, tdwb, sent;
14044c87aefeSPatrick Mooney 
14054c87aefeSPatrick Mooney 	head = sc->esc_TDH;
14064c87aefeSPatrick Mooney 	tail = sc->esc_TDT;
14074c87aefeSPatrick Mooney 	size = sc->esc_TDLEN / 16;
14084c87aefeSPatrick Mooney 	DPRINTF("tx_run: head %x, rhead %x, tail %x\r\n",
14094c87aefeSPatrick Mooney 	    sc->esc_TDH, sc->esc_TDHr, sc->esc_TDT);
14104c87aefeSPatrick Mooney 
14114c87aefeSPatrick Mooney 	pthread_mutex_unlock(&sc->esc_mtx);
14124c87aefeSPatrick Mooney 	rhead = head;
14134c87aefeSPatrick Mooney 	tdwb = 0;
14144c87aefeSPatrick Mooney 	for (lim = size / 4; sc->esc_tx_enabled && lim > 0; lim -= sent) {
14154c87aefeSPatrick Mooney 		sent = e82545_transmit(sc, head, tail, size, &rhead, &tdwb);
14164c87aefeSPatrick Mooney 		if (sent == 0)
14174c87aefeSPatrick Mooney 			break;
14184c87aefeSPatrick Mooney 		head = rhead;
14194c87aefeSPatrick Mooney 	}
14204c87aefeSPatrick Mooney 	pthread_mutex_lock(&sc->esc_mtx);
14214c87aefeSPatrick Mooney 
14224c87aefeSPatrick Mooney 	sc->esc_TDH = head;
14234c87aefeSPatrick Mooney 	sc->esc_TDHr = rhead;
14244c87aefeSPatrick Mooney 	cause = 0;
14254c87aefeSPatrick Mooney 	if (tdwb)
14264c87aefeSPatrick Mooney 		cause |= E1000_ICR_TXDW;
14274c87aefeSPatrick Mooney 	if (lim != size / 4 && sc->esc_TDH == sc->esc_TDT)
14284c87aefeSPatrick Mooney 		cause |= E1000_ICR_TXQE;
14294c87aefeSPatrick Mooney 	if (cause)
14304c87aefeSPatrick Mooney 		e82545_icr_assert(sc, cause);
14314c87aefeSPatrick Mooney 
14324c87aefeSPatrick Mooney 	DPRINTF("tx_run done: head %x, rhead %x, tail %x\r\n",
14334c87aefeSPatrick Mooney 	    sc->esc_TDH, sc->esc_TDHr, sc->esc_TDT);
14344c87aefeSPatrick Mooney }
14354c87aefeSPatrick Mooney 
14364c87aefeSPatrick Mooney static void *
14374c87aefeSPatrick Mooney e82545_tx_thread(void *param)
14384c87aefeSPatrick Mooney {
14394c87aefeSPatrick Mooney 	struct e82545_softc *sc = param;
14404c87aefeSPatrick Mooney 
14414c87aefeSPatrick Mooney 	pthread_mutex_lock(&sc->esc_mtx);
14424c87aefeSPatrick Mooney 	for (;;) {
14434c87aefeSPatrick Mooney 		while (!sc->esc_tx_enabled || sc->esc_TDHr == sc->esc_TDT) {
14444c87aefeSPatrick Mooney 			if (sc->esc_tx_enabled && sc->esc_TDHr != sc->esc_TDT)
14454c87aefeSPatrick Mooney 				break;
14464c87aefeSPatrick Mooney 			sc->esc_tx_active = 0;
14474c87aefeSPatrick Mooney 			if (sc->esc_tx_enabled == 0)
14484c87aefeSPatrick Mooney 				pthread_cond_signal(&sc->esc_tx_cond);
14494c87aefeSPatrick Mooney 			pthread_cond_wait(&sc->esc_tx_cond, &sc->esc_mtx);
14504c87aefeSPatrick Mooney 		}
14514c87aefeSPatrick Mooney 		sc->esc_tx_active = 1;
14524c87aefeSPatrick Mooney 
14534c87aefeSPatrick Mooney 		/* Process some tx descriptors.  Lock dropped inside. */
14544c87aefeSPatrick Mooney 		e82545_tx_run(sc);
14554c87aefeSPatrick Mooney 	}
14564c87aefeSPatrick Mooney #ifndef	__FreeBSD__
14574c87aefeSPatrick Mooney 	return (NULL);
14584c87aefeSPatrick Mooney #endif
14594c87aefeSPatrick Mooney }
14604c87aefeSPatrick Mooney 
14614c87aefeSPatrick Mooney static void
14624c87aefeSPatrick Mooney e82545_tx_start(struct e82545_softc *sc)
14634c87aefeSPatrick Mooney {
14644c87aefeSPatrick Mooney 
14654c87aefeSPatrick Mooney 	if (sc->esc_tx_active == 0)
14664c87aefeSPatrick Mooney 		pthread_cond_signal(&sc->esc_tx_cond);
14674c87aefeSPatrick Mooney }
14684c87aefeSPatrick Mooney 
14694c87aefeSPatrick Mooney static void
14704c87aefeSPatrick Mooney e82545_tx_enable(struct e82545_softc *sc)
14714c87aefeSPatrick Mooney {
14724c87aefeSPatrick Mooney 
14734c87aefeSPatrick Mooney 	sc->esc_tx_enabled = 1;
14744c87aefeSPatrick Mooney }
14754c87aefeSPatrick Mooney 
14764c87aefeSPatrick Mooney static void
14774c87aefeSPatrick Mooney e82545_tx_disable(struct e82545_softc *sc)
14784c87aefeSPatrick Mooney {
14794c87aefeSPatrick Mooney 
14804c87aefeSPatrick Mooney 	sc->esc_tx_enabled = 0;
14814c87aefeSPatrick Mooney 	while (sc->esc_tx_active)
14824c87aefeSPatrick Mooney 		pthread_cond_wait(&sc->esc_tx_cond, &sc->esc_mtx);
14834c87aefeSPatrick Mooney }
14844c87aefeSPatrick Mooney 
14854c87aefeSPatrick Mooney static void
14864c87aefeSPatrick Mooney e82545_rx_enable(struct e82545_softc *sc)
14874c87aefeSPatrick Mooney {
14884c87aefeSPatrick Mooney 
14894c87aefeSPatrick Mooney 	sc->esc_rx_enabled = 1;
14904c87aefeSPatrick Mooney }
14914c87aefeSPatrick Mooney 
14924c87aefeSPatrick Mooney static void
14934c87aefeSPatrick Mooney e82545_rx_disable(struct e82545_softc *sc)
14944c87aefeSPatrick Mooney {
14954c87aefeSPatrick Mooney 
14964c87aefeSPatrick Mooney 	sc->esc_rx_enabled = 0;
14974c87aefeSPatrick Mooney 	while (sc->esc_rx_active)
14984c87aefeSPatrick Mooney 		pthread_cond_wait(&sc->esc_rx_cond, &sc->esc_mtx);
14994c87aefeSPatrick Mooney }
15004c87aefeSPatrick Mooney 
15014c87aefeSPatrick Mooney static void
15024c87aefeSPatrick Mooney e82545_write_ra(struct e82545_softc *sc, int reg, uint32_t wval)
15034c87aefeSPatrick Mooney {
15044c87aefeSPatrick Mooney 	struct eth_uni *eu;
15054c87aefeSPatrick Mooney 	int idx;
15064c87aefeSPatrick Mooney 
15074c87aefeSPatrick Mooney 	idx = reg >> 1;
15084c87aefeSPatrick Mooney 	assert(idx < 15);
15094c87aefeSPatrick Mooney 
15104c87aefeSPatrick Mooney 	eu = &sc->esc_uni[idx];
15114c87aefeSPatrick Mooney 
15124c87aefeSPatrick Mooney 	if (reg & 0x1) {
15134c87aefeSPatrick Mooney 		/* RAH */
15144c87aefeSPatrick Mooney 		eu->eu_valid = ((wval & E1000_RAH_AV) == E1000_RAH_AV);
15154c87aefeSPatrick Mooney 		eu->eu_addrsel = (wval >> 16) & 0x3;
15164c87aefeSPatrick Mooney 		eu->eu_eth.octet[5] = wval >> 8;
15174c87aefeSPatrick Mooney 		eu->eu_eth.octet[4] = wval;
15184c87aefeSPatrick Mooney 	} else {
15194c87aefeSPatrick Mooney 		/* RAL */
15204c87aefeSPatrick Mooney 		eu->eu_eth.octet[3] = wval >> 24;
15214c87aefeSPatrick Mooney 		eu->eu_eth.octet[2] = wval >> 16;
15224c87aefeSPatrick Mooney 		eu->eu_eth.octet[1] = wval >> 8;
15234c87aefeSPatrick Mooney 		eu->eu_eth.octet[0] = wval;
15244c87aefeSPatrick Mooney 	}
15254c87aefeSPatrick Mooney }
15264c87aefeSPatrick Mooney 
15274c87aefeSPatrick Mooney static uint32_t
15284c87aefeSPatrick Mooney e82545_read_ra(struct e82545_softc *sc, int reg)
15294c87aefeSPatrick Mooney {
15304c87aefeSPatrick Mooney 	struct eth_uni *eu;
15314c87aefeSPatrick Mooney 	uint32_t retval;
15324c87aefeSPatrick Mooney 	int idx;
15334c87aefeSPatrick Mooney 
15344c87aefeSPatrick Mooney 	idx = reg >> 1;
15354c87aefeSPatrick Mooney 	assert(idx < 15);
15364c87aefeSPatrick Mooney 
15374c87aefeSPatrick Mooney 	eu = &sc->esc_uni[idx];
15384c87aefeSPatrick Mooney 
15394c87aefeSPatrick Mooney 	if (reg & 0x1) {
15404c87aefeSPatrick Mooney 		/* RAH */
15414c87aefeSPatrick Mooney 		retval = (eu->eu_valid << 31) |
15424c87aefeSPatrick Mooney 			 (eu->eu_addrsel << 16) |
15434c87aefeSPatrick Mooney 			 (eu->eu_eth.octet[5] << 8) |
15444c87aefeSPatrick Mooney 			 eu->eu_eth.octet[4];
15454c87aefeSPatrick Mooney 	} else {
15464c87aefeSPatrick Mooney 		/* RAL */
15474c87aefeSPatrick Mooney 		retval = (eu->eu_eth.octet[3] << 24) |
15484c87aefeSPatrick Mooney 			 (eu->eu_eth.octet[2] << 16) |
15494c87aefeSPatrick Mooney 			 (eu->eu_eth.octet[1] << 8) |
15504c87aefeSPatrick Mooney 			 eu->eu_eth.octet[0];
15514c87aefeSPatrick Mooney 	}
15524c87aefeSPatrick Mooney 
15534c87aefeSPatrick Mooney 	return (retval);
15544c87aefeSPatrick Mooney }
15554c87aefeSPatrick Mooney 
15564c87aefeSPatrick Mooney static void
15574c87aefeSPatrick Mooney e82545_write_register(struct e82545_softc *sc, uint32_t offset, uint32_t value)
15584c87aefeSPatrick Mooney {
15594c87aefeSPatrick Mooney 	int ridx;
15604c87aefeSPatrick Mooney 
15614c87aefeSPatrick Mooney 	if (offset & 0x3) {
15624c87aefeSPatrick Mooney 		DPRINTF("Unaligned register write offset:0x%x value:0x%x\r\n", offset, value);
15634c87aefeSPatrick Mooney 		return;
15644c87aefeSPatrick Mooney 	}
15654c87aefeSPatrick Mooney 	DPRINTF("Register write: 0x%x value: 0x%x\r\n", offset, value);
15664c87aefeSPatrick Mooney 
15674c87aefeSPatrick Mooney 	switch (offset) {
15684c87aefeSPatrick Mooney 	case E1000_CTRL:
15694c87aefeSPatrick Mooney 	case E1000_CTRL_DUP:
15704c87aefeSPatrick Mooney 		e82545_devctl(sc, value);
15714c87aefeSPatrick Mooney 		break;
15724c87aefeSPatrick Mooney 	case E1000_FCAL:
15734c87aefeSPatrick Mooney 		sc->esc_FCAL = value;
15744c87aefeSPatrick Mooney 		break;
15754c87aefeSPatrick Mooney 	case E1000_FCAH:
15764c87aefeSPatrick Mooney 		sc->esc_FCAH = value & ~0xFFFF0000;
15774c87aefeSPatrick Mooney 		break;
15784c87aefeSPatrick Mooney 	case E1000_FCT:
15794c87aefeSPatrick Mooney 		sc->esc_FCT = value & ~0xFFFF0000;
15804c87aefeSPatrick Mooney 		break;
15814c87aefeSPatrick Mooney 	case E1000_VET:
15824c87aefeSPatrick Mooney 		sc->esc_VET = value & ~0xFFFF0000;
15834c87aefeSPatrick Mooney 		break;
15844c87aefeSPatrick Mooney 	case E1000_FCTTV:
15854c87aefeSPatrick Mooney 		sc->esc_FCTTV = value & ~0xFFFF0000;
15864c87aefeSPatrick Mooney 		break;
15874c87aefeSPatrick Mooney 	case E1000_LEDCTL:
15884c87aefeSPatrick Mooney 		sc->esc_LEDCTL = value & ~0x30303000;
15894c87aefeSPatrick Mooney 		break;
15904c87aefeSPatrick Mooney 	case E1000_PBA:
15914c87aefeSPatrick Mooney 		sc->esc_PBA = value & 0x0000FF80;
15924c87aefeSPatrick Mooney 		break;
15934c87aefeSPatrick Mooney 	case E1000_ICR:
15944c87aefeSPatrick Mooney 	case E1000_ITR:
15954c87aefeSPatrick Mooney 	case E1000_ICS:
15964c87aefeSPatrick Mooney 	case E1000_IMS:
15974c87aefeSPatrick Mooney 	case E1000_IMC:
15984c87aefeSPatrick Mooney 		e82545_intr_write(sc, offset, value);
15994c87aefeSPatrick Mooney 		break;
16004c87aefeSPatrick Mooney 	case E1000_RCTL:
16014c87aefeSPatrick Mooney 		e82545_rx_ctl(sc, value);
16024c87aefeSPatrick Mooney 		break;
16034c87aefeSPatrick Mooney 	case E1000_FCRTL:
16044c87aefeSPatrick Mooney 		sc->esc_FCRTL = value & ~0xFFFF0007;
16054c87aefeSPatrick Mooney 		break;
16064c87aefeSPatrick Mooney 	case E1000_FCRTH:
16074c87aefeSPatrick Mooney 		sc->esc_FCRTH = value & ~0xFFFF0007;
16084c87aefeSPatrick Mooney 		break;
16094c87aefeSPatrick Mooney 	case E1000_RDBAL(0):
16104c87aefeSPatrick Mooney 		sc->esc_RDBAL = value & ~0xF;
16114c87aefeSPatrick Mooney 		if (sc->esc_rx_enabled) {
16124c87aefeSPatrick Mooney 			/* Apparently legal: update cached address */
16134c87aefeSPatrick Mooney 			e82545_rx_update_rdba(sc);
16144c87aefeSPatrick Mooney 		}
16154c87aefeSPatrick Mooney 		break;
16164c87aefeSPatrick Mooney 	case E1000_RDBAH(0):
16174c87aefeSPatrick Mooney 		assert(!sc->esc_rx_enabled);
16184c87aefeSPatrick Mooney 		sc->esc_RDBAH = value;
16194c87aefeSPatrick Mooney 		break;
16204c87aefeSPatrick Mooney 	case E1000_RDLEN(0):
16214c87aefeSPatrick Mooney 		assert(!sc->esc_rx_enabled);
16224c87aefeSPatrick Mooney 		sc->esc_RDLEN = value & ~0xFFF0007F;
16234c87aefeSPatrick Mooney 		break;
16244c87aefeSPatrick Mooney 	case E1000_RDH(0):
16254c87aefeSPatrick Mooney 		/* XXX should only ever be zero ? Range check ? */
16264c87aefeSPatrick Mooney 		sc->esc_RDH = value;
16274c87aefeSPatrick Mooney 		break;
16284c87aefeSPatrick Mooney 	case E1000_RDT(0):
16294c87aefeSPatrick Mooney 		/* XXX if this opens up the rx ring, do something ? */
16304c87aefeSPatrick Mooney 		sc->esc_RDT = value;
16314c87aefeSPatrick Mooney 		break;
16324c87aefeSPatrick Mooney 	case E1000_RDTR:
16334c87aefeSPatrick Mooney 		/* ignore FPD bit 31 */
16344c87aefeSPatrick Mooney 		sc->esc_RDTR = value & ~0xFFFF0000;
16354c87aefeSPatrick Mooney 		break;
16364c87aefeSPatrick Mooney 	case E1000_RXDCTL(0):
16374c87aefeSPatrick Mooney 		sc->esc_RXDCTL = value & ~0xFEC0C0C0;
16384c87aefeSPatrick Mooney 		break;
16394c87aefeSPatrick Mooney 	case E1000_RADV:
16404c87aefeSPatrick Mooney 		sc->esc_RADV = value & ~0xFFFF0000;
16414c87aefeSPatrick Mooney 		break;
16424c87aefeSPatrick Mooney 	case E1000_RSRPD:
16434c87aefeSPatrick Mooney 		sc->esc_RSRPD = value & ~0xFFFFF000;
16444c87aefeSPatrick Mooney 		break;
16454c87aefeSPatrick Mooney 	case E1000_RXCSUM:
16464c87aefeSPatrick Mooney 		sc->esc_RXCSUM = value & ~0xFFFFF800;
16474c87aefeSPatrick Mooney 		break;
16484c87aefeSPatrick Mooney 	case E1000_TXCW:
16494c87aefeSPatrick Mooney 		sc->esc_TXCW = value & ~0x3FFF0000;
16504c87aefeSPatrick Mooney 		break;
16514c87aefeSPatrick Mooney 	case E1000_TCTL:
16524c87aefeSPatrick Mooney 		e82545_tx_ctl(sc, value);
16534c87aefeSPatrick Mooney 		break;
16544c87aefeSPatrick Mooney 	case E1000_TIPG:
16554c87aefeSPatrick Mooney 		sc->esc_TIPG = value;
16564c87aefeSPatrick Mooney 		break;
16574c87aefeSPatrick Mooney 	case E1000_AIT:
16584c87aefeSPatrick Mooney 		sc->esc_AIT = value;
16594c87aefeSPatrick Mooney 		break;
16604c87aefeSPatrick Mooney 	case E1000_TDBAL(0):
16614c87aefeSPatrick Mooney 		sc->esc_TDBAL = value & ~0xF;
16624c87aefeSPatrick Mooney 		if (sc->esc_tx_enabled) {
16634c87aefeSPatrick Mooney 			/* Apparently legal */
16644c87aefeSPatrick Mooney 			e82545_tx_update_tdba(sc);
16654c87aefeSPatrick Mooney 		}
16664c87aefeSPatrick Mooney 		break;
16674c87aefeSPatrick Mooney 	case E1000_TDBAH(0):
16684c87aefeSPatrick Mooney 		//assert(!sc->esc_tx_enabled);
16694c87aefeSPatrick Mooney 		sc->esc_TDBAH = value;
16704c87aefeSPatrick Mooney 		break;
16714c87aefeSPatrick Mooney 	case E1000_TDLEN(0):
16724c87aefeSPatrick Mooney 		//assert(!sc->esc_tx_enabled);
16734c87aefeSPatrick Mooney 		sc->esc_TDLEN = value & ~0xFFF0007F;
16744c87aefeSPatrick Mooney 		break;
16754c87aefeSPatrick Mooney 	case E1000_TDH(0):
16764c87aefeSPatrick Mooney 		//assert(!sc->esc_tx_enabled);
16774c87aefeSPatrick Mooney 		/* XXX should only ever be zero ? Range check ? */
16784c87aefeSPatrick Mooney 		sc->esc_TDHr = sc->esc_TDH = value;
16794c87aefeSPatrick Mooney 		break;
16804c87aefeSPatrick Mooney 	case E1000_TDT(0):
16814c87aefeSPatrick Mooney 		/* XXX range check ? */
16824c87aefeSPatrick Mooney 		sc->esc_TDT = value;
16834c87aefeSPatrick Mooney 		if (sc->esc_tx_enabled)
16844c87aefeSPatrick Mooney 			e82545_tx_start(sc);
16854c87aefeSPatrick Mooney 		break;
16864c87aefeSPatrick Mooney 	case E1000_TIDV:
16874c87aefeSPatrick Mooney 		sc->esc_TIDV = value & ~0xFFFF0000;
16884c87aefeSPatrick Mooney 		break;
16894c87aefeSPatrick Mooney 	case E1000_TXDCTL(0):
16904c87aefeSPatrick Mooney 		//assert(!sc->esc_tx_enabled);
16914c87aefeSPatrick Mooney 		sc->esc_TXDCTL = value & ~0xC0C0C0;
16924c87aefeSPatrick Mooney 		break;
16934c87aefeSPatrick Mooney 	case E1000_TADV:
16944c87aefeSPatrick Mooney 		sc->esc_TADV = value & ~0xFFFF0000;
16954c87aefeSPatrick Mooney 		break;
16964c87aefeSPatrick Mooney 	case E1000_RAL(0) ... E1000_RAH(15):
16974c87aefeSPatrick Mooney 		/* convert to u32 offset */
16984c87aefeSPatrick Mooney 		ridx = (offset - E1000_RAL(0)) >> 2;
16994c87aefeSPatrick Mooney 		e82545_write_ra(sc, ridx, value);
17004c87aefeSPatrick Mooney 		break;
17014c87aefeSPatrick Mooney 	case E1000_MTA ... (E1000_MTA + (127*4)):
17024c87aefeSPatrick Mooney 		sc->esc_fmcast[(offset - E1000_MTA) >> 2] = value;
17034c87aefeSPatrick Mooney 		break;
17044c87aefeSPatrick Mooney 	case E1000_VFTA ... (E1000_VFTA + (127*4)):
17054c87aefeSPatrick Mooney 		sc->esc_fvlan[(offset - E1000_VFTA) >> 2] = value;
17064c87aefeSPatrick Mooney 		break;
17074c87aefeSPatrick Mooney 	case E1000_EECD:
17084c87aefeSPatrick Mooney 	{
17094c87aefeSPatrick Mooney 		//DPRINTF("EECD write 0x%x -> 0x%x\r\n", sc->eeprom_control, value);
17104c87aefeSPatrick Mooney 		/* edge triggered low->high */
17114c87aefeSPatrick Mooney 		uint32_t eecd_strobe = ((sc->eeprom_control & E1000_EECD_SK) ?
17124c87aefeSPatrick Mooney 			0 : (value & E1000_EECD_SK));
17134c87aefeSPatrick Mooney 		uint32_t eecd_mask = (E1000_EECD_SK|E1000_EECD_CS|
17144c87aefeSPatrick Mooney 					E1000_EECD_DI|E1000_EECD_REQ);
17154c87aefeSPatrick Mooney 		sc->eeprom_control &= ~eecd_mask;
17164c87aefeSPatrick Mooney 		sc->eeprom_control |= (value & eecd_mask);
17174c87aefeSPatrick Mooney 		/* grant/revoke immediately */
17184c87aefeSPatrick Mooney 		if (value & E1000_EECD_REQ) {
17194c87aefeSPatrick Mooney 			sc->eeprom_control |= E1000_EECD_GNT;
17204c87aefeSPatrick Mooney 		} else {
17214c87aefeSPatrick Mooney                         sc->eeprom_control &= ~E1000_EECD_GNT;
17224c87aefeSPatrick Mooney 		}
17234c87aefeSPatrick Mooney 		if (eecd_strobe && (sc->eeprom_control & E1000_EECD_CS)) {
17244c87aefeSPatrick Mooney 			e82545_eecd_strobe(sc);
17254c87aefeSPatrick Mooney 		}
17264c87aefeSPatrick Mooney 		return;
17274c87aefeSPatrick Mooney 	}
17284c87aefeSPatrick Mooney 	case E1000_MDIC:
17294c87aefeSPatrick Mooney 	{
17304c87aefeSPatrick Mooney 		uint8_t reg_addr = (uint8_t)((value & E1000_MDIC_REG_MASK) >>
17314c87aefeSPatrick Mooney 						E1000_MDIC_REG_SHIFT);
17324c87aefeSPatrick Mooney 		uint8_t phy_addr = (uint8_t)((value & E1000_MDIC_PHY_MASK) >>
17334c87aefeSPatrick Mooney 						E1000_MDIC_PHY_SHIFT);
17344c87aefeSPatrick Mooney 		sc->mdi_control =
17354c87aefeSPatrick Mooney 			(value & ~(E1000_MDIC_ERROR|E1000_MDIC_DEST));
17364c87aefeSPatrick Mooney 		if ((value & E1000_MDIC_READY) != 0) {
17374c87aefeSPatrick Mooney 			DPRINTF("Incorrect MDIC ready bit: 0x%x\r\n", value);
17384c87aefeSPatrick Mooney 			return;
17394c87aefeSPatrick Mooney 		}
17404c87aefeSPatrick Mooney 		switch (value & E82545_MDIC_OP_MASK) {
17414c87aefeSPatrick Mooney 		case E1000_MDIC_OP_READ:
17424c87aefeSPatrick Mooney 			sc->mdi_control &= ~E82545_MDIC_DATA_MASK;
17434c87aefeSPatrick Mooney 			sc->mdi_control |= e82545_read_mdi(sc, reg_addr, phy_addr);
17444c87aefeSPatrick Mooney 			break;
17454c87aefeSPatrick Mooney 		case E1000_MDIC_OP_WRITE:
17464c87aefeSPatrick Mooney 			e82545_write_mdi(sc, reg_addr, phy_addr,
17474c87aefeSPatrick Mooney 				value & E82545_MDIC_DATA_MASK);
17484c87aefeSPatrick Mooney 			break;
17494c87aefeSPatrick Mooney 		default:
17504c87aefeSPatrick Mooney 			DPRINTF("Unknown MDIC op: 0x%x\r\n", value);
17514c87aefeSPatrick Mooney 			return;
17524c87aefeSPatrick Mooney 		}
17534c87aefeSPatrick Mooney 		/* TODO: barrier? */
17544c87aefeSPatrick Mooney 		sc->mdi_control |= E1000_MDIC_READY;
17554c87aefeSPatrick Mooney 		if (value & E82545_MDIC_IE) {
17564c87aefeSPatrick Mooney 			// TODO: generate interrupt
17574c87aefeSPatrick Mooney 		}
17584c87aefeSPatrick Mooney 		return;
17594c87aefeSPatrick Mooney 	}
17604c87aefeSPatrick Mooney 	case E1000_MANC:
17614c87aefeSPatrick Mooney 	case E1000_STATUS:
17624c87aefeSPatrick Mooney 		return;
17634c87aefeSPatrick Mooney 	default:
17644c87aefeSPatrick Mooney 		DPRINTF("Unknown write register: 0x%x value:%x\r\n", offset, value);
17654c87aefeSPatrick Mooney 		return;
17664c87aefeSPatrick Mooney 	}
17674c87aefeSPatrick Mooney }
17684c87aefeSPatrick Mooney 
17694c87aefeSPatrick Mooney static uint32_t
17704c87aefeSPatrick Mooney e82545_read_register(struct e82545_softc *sc, uint32_t offset)
17714c87aefeSPatrick Mooney {
17724c87aefeSPatrick Mooney 	uint32_t retval;
17734c87aefeSPatrick Mooney 	int ridx;
17744c87aefeSPatrick Mooney 
17754c87aefeSPatrick Mooney 	if (offset & 0x3) {
17764c87aefeSPatrick Mooney 		DPRINTF("Unaligned register read offset:0x%x\r\n", offset);
17774c87aefeSPatrick Mooney 		return 0;
17784c87aefeSPatrick Mooney 	}
17794c87aefeSPatrick Mooney 
17804c87aefeSPatrick Mooney 	DPRINTF("Register read: 0x%x\r\n", offset);
17814c87aefeSPatrick Mooney 
17824c87aefeSPatrick Mooney 	switch (offset) {
17834c87aefeSPatrick Mooney 	case E1000_CTRL:
17844c87aefeSPatrick Mooney 		retval = sc->esc_CTRL;
17854c87aefeSPatrick Mooney 		break;
17864c87aefeSPatrick Mooney 	case E1000_STATUS:
17874c87aefeSPatrick Mooney 		retval = E1000_STATUS_FD | E1000_STATUS_LU |
17884c87aefeSPatrick Mooney 		    E1000_STATUS_SPEED_1000;
17894c87aefeSPatrick Mooney 		break;
17904c87aefeSPatrick Mooney 	case E1000_FCAL:
17914c87aefeSPatrick Mooney 		retval = sc->esc_FCAL;
17924c87aefeSPatrick Mooney 		break;
17934c87aefeSPatrick Mooney 	case E1000_FCAH:
17944c87aefeSPatrick Mooney 		retval = sc->esc_FCAH;
17954c87aefeSPatrick Mooney 		break;
17964c87aefeSPatrick Mooney 	case E1000_FCT:
17974c87aefeSPatrick Mooney 		retval = sc->esc_FCT;
17984c87aefeSPatrick Mooney 		break;
17994c87aefeSPatrick Mooney 	case E1000_VET:
18004c87aefeSPatrick Mooney 		retval = sc->esc_VET;
18014c87aefeSPatrick Mooney 		break;
18024c87aefeSPatrick Mooney 	case E1000_FCTTV:
18034c87aefeSPatrick Mooney 		retval = sc->esc_FCTTV;
18044c87aefeSPatrick Mooney 		break;
18054c87aefeSPatrick Mooney 	case E1000_LEDCTL:
18064c87aefeSPatrick Mooney 		retval = sc->esc_LEDCTL;
18074c87aefeSPatrick Mooney 		break;
18084c87aefeSPatrick Mooney 	case E1000_PBA:
18094c87aefeSPatrick Mooney 		retval = sc->esc_PBA;
18104c87aefeSPatrick Mooney 		break;
18114c87aefeSPatrick Mooney 	case E1000_ICR:
18124c87aefeSPatrick Mooney 	case E1000_ITR:
18134c87aefeSPatrick Mooney 	case E1000_ICS:
18144c87aefeSPatrick Mooney 	case E1000_IMS:
18154c87aefeSPatrick Mooney 	case E1000_IMC:
18164c87aefeSPatrick Mooney 		retval = e82545_intr_read(sc, offset);
18174c87aefeSPatrick Mooney 		break;
18184c87aefeSPatrick Mooney 	case E1000_RCTL:
18194c87aefeSPatrick Mooney 		retval = sc->esc_RCTL;
18204c87aefeSPatrick Mooney 		break;
18214c87aefeSPatrick Mooney 	case E1000_FCRTL:
18224c87aefeSPatrick Mooney 		retval = sc->esc_FCRTL;
18234c87aefeSPatrick Mooney 		break;
18244c87aefeSPatrick Mooney 	case E1000_FCRTH:
18254c87aefeSPatrick Mooney 		retval = sc->esc_FCRTH;
18264c87aefeSPatrick Mooney 		break;
18274c87aefeSPatrick Mooney 	case E1000_RDBAL(0):
18284c87aefeSPatrick Mooney 		retval = sc->esc_RDBAL;
18294c87aefeSPatrick Mooney 		break;
18304c87aefeSPatrick Mooney 	case E1000_RDBAH(0):
18314c87aefeSPatrick Mooney 		retval = sc->esc_RDBAH;
18324c87aefeSPatrick Mooney 		break;
18334c87aefeSPatrick Mooney 	case E1000_RDLEN(0):
18344c87aefeSPatrick Mooney 		retval = sc->esc_RDLEN;
18354c87aefeSPatrick Mooney 		break;
18364c87aefeSPatrick Mooney 	case E1000_RDH(0):
18374c87aefeSPatrick Mooney 		retval = sc->esc_RDH;
18384c87aefeSPatrick Mooney 		break;
18394c87aefeSPatrick Mooney 	case E1000_RDT(0):
18404c87aefeSPatrick Mooney 		retval = sc->esc_RDT;
18414c87aefeSPatrick Mooney 		break;
18424c87aefeSPatrick Mooney 	case E1000_RDTR:
18434c87aefeSPatrick Mooney 		retval = sc->esc_RDTR;
18444c87aefeSPatrick Mooney 		break;
18454c87aefeSPatrick Mooney 	case E1000_RXDCTL(0):
18464c87aefeSPatrick Mooney 		retval = sc->esc_RXDCTL;
18474c87aefeSPatrick Mooney 		break;
18484c87aefeSPatrick Mooney 	case E1000_RADV:
18494c87aefeSPatrick Mooney 		retval = sc->esc_RADV;
18504c87aefeSPatrick Mooney 		break;
18514c87aefeSPatrick Mooney 	case E1000_RSRPD:
18524c87aefeSPatrick Mooney 		retval = sc->esc_RSRPD;
18534c87aefeSPatrick Mooney 		break;
18544c87aefeSPatrick Mooney 	case E1000_RXCSUM:
18554c87aefeSPatrick Mooney 		retval = sc->esc_RXCSUM;
18564c87aefeSPatrick Mooney 		break;
18574c87aefeSPatrick Mooney 	case E1000_TXCW:
18584c87aefeSPatrick Mooney 		retval = sc->esc_TXCW;
18594c87aefeSPatrick Mooney 		break;
18604c87aefeSPatrick Mooney 	case E1000_TCTL:
18614c87aefeSPatrick Mooney 		retval = sc->esc_TCTL;
18624c87aefeSPatrick Mooney 		break;
18634c87aefeSPatrick Mooney 	case E1000_TIPG:
18644c87aefeSPatrick Mooney 		retval = sc->esc_TIPG;
18654c87aefeSPatrick Mooney 		break;
18664c87aefeSPatrick Mooney 	case E1000_AIT:
18674c87aefeSPatrick Mooney 		retval = sc->esc_AIT;
18684c87aefeSPatrick Mooney 		break;
18694c87aefeSPatrick Mooney 	case E1000_TDBAL(0):
18704c87aefeSPatrick Mooney 		retval = sc->esc_TDBAL;
18714c87aefeSPatrick Mooney 		break;
18724c87aefeSPatrick Mooney 	case E1000_TDBAH(0):
18734c87aefeSPatrick Mooney 		retval = sc->esc_TDBAH;
18744c87aefeSPatrick Mooney 		break;
18754c87aefeSPatrick Mooney 	case E1000_TDLEN(0):
18764c87aefeSPatrick Mooney 		retval = sc->esc_TDLEN;
18774c87aefeSPatrick Mooney 		break;
18784c87aefeSPatrick Mooney 	case E1000_TDH(0):
18794c87aefeSPatrick Mooney 		retval = sc->esc_TDH;
18804c87aefeSPatrick Mooney 		break;
18814c87aefeSPatrick Mooney 	case E1000_TDT(0):
18824c87aefeSPatrick Mooney 		retval = sc->esc_TDT;
18834c87aefeSPatrick Mooney 		break;
18844c87aefeSPatrick Mooney 	case E1000_TIDV:
18854c87aefeSPatrick Mooney 		retval = sc->esc_TIDV;
18864c87aefeSPatrick Mooney 		break;
18874c87aefeSPatrick Mooney 	case E1000_TXDCTL(0):
18884c87aefeSPatrick Mooney 		retval = sc->esc_TXDCTL;
18894c87aefeSPatrick Mooney 		break;
18904c87aefeSPatrick Mooney 	case E1000_TADV:
18914c87aefeSPatrick Mooney 		retval = sc->esc_TADV;
18924c87aefeSPatrick Mooney 		break;
18934c87aefeSPatrick Mooney 	case E1000_RAL(0) ... E1000_RAH(15):
18944c87aefeSPatrick Mooney 		/* convert to u32 offset */
18954c87aefeSPatrick Mooney 		ridx = (offset - E1000_RAL(0)) >> 2;
18964c87aefeSPatrick Mooney 		retval = e82545_read_ra(sc, ridx);
18974c87aefeSPatrick Mooney 		break;
18984c87aefeSPatrick Mooney 	case E1000_MTA ... (E1000_MTA + (127*4)):
18994c87aefeSPatrick Mooney 		retval = sc->esc_fmcast[(offset - E1000_MTA) >> 2];
19004c87aefeSPatrick Mooney 		break;
19014c87aefeSPatrick Mooney 	case E1000_VFTA ... (E1000_VFTA + (127*4)):
19024c87aefeSPatrick Mooney 		retval = sc->esc_fvlan[(offset - E1000_VFTA) >> 2];
19034c87aefeSPatrick Mooney 		break;
19044c87aefeSPatrick Mooney 	case E1000_EECD:
19054c87aefeSPatrick Mooney 		//DPRINTF("EECD read %x\r\n", sc->eeprom_control);
19064c87aefeSPatrick Mooney 		retval = sc->eeprom_control;
19074c87aefeSPatrick Mooney 		break;
19084c87aefeSPatrick Mooney 	case E1000_MDIC:
19094c87aefeSPatrick Mooney 		retval = sc->mdi_control;
19104c87aefeSPatrick Mooney 		break;
19114c87aefeSPatrick Mooney 	case E1000_MANC:
19124c87aefeSPatrick Mooney 		retval = 0;
19134c87aefeSPatrick Mooney 		break;
19144c87aefeSPatrick Mooney 	/* stats that we emulate. */
19154c87aefeSPatrick Mooney 	case E1000_MPC:
19164c87aefeSPatrick Mooney 		retval = sc->missed_pkt_count;
19174c87aefeSPatrick Mooney 		break;
19184c87aefeSPatrick Mooney 	case E1000_PRC64:
19194c87aefeSPatrick Mooney 		retval = sc->pkt_rx_by_size[0];
19204c87aefeSPatrick Mooney 		break;
19214c87aefeSPatrick Mooney 	case E1000_PRC127:
19224c87aefeSPatrick Mooney 		retval = sc->pkt_rx_by_size[1];
19234c87aefeSPatrick Mooney 		break;
19244c87aefeSPatrick Mooney 	case E1000_PRC255:
19254c87aefeSPatrick Mooney 		retval = sc->pkt_rx_by_size[2];
19264c87aefeSPatrick Mooney 		break;
19274c87aefeSPatrick Mooney 	case E1000_PRC511:
19284c87aefeSPatrick Mooney 		retval = sc->pkt_rx_by_size[3];
19294c87aefeSPatrick Mooney 		break;
19304c87aefeSPatrick Mooney 	case E1000_PRC1023:
19314c87aefeSPatrick Mooney 		retval = sc->pkt_rx_by_size[4];
19324c87aefeSPatrick Mooney 		break;
19334c87aefeSPatrick Mooney 	case E1000_PRC1522:
19344c87aefeSPatrick Mooney 		retval = sc->pkt_rx_by_size[5];
19354c87aefeSPatrick Mooney 		break;
19364c87aefeSPatrick Mooney 	case E1000_GPRC:
19374c87aefeSPatrick Mooney 		retval = sc->good_pkt_rx_count;
19384c87aefeSPatrick Mooney 		break;
19394c87aefeSPatrick Mooney 	case E1000_BPRC:
19404c87aefeSPatrick Mooney 		retval = sc->bcast_pkt_rx_count;
19414c87aefeSPatrick Mooney 		break;
19424c87aefeSPatrick Mooney 	case E1000_MPRC:
19434c87aefeSPatrick Mooney 		retval = sc->mcast_pkt_rx_count;
19444c87aefeSPatrick Mooney 		break;
19454c87aefeSPatrick Mooney 	case E1000_GPTC:
19464c87aefeSPatrick Mooney 	case E1000_TPT:
19474c87aefeSPatrick Mooney 		retval = sc->good_pkt_tx_count;
19484c87aefeSPatrick Mooney 		break;
19494c87aefeSPatrick Mooney 	case E1000_GORCL:
19504c87aefeSPatrick Mooney 		retval = (uint32_t)sc->good_octets_rx;
19514c87aefeSPatrick Mooney 		break;
19524c87aefeSPatrick Mooney 	case E1000_GORCH:
19534c87aefeSPatrick Mooney 		retval = (uint32_t)(sc->good_octets_rx >> 32);
19544c87aefeSPatrick Mooney 		break;
19554c87aefeSPatrick Mooney 	case E1000_TOTL:
19564c87aefeSPatrick Mooney 	case E1000_GOTCL:
19574c87aefeSPatrick Mooney 		retval = (uint32_t)sc->good_octets_tx;
19584c87aefeSPatrick Mooney 		break;
19594c87aefeSPatrick Mooney 	case E1000_TOTH:
19604c87aefeSPatrick Mooney 	case E1000_GOTCH:
19614c87aefeSPatrick Mooney 		retval = (uint32_t)(sc->good_octets_tx >> 32);
19624c87aefeSPatrick Mooney 		break;
19634c87aefeSPatrick Mooney 	case E1000_ROC:
19644c87aefeSPatrick Mooney 		retval = sc->oversize_rx_count;
19654c87aefeSPatrick Mooney 		break;
19664c87aefeSPatrick Mooney 	case E1000_TORL:
19674c87aefeSPatrick Mooney 		retval = (uint32_t)(sc->good_octets_rx + sc->missed_octets);
19684c87aefeSPatrick Mooney 		break;
19694c87aefeSPatrick Mooney 	case E1000_TORH:
19704c87aefeSPatrick Mooney 		retval = (uint32_t)((sc->good_octets_rx +
19714c87aefeSPatrick Mooney 		    sc->missed_octets) >> 32);
19724c87aefeSPatrick Mooney 		break;
19734c87aefeSPatrick Mooney 	case E1000_TPR:
19744c87aefeSPatrick Mooney 		retval = sc->good_pkt_rx_count + sc->missed_pkt_count +
19754c87aefeSPatrick Mooney 		    sc->oversize_rx_count;
19764c87aefeSPatrick Mooney 		break;
19774c87aefeSPatrick Mooney 	case E1000_PTC64:
19784c87aefeSPatrick Mooney 		retval = sc->pkt_tx_by_size[0];
19794c87aefeSPatrick Mooney 		break;
19804c87aefeSPatrick Mooney 	case E1000_PTC127:
19814c87aefeSPatrick Mooney 		retval = sc->pkt_tx_by_size[1];
19824c87aefeSPatrick Mooney 		break;
19834c87aefeSPatrick Mooney 	case E1000_PTC255:
19844c87aefeSPatrick Mooney 		retval = sc->pkt_tx_by_size[2];
19854c87aefeSPatrick Mooney 		break;
19864c87aefeSPatrick Mooney 	case E1000_PTC511:
19874c87aefeSPatrick Mooney 		retval = sc->pkt_tx_by_size[3];
19884c87aefeSPatrick Mooney 		break;
19894c87aefeSPatrick Mooney 	case E1000_PTC1023:
19904c87aefeSPatrick Mooney 		retval = sc->pkt_tx_by_size[4];
19914c87aefeSPatrick Mooney 		break;
19924c87aefeSPatrick Mooney 	case E1000_PTC1522:
19934c87aefeSPatrick Mooney 		retval = sc->pkt_tx_by_size[5];
19944c87aefeSPatrick Mooney 		break;
19954c87aefeSPatrick Mooney 	case E1000_MPTC:
19964c87aefeSPatrick Mooney 		retval = sc->mcast_pkt_tx_count;
19974c87aefeSPatrick Mooney 		break;
19984c87aefeSPatrick Mooney 	case E1000_BPTC:
19994c87aefeSPatrick Mooney 		retval = sc->bcast_pkt_tx_count;
20004c87aefeSPatrick Mooney 		break;
20014c87aefeSPatrick Mooney 	case E1000_TSCTC:
20024c87aefeSPatrick Mooney 		retval = sc->tso_tx_count;
20034c87aefeSPatrick Mooney 		break;
20044c87aefeSPatrick Mooney 	/* stats that are always 0. */
20054c87aefeSPatrick Mooney 	case E1000_CRCERRS:
20064c87aefeSPatrick Mooney 	case E1000_ALGNERRC:
20074c87aefeSPatrick Mooney 	case E1000_SYMERRS:
20084c87aefeSPatrick Mooney 	case E1000_RXERRC:
20094c87aefeSPatrick Mooney 	case E1000_SCC:
20104c87aefeSPatrick Mooney 	case E1000_ECOL:
20114c87aefeSPatrick Mooney 	case E1000_MCC:
20124c87aefeSPatrick Mooney 	case E1000_LATECOL:
20134c87aefeSPatrick Mooney 	case E1000_COLC:
20144c87aefeSPatrick Mooney 	case E1000_DC:
20154c87aefeSPatrick Mooney 	case E1000_TNCRS:
20164c87aefeSPatrick Mooney 	case E1000_SEC:
20174c87aefeSPatrick Mooney 	case E1000_CEXTERR:
20184c87aefeSPatrick Mooney 	case E1000_RLEC:
20194c87aefeSPatrick Mooney 	case E1000_XONRXC:
20204c87aefeSPatrick Mooney 	case E1000_XONTXC:
20214c87aefeSPatrick Mooney 	case E1000_XOFFRXC:
20224c87aefeSPatrick Mooney 	case E1000_XOFFTXC:
20234c87aefeSPatrick Mooney 	case E1000_FCRUC:
20244c87aefeSPatrick Mooney 	case E1000_RNBC:
20254c87aefeSPatrick Mooney 	case E1000_RUC:
20264c87aefeSPatrick Mooney 	case E1000_RFC:
20274c87aefeSPatrick Mooney 	case E1000_RJC:
20284c87aefeSPatrick Mooney 	case E1000_MGTPRC:
20294c87aefeSPatrick Mooney 	case E1000_MGTPDC:
20304c87aefeSPatrick Mooney 	case E1000_MGTPTC:
20314c87aefeSPatrick Mooney 	case E1000_TSCTFC:
20324c87aefeSPatrick Mooney 		retval = 0;
20334c87aefeSPatrick Mooney 		break;
20344c87aefeSPatrick Mooney 	default:
20354c87aefeSPatrick Mooney 		DPRINTF("Unknown read register: 0x%x\r\n", offset);
20364c87aefeSPatrick Mooney 		retval = 0;
20374c87aefeSPatrick Mooney 		break;
20384c87aefeSPatrick Mooney 	}
20394c87aefeSPatrick Mooney 
20404c87aefeSPatrick Mooney 	return (retval);
20414c87aefeSPatrick Mooney }
20424c87aefeSPatrick Mooney 
20434c87aefeSPatrick Mooney static void
20444c87aefeSPatrick Mooney e82545_write(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, int baridx,
20454c87aefeSPatrick Mooney 	     uint64_t offset, int size, uint64_t value)
20464c87aefeSPatrick Mooney {
20474c87aefeSPatrick Mooney 	struct e82545_softc *sc;
20484c87aefeSPatrick Mooney 
20494c87aefeSPatrick Mooney 	//DPRINTF("Write bar:%d offset:0x%lx value:0x%lx size:%d\r\n", baridx, offset, value, size);
20504c87aefeSPatrick Mooney 
20514c87aefeSPatrick Mooney 	sc = pi->pi_arg;
20524c87aefeSPatrick Mooney 
20534c87aefeSPatrick Mooney 	pthread_mutex_lock(&sc->esc_mtx);
20544c87aefeSPatrick Mooney 
20554c87aefeSPatrick Mooney 	switch (baridx) {
20564c87aefeSPatrick Mooney 	case E82545_BAR_IO:
20574c87aefeSPatrick Mooney 		switch (offset) {
20584c87aefeSPatrick Mooney 		case E82545_IOADDR:
20594c87aefeSPatrick Mooney 			if (size != 4) {
20604c87aefeSPatrick Mooney 				DPRINTF("Wrong io addr write sz:%d value:0x%lx\r\n", size, value);
20614c87aefeSPatrick Mooney 			} else
20624c87aefeSPatrick Mooney 				sc->io_addr = (uint32_t)value;
20634c87aefeSPatrick Mooney 			break;
20644c87aefeSPatrick Mooney 		case E82545_IODATA:
20654c87aefeSPatrick Mooney 			if (size != 4) {
20664c87aefeSPatrick Mooney 				DPRINTF("Wrong io data write size:%d value:0x%lx\r\n", size, value);
20674c87aefeSPatrick Mooney 			} else if (sc->io_addr > E82545_IO_REGISTER_MAX) {
20684c87aefeSPatrick Mooney 				DPRINTF("Non-register io write addr:0x%x value:0x%lx\r\n", sc->io_addr, value);
20694c87aefeSPatrick Mooney 			} else
20704c87aefeSPatrick Mooney 				e82545_write_register(sc, sc->io_addr,
20714c87aefeSPatrick Mooney 						      (uint32_t)value);
20724c87aefeSPatrick Mooney 			break;
20734c87aefeSPatrick Mooney 		default:
20744c87aefeSPatrick Mooney 			DPRINTF("Unknown io bar write offset:0x%lx value:0x%lx size:%d\r\n", offset, value, size);
20754c87aefeSPatrick Mooney 			break;
20764c87aefeSPatrick Mooney 		}
20774c87aefeSPatrick Mooney 		break;
20784c87aefeSPatrick Mooney 	case E82545_BAR_REGISTER:
20794c87aefeSPatrick Mooney 		if (size != 4) {
20804c87aefeSPatrick Mooney 			DPRINTF("Wrong register write size:%d offset:0x%lx value:0x%lx\r\n", size, offset, value);
20814c87aefeSPatrick Mooney 		} else
20824c87aefeSPatrick Mooney 			e82545_write_register(sc, (uint32_t)offset,
20834c87aefeSPatrick Mooney 					      (uint32_t)value);
20844c87aefeSPatrick Mooney 		break;
20854c87aefeSPatrick Mooney 	default:
20864c87aefeSPatrick Mooney 		DPRINTF("Unknown write bar:%d off:0x%lx val:0x%lx size:%d\r\n",
20874c87aefeSPatrick Mooney 			baridx, offset, value, size);
20884c87aefeSPatrick Mooney 	}
20894c87aefeSPatrick Mooney 
20904c87aefeSPatrick Mooney 	pthread_mutex_unlock(&sc->esc_mtx);
20914c87aefeSPatrick Mooney }
20924c87aefeSPatrick Mooney 
20934c87aefeSPatrick Mooney static uint64_t
20944c87aefeSPatrick Mooney e82545_read(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, int baridx,
20954c87aefeSPatrick Mooney 	    uint64_t offset, int size)
20964c87aefeSPatrick Mooney {
20974c87aefeSPatrick Mooney 	struct e82545_softc *sc;
20984c87aefeSPatrick Mooney 	uint64_t retval;
20994c87aefeSPatrick Mooney 
21004c87aefeSPatrick Mooney 	//DPRINTF("Read  bar:%d offset:0x%lx size:%d\r\n", baridx, offset, size);
21014c87aefeSPatrick Mooney 	sc = pi->pi_arg;
21024c87aefeSPatrick Mooney 	retval = 0;
21034c87aefeSPatrick Mooney 
21044c87aefeSPatrick Mooney 	pthread_mutex_lock(&sc->esc_mtx);
21054c87aefeSPatrick Mooney 
21064c87aefeSPatrick Mooney 	switch (baridx) {
21074c87aefeSPatrick Mooney 	case E82545_BAR_IO:
21084c87aefeSPatrick Mooney 		switch (offset) {
21094c87aefeSPatrick Mooney 		case E82545_IOADDR:
21104c87aefeSPatrick Mooney 			if (size != 4) {
21114c87aefeSPatrick Mooney 				DPRINTF("Wrong io addr read sz:%d\r\n", size);
21124c87aefeSPatrick Mooney 			} else
21134c87aefeSPatrick Mooney 				retval = sc->io_addr;
21144c87aefeSPatrick Mooney 			break;
21154c87aefeSPatrick Mooney 		case E82545_IODATA:
21164c87aefeSPatrick Mooney 			if (size != 4) {
21174c87aefeSPatrick Mooney 				DPRINTF("Wrong io data read sz:%d\r\n", size);
21184c87aefeSPatrick Mooney 			}
21194c87aefeSPatrick Mooney 			if (sc->io_addr > E82545_IO_REGISTER_MAX) {
21204c87aefeSPatrick Mooney 				DPRINTF("Non-register io read addr:0x%x\r\n",
21214c87aefeSPatrick Mooney 					sc->io_addr);
21224c87aefeSPatrick Mooney 			} else
21234c87aefeSPatrick Mooney 				retval = e82545_read_register(sc, sc->io_addr);
21244c87aefeSPatrick Mooney 			break;
21254c87aefeSPatrick Mooney 		default:
21264c87aefeSPatrick Mooney 			DPRINTF("Unknown io bar read offset:0x%lx size:%d\r\n",
21274c87aefeSPatrick Mooney 				offset, size);
21284c87aefeSPatrick Mooney 			break;
21294c87aefeSPatrick Mooney 		}
21304c87aefeSPatrick Mooney 		break;
21314c87aefeSPatrick Mooney 	case E82545_BAR_REGISTER:
21324c87aefeSPatrick Mooney 		if (size != 4) {
21334c87aefeSPatrick Mooney 			DPRINTF("Wrong register read size:%d offset:0x%lx\r\n",
21344c87aefeSPatrick Mooney 				size, offset);
21354c87aefeSPatrick Mooney 		} else
21364c87aefeSPatrick Mooney 			retval = e82545_read_register(sc, (uint32_t)offset);
21374c87aefeSPatrick Mooney 		break;
21384c87aefeSPatrick Mooney 	default:
21394c87aefeSPatrick Mooney 		DPRINTF("Unknown read bar:%d offset:0x%lx size:%d\r\n",
21404c87aefeSPatrick Mooney 			baridx, offset, size);
21414c87aefeSPatrick Mooney 		break;
21424c87aefeSPatrick Mooney 	}
21434c87aefeSPatrick Mooney 
21444c87aefeSPatrick Mooney 	pthread_mutex_unlock(&sc->esc_mtx);
21454c87aefeSPatrick Mooney 
21464c87aefeSPatrick Mooney 	return (retval);
21474c87aefeSPatrick Mooney }
21484c87aefeSPatrick Mooney 
21494c87aefeSPatrick Mooney static void
21504c87aefeSPatrick Mooney e82545_reset(struct e82545_softc *sc, int drvr)
21514c87aefeSPatrick Mooney {
21524c87aefeSPatrick Mooney 	int i;
21534c87aefeSPatrick Mooney 
21544c87aefeSPatrick Mooney 	e82545_rx_disable(sc);
21554c87aefeSPatrick Mooney 	e82545_tx_disable(sc);
21564c87aefeSPatrick Mooney 
21574c87aefeSPatrick Mooney 	/* clear outstanding interrupts */
21584c87aefeSPatrick Mooney 	if (sc->esc_irq_asserted)
21594c87aefeSPatrick Mooney 		pci_lintr_deassert(sc->esc_pi);
21604c87aefeSPatrick Mooney 
21614c87aefeSPatrick Mooney 	/* misc */
21624c87aefeSPatrick Mooney 	if (!drvr) {
21634c87aefeSPatrick Mooney 		sc->esc_FCAL = 0;
21644c87aefeSPatrick Mooney 		sc->esc_FCAH = 0;
21654c87aefeSPatrick Mooney 		sc->esc_FCT = 0;
21664c87aefeSPatrick Mooney 		sc->esc_VET = 0;
21674c87aefeSPatrick Mooney 		sc->esc_FCTTV = 0;
21684c87aefeSPatrick Mooney 	}
21694c87aefeSPatrick Mooney 	sc->esc_LEDCTL = 0x07061302;
21704c87aefeSPatrick Mooney 	sc->esc_PBA = 0x00100030;
21714c87aefeSPatrick Mooney 
21724c87aefeSPatrick Mooney 	/* start nvm in opcode mode. */
21734c87aefeSPatrick Mooney 	sc->nvm_opaddr = 0;
21744c87aefeSPatrick Mooney 	sc->nvm_mode = E82545_NVM_MODE_OPADDR;
21754c87aefeSPatrick Mooney 	sc->nvm_bits = E82545_NVM_OPADDR_BITS;
21764c87aefeSPatrick Mooney 	sc->eeprom_control = E1000_EECD_PRES | E82545_EECD_FWE_EN;
21774c87aefeSPatrick Mooney 	e82545_init_eeprom(sc);
21784c87aefeSPatrick Mooney 
21794c87aefeSPatrick Mooney 	/* interrupt */
21804c87aefeSPatrick Mooney 	sc->esc_ICR = 0;
21814c87aefeSPatrick Mooney 	sc->esc_ITR = 250;
21824c87aefeSPatrick Mooney 	sc->esc_ICS = 0;
21834c87aefeSPatrick Mooney 	sc->esc_IMS = 0;
21844c87aefeSPatrick Mooney 	sc->esc_IMC = 0;
21854c87aefeSPatrick Mooney 
21864c87aefeSPatrick Mooney 	/* L2 filters */
21874c87aefeSPatrick Mooney 	if (!drvr) {
21884c87aefeSPatrick Mooney 		memset(sc->esc_fvlan, 0, sizeof(sc->esc_fvlan));
21894c87aefeSPatrick Mooney 		memset(sc->esc_fmcast, 0, sizeof(sc->esc_fmcast));
21904c87aefeSPatrick Mooney 		memset(sc->esc_uni, 0, sizeof(sc->esc_uni));
21914c87aefeSPatrick Mooney 
21924c87aefeSPatrick Mooney 		/* XXX not necessary on 82545 ?? */
21934c87aefeSPatrick Mooney 		sc->esc_uni[0].eu_valid = 1;
21944c87aefeSPatrick Mooney 		memcpy(sc->esc_uni[0].eu_eth.octet, sc->esc_mac.octet,
21954c87aefeSPatrick Mooney 		    ETHER_ADDR_LEN);
21964c87aefeSPatrick Mooney 	} else {
21974c87aefeSPatrick Mooney 		/* Clear RAH valid bits */
21984c87aefeSPatrick Mooney 		for (i = 0; i < 16; i++)
21994c87aefeSPatrick Mooney 			sc->esc_uni[i].eu_valid = 0;
22004c87aefeSPatrick Mooney 	}
22014c87aefeSPatrick Mooney 
22024c87aefeSPatrick Mooney 	/* receive */
22034c87aefeSPatrick Mooney 	if (!drvr) {
22044c87aefeSPatrick Mooney 		sc->esc_RDBAL = 0;
22054c87aefeSPatrick Mooney 		sc->esc_RDBAH = 0;
22064c87aefeSPatrick Mooney 	}
22074c87aefeSPatrick Mooney 	sc->esc_RCTL = 0;
22084c87aefeSPatrick Mooney 	sc->esc_FCRTL = 0;
22094c87aefeSPatrick Mooney 	sc->esc_FCRTH = 0;
22104c87aefeSPatrick Mooney 	sc->esc_RDLEN = 0;
22114c87aefeSPatrick Mooney 	sc->esc_RDH = 0;
22124c87aefeSPatrick Mooney 	sc->esc_RDT = 0;
22134c87aefeSPatrick Mooney 	sc->esc_RDTR = 0;
22144c87aefeSPatrick Mooney 	sc->esc_RXDCTL = (1 << 24) | (1 << 16); /* default GRAN/WTHRESH */
22154c87aefeSPatrick Mooney 	sc->esc_RADV = 0;
22164c87aefeSPatrick Mooney 	sc->esc_RXCSUM = 0;
22174c87aefeSPatrick Mooney 
22184c87aefeSPatrick Mooney 	/* transmit */
22194c87aefeSPatrick Mooney 	if (!drvr) {
22204c87aefeSPatrick Mooney 		sc->esc_TDBAL = 0;
22214c87aefeSPatrick Mooney 		sc->esc_TDBAH = 0;
22224c87aefeSPatrick Mooney 		sc->esc_TIPG = 0;
22234c87aefeSPatrick Mooney 		sc->esc_AIT = 0;
22244c87aefeSPatrick Mooney 		sc->esc_TIDV = 0;
22254c87aefeSPatrick Mooney 		sc->esc_TADV = 0;
22264c87aefeSPatrick Mooney 	}
22274c87aefeSPatrick Mooney 	sc->esc_tdba = 0;
22284c87aefeSPatrick Mooney 	sc->esc_txdesc = NULL;
22294c87aefeSPatrick Mooney 	sc->esc_TXCW = 0;
22304c87aefeSPatrick Mooney 	sc->esc_TCTL = 0;
22314c87aefeSPatrick Mooney 	sc->esc_TDLEN = 0;
22324c87aefeSPatrick Mooney 	sc->esc_TDT = 0;
22334c87aefeSPatrick Mooney 	sc->esc_TDHr = sc->esc_TDH = 0;
22344c87aefeSPatrick Mooney 	sc->esc_TXDCTL = 0;
22354c87aefeSPatrick Mooney }
22364c87aefeSPatrick Mooney 
22374c87aefeSPatrick Mooney static void
22384c87aefeSPatrick Mooney e82545_open_tap(struct e82545_softc *sc, char *opts)
22394c87aefeSPatrick Mooney {
22404c87aefeSPatrick Mooney 	char tbuf[80];
22414c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM
22424c87aefeSPatrick Mooney 	cap_rights_t rights;
22434c87aefeSPatrick Mooney #endif
22444c87aefeSPatrick Mooney 
22454c87aefeSPatrick Mooney 	if (opts == NULL) {
22464c87aefeSPatrick Mooney 		sc->esc_tapfd = -1;
22474c87aefeSPatrick Mooney 		return;
22484c87aefeSPatrick Mooney 	}
22494c87aefeSPatrick Mooney 
22504c87aefeSPatrick Mooney 	strcpy(tbuf, "/dev/");
22514c87aefeSPatrick Mooney 	strlcat(tbuf, opts, sizeof(tbuf));
22524c87aefeSPatrick Mooney 
22534c87aefeSPatrick Mooney 	sc->esc_tapfd = open(tbuf, O_RDWR);
22544c87aefeSPatrick Mooney 	if (sc->esc_tapfd == -1) {
22554c87aefeSPatrick Mooney 		DPRINTF("unable to open tap device %s\n", opts);
22564c87aefeSPatrick Mooney 		exit(4);
22574c87aefeSPatrick Mooney 	}
22584c87aefeSPatrick Mooney 
22594c87aefeSPatrick Mooney 	/*
22604c87aefeSPatrick Mooney 	 * Set non-blocking and register for read
22614c87aefeSPatrick Mooney 	 * notifications with the event loop
22624c87aefeSPatrick Mooney 	 */
22634c87aefeSPatrick Mooney 	int opt = 1;
22644c87aefeSPatrick Mooney 	if (ioctl(sc->esc_tapfd, FIONBIO, &opt) < 0) {
22654c87aefeSPatrick Mooney 		WPRINTF("tap device O_NONBLOCK failed: %d\n", errno);
22664c87aefeSPatrick Mooney 		close(sc->esc_tapfd);
22674c87aefeSPatrick Mooney 		sc->esc_tapfd = -1;
22684c87aefeSPatrick Mooney 	}
22694c87aefeSPatrick Mooney 
22704c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM
22714c87aefeSPatrick Mooney 	cap_rights_init(&rights, CAP_EVENT, CAP_READ, CAP_WRITE);
22724c87aefeSPatrick Mooney 	if (caph_rights_limit(sc->esc_tapfd, &rights) == -1)
22734c87aefeSPatrick Mooney 		errx(EX_OSERR, "Unable to apply rights for sandbox");
22744c87aefeSPatrick Mooney #endif
22754c87aefeSPatrick Mooney 
22764c87aefeSPatrick Mooney #ifdef	__FreeBSD__
22774c87aefeSPatrick Mooney 	sc->esc_mevp = mevent_add(sc->esc_tapfd,
22784c87aefeSPatrick Mooney 				  EVF_READ,
22794c87aefeSPatrick Mooney 				  e82545_tap_callback,
22804c87aefeSPatrick Mooney 				  sc);
22814c87aefeSPatrick Mooney 	if (sc->esc_mevp == NULL) {
22824c87aefeSPatrick Mooney 		DPRINTF("Could not register mevent %d\n", EVF_READ);
22834c87aefeSPatrick Mooney 		close(sc->esc_tapfd);
22844c87aefeSPatrick Mooney 		sc->esc_tapfd = -1;
22854c87aefeSPatrick Mooney 	}
22864c87aefeSPatrick Mooney #endif
22874c87aefeSPatrick Mooney }
22884c87aefeSPatrick Mooney 
22894c87aefeSPatrick Mooney static int
22904c87aefeSPatrick Mooney e82545_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts)
22914c87aefeSPatrick Mooney {
22924c87aefeSPatrick Mooney 	char nstr[80];
22934c87aefeSPatrick Mooney 	struct e82545_softc *sc;
22944c87aefeSPatrick Mooney 	char *devname;
22954c87aefeSPatrick Mooney 	char *vtopts;
22964c87aefeSPatrick Mooney 	int mac_provided;
22974c87aefeSPatrick Mooney 
2298*84659b24SMichael Zeller 	DPRINTF("Loading with options: %s\r\n", opts);
2299*84659b24SMichael Zeller 
23004c87aefeSPatrick Mooney 	/* Setup our softc */
23014c87aefeSPatrick Mooney 	sc = calloc(1, sizeof(*sc));
23024c87aefeSPatrick Mooney 
23034c87aefeSPatrick Mooney 	pi->pi_arg = sc;
23044c87aefeSPatrick Mooney 	sc->esc_pi = pi;
23054c87aefeSPatrick Mooney 	sc->esc_ctx = ctx;
23064c87aefeSPatrick Mooney 
23074c87aefeSPatrick Mooney 	pthread_mutex_init(&sc->esc_mtx, NULL);
23084c87aefeSPatrick Mooney 	pthread_cond_init(&sc->esc_rx_cond, NULL);
23094c87aefeSPatrick Mooney 	pthread_cond_init(&sc->esc_tx_cond, NULL);
23104c87aefeSPatrick Mooney 	pthread_create(&sc->esc_tx_tid, NULL, e82545_tx_thread, sc);
23114c87aefeSPatrick Mooney 	snprintf(nstr, sizeof(nstr), "e82545-%d:%d tx", pi->pi_slot,
23124c87aefeSPatrick Mooney 	    pi->pi_func);
23134c87aefeSPatrick Mooney         pthread_set_name_np(sc->esc_tx_tid, nstr);
23144c87aefeSPatrick Mooney 
23154c87aefeSPatrick Mooney 	pci_set_cfgdata16(pi, PCIR_DEVICE, E82545_DEV_ID_82545EM_COPPER);
23164c87aefeSPatrick Mooney 	pci_set_cfgdata16(pi, PCIR_VENDOR, E82545_VENDOR_ID_INTEL);
23174c87aefeSPatrick Mooney 	pci_set_cfgdata8(pi,  PCIR_CLASS, PCIC_NETWORK);
23184c87aefeSPatrick Mooney 	pci_set_cfgdata8(pi, PCIR_SUBCLASS, PCIS_NETWORK_ETHERNET);
23194c87aefeSPatrick Mooney 	pci_set_cfgdata16(pi, PCIR_SUBDEV_0, E82545_SUBDEV_ID);
23204c87aefeSPatrick Mooney 	pci_set_cfgdata16(pi, PCIR_SUBVEND_0, E82545_VENDOR_ID_INTEL);
23214c87aefeSPatrick Mooney 
23224c87aefeSPatrick Mooney 	pci_set_cfgdata8(pi,  PCIR_HDRTYPE, PCIM_HDRTYPE_NORMAL);
23234c87aefeSPatrick Mooney 	pci_set_cfgdata8(pi,  PCIR_INTPIN, 0x1);
23244c87aefeSPatrick Mooney 
23254c87aefeSPatrick Mooney 	/* TODO: this card also supports msi, but the freebsd driver for it
23264c87aefeSPatrick Mooney 	 * does not, so I have not implemented it. */
23274c87aefeSPatrick Mooney 	pci_lintr_request(pi);
23284c87aefeSPatrick Mooney 
23294c87aefeSPatrick Mooney 	pci_emul_alloc_bar(pi, E82545_BAR_REGISTER, PCIBAR_MEM32,
23304c87aefeSPatrick Mooney 		E82545_BAR_REGISTER_LEN);
23314c87aefeSPatrick Mooney 	pci_emul_alloc_bar(pi, E82545_BAR_FLASH, PCIBAR_MEM32,
23324c87aefeSPatrick Mooney 		E82545_BAR_FLASH_LEN);
23334c87aefeSPatrick Mooney 	pci_emul_alloc_bar(pi, E82545_BAR_IO, PCIBAR_IO,
23344c87aefeSPatrick Mooney 		E82545_BAR_IO_LEN);
23354c87aefeSPatrick Mooney 
23364c87aefeSPatrick Mooney 	/*
23374c87aefeSPatrick Mooney 	 * Attempt to open the tap device and read the MAC address
23384c87aefeSPatrick Mooney 	 * if specified.  Copied from virtio-net, slightly modified.
23394c87aefeSPatrick Mooney 	 */
23404c87aefeSPatrick Mooney 	mac_provided = 0;
23414c87aefeSPatrick Mooney 	sc->esc_tapfd = -1;
23424c87aefeSPatrick Mooney 	if (opts != NULL) {
23434c87aefeSPatrick Mooney 		int err;
23444c87aefeSPatrick Mooney 
23454c87aefeSPatrick Mooney 		devname = vtopts = strdup(opts);
23464c87aefeSPatrick Mooney 		(void) strsep(&vtopts, ",");
23474c87aefeSPatrick Mooney 
23484c87aefeSPatrick Mooney 		if (vtopts != NULL) {
2349*84659b24SMichael Zeller 			err = net_parsemac(vtopts, sc->esc_mac.octet);
23504c87aefeSPatrick Mooney 			if (err != 0) {
23514c87aefeSPatrick Mooney 				free(devname);
23524c87aefeSPatrick Mooney 				return (err);
23534c87aefeSPatrick Mooney 			}
23544c87aefeSPatrick Mooney 			mac_provided = 1;
23554c87aefeSPatrick Mooney 		}
23564c87aefeSPatrick Mooney 
23574c87aefeSPatrick Mooney 		if (strncmp(devname, "tap", 3) == 0 ||
23584c87aefeSPatrick Mooney 		    strncmp(devname, "vmnet", 5) == 0)
23594c87aefeSPatrick Mooney 			e82545_open_tap(sc, devname);
23604c87aefeSPatrick Mooney 
23614c87aefeSPatrick Mooney 		free(devname);
23624c87aefeSPatrick Mooney 	}
23634c87aefeSPatrick Mooney 
23644c87aefeSPatrick Mooney 	if (!mac_provided) {
2365*84659b24SMichael Zeller 		net_genmac(pi, sc->esc_mac.octet);
23664c87aefeSPatrick Mooney 	}
23674c87aefeSPatrick Mooney 
23684c87aefeSPatrick Mooney 	/* H/w initiated reset */
23694c87aefeSPatrick Mooney 	e82545_reset(sc, 0);
23704c87aefeSPatrick Mooney 
23714c87aefeSPatrick Mooney 	return (0);
23724c87aefeSPatrick Mooney }
23734c87aefeSPatrick Mooney 
23744c87aefeSPatrick Mooney struct pci_devemu pci_de_e82545 = {
23754c87aefeSPatrick Mooney 	.pe_emu = 	"e1000",
23764c87aefeSPatrick Mooney 	.pe_init =	e82545_init,
23774c87aefeSPatrick Mooney 	.pe_barwrite =	e82545_write,
23784c87aefeSPatrick Mooney 	.pe_barread =	e82545_read
23794c87aefeSPatrick Mooney };
23804c87aefeSPatrick Mooney PCI_EMUL_SET(pci_de_e82545);
23814c87aefeSPatrick Mooney 
2382