xref: /freebsd/usr.sbin/bhyve/pci_e82545.c (revision ee7230f4f7bdd8edd2c6b8fc26b639cbf003ec1c)
19e749f25SAlexander Motin /*
29e749f25SAlexander Motin  * Copyright (c) 2016 Alexander Motin <mav@FreeBSD.org>
39e749f25SAlexander Motin  * Copyright (c) 2015 Peter Grehan <grehan@freebsd.org>
49e749f25SAlexander Motin  * Copyright (c) 2013 Jeremiah Lott, Avere Systems
59e749f25SAlexander Motin  * All rights reserved.
69e749f25SAlexander Motin  *
79e749f25SAlexander Motin  * Redistribution and use in source and binary forms, with or without
89e749f25SAlexander Motin  * modification, are permitted provided that the following conditions
99e749f25SAlexander Motin  * are met:
109e749f25SAlexander Motin  * 1. Redistributions of source code must retain the above copyright
119e749f25SAlexander Motin  *    notice, this list of conditions and the following disclaimer
129e749f25SAlexander Motin  *    in this position and unchanged.
139e749f25SAlexander Motin  * 2. Redistributions in binary form must reproduce the above copyright
149e749f25SAlexander Motin  *    notice, this list of conditions and the following disclaimer in the
159e749f25SAlexander Motin  *    documentation and/or other materials provided with the distribution.
169e749f25SAlexander Motin  *
179e749f25SAlexander Motin  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
189e749f25SAlexander Motin  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
199e749f25SAlexander Motin  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
209e749f25SAlexander Motin  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
219e749f25SAlexander Motin  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
229e749f25SAlexander Motin  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
239e749f25SAlexander Motin  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
249e749f25SAlexander Motin  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
259e749f25SAlexander Motin  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
269e749f25SAlexander Motin  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
279e749f25SAlexander Motin  * SUCH DAMAGE.
289e749f25SAlexander Motin  */
299e749f25SAlexander Motin 
309e749f25SAlexander Motin #include <sys/cdefs.h>
319e749f25SAlexander Motin __FBSDID("$FreeBSD$");
329e749f25SAlexander Motin 
339e749f25SAlexander Motin #include <sys/types.h>
349e749f25SAlexander Motin #include <sys/limits.h>
359e749f25SAlexander Motin #include <sys/ioctl.h>
369e749f25SAlexander Motin #include <sys/uio.h>
379e749f25SAlexander Motin #include <net/ethernet.h>
389e749f25SAlexander Motin #include <netinet/in.h>
399e749f25SAlexander Motin #include <netinet/tcp.h>
409e749f25SAlexander Motin 
419e749f25SAlexander Motin #include <errno.h>
429e749f25SAlexander Motin #include <fcntl.h>
439e749f25SAlexander Motin #include <md5.h>
449e749f25SAlexander Motin #include <stdio.h>
459e749f25SAlexander Motin #include <stdlib.h>
469e749f25SAlexander Motin #include <string.h>
479e749f25SAlexander Motin #include <unistd.h>
489e749f25SAlexander Motin #include <pthread.h>
499e749f25SAlexander Motin #include <pthread_np.h>
509e749f25SAlexander Motin 
519e749f25SAlexander Motin #include "e1000_regs.h"
529e749f25SAlexander Motin #include "e1000_defines.h"
539e749f25SAlexander Motin #include "mii.h"
549e749f25SAlexander Motin 
559e749f25SAlexander Motin #include "bhyverun.h"
569e749f25SAlexander Motin #include "pci_emul.h"
579e749f25SAlexander Motin #include "mevent.h"
589e749f25SAlexander Motin 
599e749f25SAlexander Motin /* Hardware/register definitions XXX: move some to common code. */
609e749f25SAlexander Motin #define E82545_VENDOR_ID_INTEL			0x8086
619e749f25SAlexander Motin #define E82545_DEV_ID_82545EM_COPPER		0x100F
629e749f25SAlexander Motin #define E82545_SUBDEV_ID			0x1008
639e749f25SAlexander Motin 
649e749f25SAlexander Motin #define E82545_REVISION_4			4
659e749f25SAlexander Motin 
669e749f25SAlexander Motin #define E82545_MDIC_DATA_MASK			0x0000FFFF
679e749f25SAlexander Motin #define E82545_MDIC_OP_MASK			0x0c000000
689e749f25SAlexander Motin #define E82545_MDIC_IE				0x20000000
699e749f25SAlexander Motin 
709e749f25SAlexander Motin #define E82545_EECD_FWE_DIS	0x00000010 /* Flash writes disabled */
719e749f25SAlexander Motin #define E82545_EECD_FWE_EN	0x00000020 /* Flash writes enabled */
729e749f25SAlexander Motin #define E82545_EECD_FWE_MASK	0x00000030 /* Flash writes mask */
739e749f25SAlexander Motin 
749e749f25SAlexander Motin #define E82545_BAR_REGISTER			0
759e749f25SAlexander Motin #define E82545_BAR_REGISTER_LEN			(128*1024)
769e749f25SAlexander Motin #define E82545_BAR_FLASH			1
779e749f25SAlexander Motin #define E82545_BAR_FLASH_LEN			(64*1024)
789e749f25SAlexander Motin #define E82545_BAR_IO				2
799e749f25SAlexander Motin #define E82545_BAR_IO_LEN			8
809e749f25SAlexander Motin 
819e749f25SAlexander Motin #define E82545_IOADDR				0x00000000
829e749f25SAlexander Motin #define E82545_IODATA				0x00000004
839e749f25SAlexander Motin #define E82545_IO_REGISTER_MAX			0x0001FFFF
849e749f25SAlexander Motin #define E82545_IO_FLASH_BASE			0x00080000
859e749f25SAlexander Motin #define E82545_IO_FLASH_MAX			0x000FFFFF
869e749f25SAlexander Motin 
879e749f25SAlexander Motin #define E82545_ARRAY_ENTRY(reg, offset)		(reg + (offset<<2))
889e749f25SAlexander Motin #define E82545_RAR_MAX				15
899e749f25SAlexander Motin #define E82545_MTA_MAX				127
909e749f25SAlexander Motin #define E82545_VFTA_MAX				127
919e749f25SAlexander Motin 
929e749f25SAlexander Motin /* Slightly modified from the driver versions, hardcoded for 3 opcode bits,
939e749f25SAlexander Motin  * followed by 6 address bits.
949e749f25SAlexander Motin  * TODO: make opcode bits and addr bits configurable?
959e749f25SAlexander Motin  * NVM Commands - Microwire */
969e749f25SAlexander Motin #define E82545_NVM_OPCODE_BITS	3
979e749f25SAlexander Motin #define E82545_NVM_ADDR_BITS	6
989e749f25SAlexander Motin #define E82545_NVM_DATA_BITS	16
999e749f25SAlexander Motin #define E82545_NVM_OPADDR_BITS	(E82545_NVM_OPCODE_BITS + E82545_NVM_ADDR_BITS)
1009e749f25SAlexander Motin #define E82545_NVM_ADDR_MASK	((1 << E82545_NVM_ADDR_BITS)-1)
1019e749f25SAlexander Motin #define E82545_NVM_OPCODE_MASK	\
1029e749f25SAlexander Motin     (((1 << E82545_NVM_OPCODE_BITS) - 1) << E82545_NVM_ADDR_BITS)
1039e749f25SAlexander Motin #define E82545_NVM_OPCODE_READ	(0x6 << E82545_NVM_ADDR_BITS)	/* read */
1049e749f25SAlexander Motin #define E82545_NVM_OPCODE_WRITE	(0x5 << E82545_NVM_ADDR_BITS)	/* write */
1059e749f25SAlexander Motin #define E82545_NVM_OPCODE_ERASE	(0x7 << E82545_NVM_ADDR_BITS)	/* erase */
1069e749f25SAlexander Motin #define	E82545_NVM_OPCODE_EWEN	(0x4 << E82545_NVM_ADDR_BITS)	/* wr-enable */
1079e749f25SAlexander Motin 
1089e749f25SAlexander Motin #define	E82545_NVM_EEPROM_SIZE	64 /* 64 * 16-bit values == 128K */
1099e749f25SAlexander Motin 
1109e749f25SAlexander Motin #define E1000_ICR_SRPD		0x00010000
1119e749f25SAlexander Motin 
112*ee7230f4SAlexander Motin /* This is an arbitrary number.  There is no hard limit on the chip. */
113*ee7230f4SAlexander Motin #define I82545_MAX_TXSEGS	64
1149e749f25SAlexander Motin 
1159e749f25SAlexander Motin /* Legacy receive descriptor */
1169e749f25SAlexander Motin struct e1000_rx_desc {
1179e749f25SAlexander Motin 	uint64_t buffer_addr;	/* Address of the descriptor's data buffer */
1189e749f25SAlexander Motin 	uint16_t length;	/* Length of data DMAed into data buffer */
1199e749f25SAlexander Motin 	uint16_t csum;		/* Packet checksum */
1209e749f25SAlexander Motin 	uint8_t	 status;       	/* Descriptor status */
1219e749f25SAlexander Motin 	uint8_t  errors;	/* Descriptor Errors */
1229e749f25SAlexander Motin 	uint16_t special;
1239e749f25SAlexander Motin };
1249e749f25SAlexander Motin 
1259e749f25SAlexander Motin /* Transmit descriptor types */
1269e749f25SAlexander Motin #define	E1000_TXD_MASK		(E1000_TXD_CMD_DEXT | 0x00F00000)
1279e749f25SAlexander Motin #define E1000_TXD_TYP_L		(0)
1289e749f25SAlexander Motin #define E1000_TXD_TYP_C		(E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_C)
1299e749f25SAlexander Motin #define E1000_TXD_TYP_D		(E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D)
1309e749f25SAlexander Motin 
1319e749f25SAlexander Motin /* Legacy transmit descriptor */
1329e749f25SAlexander Motin struct e1000_tx_desc {
1339e749f25SAlexander Motin 	uint64_t buffer_addr;   /* Address of the descriptor's data buffer */
1349e749f25SAlexander Motin 	union {
1359e749f25SAlexander Motin 		uint32_t data;
1369e749f25SAlexander Motin 		struct {
1379e749f25SAlexander Motin 			uint16_t length;  /* Data buffer length */
1389e749f25SAlexander Motin 			uint8_t  cso;  /* Checksum offset */
1399e749f25SAlexander Motin 			uint8_t  cmd;  /* Descriptor control */
1409e749f25SAlexander Motin 		} flags;
1419e749f25SAlexander Motin 	} lower;
1429e749f25SAlexander Motin 	union {
1439e749f25SAlexander Motin 		uint32_t data;
1449e749f25SAlexander Motin 		struct {
1459e749f25SAlexander Motin 			uint8_t status; /* Descriptor status */
1469e749f25SAlexander Motin 			uint8_t css;  /* Checksum start */
1479e749f25SAlexander Motin 			uint16_t special;
1489e749f25SAlexander Motin 		} fields;
1499e749f25SAlexander Motin 	} upper;
1509e749f25SAlexander Motin };
1519e749f25SAlexander Motin 
1529e749f25SAlexander Motin /* Context descriptor */
1539e749f25SAlexander Motin struct e1000_context_desc {
1549e749f25SAlexander Motin 	union {
1559e749f25SAlexander Motin 		uint32_t ip_config;
1569e749f25SAlexander Motin 		struct {
1579e749f25SAlexander Motin 			uint8_t ipcss;  /* IP checksum start */
1589e749f25SAlexander Motin 			uint8_t ipcso;  /* IP checksum offset */
1599e749f25SAlexander Motin 			uint16_t ipcse;  /* IP checksum end */
1609e749f25SAlexander Motin 		} ip_fields;
1619e749f25SAlexander Motin 	} lower_setup;
1629e749f25SAlexander Motin 	union {
1639e749f25SAlexander Motin 		uint32_t tcp_config;
1649e749f25SAlexander Motin 		struct {
1659e749f25SAlexander Motin 			uint8_t tucss;  /* TCP checksum start */
1669e749f25SAlexander Motin 			uint8_t tucso;  /* TCP checksum offset */
1679e749f25SAlexander Motin 			uint16_t tucse;  /* TCP checksum end */
1689e749f25SAlexander Motin 		} tcp_fields;
1699e749f25SAlexander Motin 	} upper_setup;
1709e749f25SAlexander Motin 	uint32_t cmd_and_length;
1719e749f25SAlexander Motin 	union {
1729e749f25SAlexander Motin 		uint32_t data;
1739e749f25SAlexander Motin 		struct {
1749e749f25SAlexander Motin 			uint8_t status;  /* Descriptor status */
1759e749f25SAlexander Motin 			uint8_t hdr_len;  /* Header length */
1769e749f25SAlexander Motin 			uint16_t mss;  /* Maximum segment size */
1779e749f25SAlexander Motin 		} fields;
1789e749f25SAlexander Motin 	} tcp_seg_setup;
1799e749f25SAlexander Motin };
1809e749f25SAlexander Motin 
1819e749f25SAlexander Motin /* Data descriptor */
1829e749f25SAlexander Motin struct e1000_data_desc {
1839e749f25SAlexander Motin 	uint64_t buffer_addr;  /* Address of the descriptor's buffer address */
1849e749f25SAlexander Motin 	union {
1859e749f25SAlexander Motin 		uint32_t data;
1869e749f25SAlexander Motin 		struct {
1879e749f25SAlexander Motin 			uint16_t length;  /* Data buffer length */
1889e749f25SAlexander Motin 			uint8_t typ_len_ext;
1899e749f25SAlexander Motin 			uint8_t cmd;
1909e749f25SAlexander Motin 		} flags;
1919e749f25SAlexander Motin 	} lower;
1929e749f25SAlexander Motin 	union {
1939e749f25SAlexander Motin 		uint32_t data;
1949e749f25SAlexander Motin 		struct {
1959e749f25SAlexander Motin 			uint8_t status;  /* Descriptor status */
1969e749f25SAlexander Motin 			uint8_t popts;  /* Packet Options */
1979e749f25SAlexander Motin 			uint16_t special;
1989e749f25SAlexander Motin 		} fields;
1999e749f25SAlexander Motin 	} upper;
2009e749f25SAlexander Motin };
2019e749f25SAlexander Motin 
2029e749f25SAlexander Motin union e1000_tx_udesc {
2039e749f25SAlexander Motin 	struct e1000_tx_desc td;
2049e749f25SAlexander Motin 	struct e1000_context_desc cd;
2059e749f25SAlexander Motin 	struct e1000_data_desc dd;
2069e749f25SAlexander Motin };
2079e749f25SAlexander Motin 
2089e749f25SAlexander Motin /* Tx checksum info for a packet. */
2099e749f25SAlexander Motin struct ck_info {
2109e749f25SAlexander Motin 	int	ck_valid;	/* ck_info is valid */
2119e749f25SAlexander Motin 	uint8_t	ck_start;	/* start byte of cksum calcuation */
2129e749f25SAlexander Motin 	uint8_t	ck_off;		/* offset of cksum insertion */
2139e749f25SAlexander Motin 	uint16_t ck_len;	/* length of cksum calc: 0 is to packet-end */
2149e749f25SAlexander Motin };
2159e749f25SAlexander Motin 
2169e749f25SAlexander Motin /*
2179e749f25SAlexander Motin  * Debug printf
2189e749f25SAlexander Motin  */
2199e749f25SAlexander Motin static int e82545_debug = 0;
2209e749f25SAlexander Motin #define DPRINTF(msg,params...) if (e82545_debug) fprintf(stderr, "e82545: " msg, params)
2219e749f25SAlexander Motin #define WPRINTF(msg,params...) fprintf(stderr, "e82545: " msg, params)
2229e749f25SAlexander Motin 
2239e749f25SAlexander Motin #define	MIN(a,b) (((a)<(b))?(a):(b))
2249e749f25SAlexander Motin #define	MAX(a,b) (((a)>(b))?(a):(b))
2259e749f25SAlexander Motin 
2269e749f25SAlexander Motin /* s/w representation of the RAL/RAH regs */
2279e749f25SAlexander Motin struct  eth_uni {
2289e749f25SAlexander Motin 	int		eu_valid;
2299e749f25SAlexander Motin 	int		eu_addrsel;
2309e749f25SAlexander Motin 	struct ether_addr eu_eth;
2319e749f25SAlexander Motin };
2329e749f25SAlexander Motin 
2339e749f25SAlexander Motin 
2349e749f25SAlexander Motin struct e82545_softc {
2359e749f25SAlexander Motin 	struct pci_devinst *esc_pi;
2369e749f25SAlexander Motin 	struct vmctx	*esc_ctx;
2379e749f25SAlexander Motin 	struct mevent   *esc_mevp;
2389e749f25SAlexander Motin 	struct mevent   *esc_mevpitr;
2399e749f25SAlexander Motin 	pthread_mutex_t	esc_mtx;
2409e749f25SAlexander Motin 	struct ether_addr esc_mac;
2419e749f25SAlexander Motin 	int		esc_tapfd;
2429e749f25SAlexander Motin 
2439e749f25SAlexander Motin 	/* General */
2449e749f25SAlexander Motin 	uint32_t	esc_CTRL;	/* x0000 device ctl */
2459e749f25SAlexander Motin 	uint32_t	esc_FCAL;	/* x0028 flow ctl addr lo */
2469e749f25SAlexander Motin 	uint32_t	esc_FCAH;	/* x002C flow ctl addr hi */
2479e749f25SAlexander Motin 	uint32_t	esc_FCT;	/* x0030 flow ctl type */
2489e749f25SAlexander Motin 	uint32_t	esc_VET;	/* x0038 VLAN eth type */
2499e749f25SAlexander Motin 	uint32_t	esc_FCTTV;	/* x0170 flow ctl tx timer */
2509e749f25SAlexander Motin 	uint32_t	esc_LEDCTL;	/* x0E00 LED control */
2519e749f25SAlexander Motin 	uint32_t	esc_PBA;	/* x1000 pkt buffer allocation */
2529e749f25SAlexander Motin 
2539e749f25SAlexander Motin 	/* Interrupt control */
2549e749f25SAlexander Motin 	int		esc_irq_asserted;
2559e749f25SAlexander Motin 	uint32_t	esc_ICR;	/* x00C0 cause read/clear */
2569e749f25SAlexander Motin 	uint32_t	esc_ITR;	/* x00C4 intr throttling */
2579e749f25SAlexander Motin 	uint32_t	esc_ICS;	/* x00C8 cause set */
2589e749f25SAlexander Motin 	uint32_t	esc_IMS;	/* x00D0 mask set/read */
2599e749f25SAlexander Motin 	uint32_t	esc_IMC;	/* x00D8 mask clear */
2609e749f25SAlexander Motin 
2619e749f25SAlexander Motin 	/* Transmit */
2629e749f25SAlexander Motin 	union e1000_tx_udesc *esc_txdesc;
2639e749f25SAlexander Motin 	struct e1000_context_desc esc_txctx;
2649e749f25SAlexander Motin 	pthread_t	esc_tx_tid;
2659e749f25SAlexander Motin 	pthread_cond_t	esc_tx_cond;
2669e749f25SAlexander Motin 	int		esc_tx_enabled;
2679e749f25SAlexander Motin 	int		esc_tx_active;
2689e749f25SAlexander Motin 	uint32_t	esc_TXCW;	/* x0178 transmit config */
2699e749f25SAlexander Motin 	uint32_t	esc_TCTL;	/* x0400 transmit ctl */
2709e749f25SAlexander Motin 	uint32_t	esc_TIPG;	/* x0410 inter-packet gap */
2719e749f25SAlexander Motin 	uint16_t	esc_AIT;	/* x0458 Adaptive Interframe Throttle */
2729e749f25SAlexander Motin 	uint64_t	esc_tdba;      	/* verified 64-bit desc table addr */
2739e749f25SAlexander Motin 	uint32_t	esc_TDBAL;	/* x3800 desc table addr, low bits */
2749e749f25SAlexander Motin 	uint32_t	esc_TDBAH;	/* x3804 desc table addr, hi 32-bits */
2759e749f25SAlexander Motin 	uint32_t	esc_TDLEN;	/* x3808 # descriptors in bytes */
2769e749f25SAlexander Motin 	uint16_t	esc_TDH;	/* x3810 desc table head idx */
2779e749f25SAlexander Motin 	uint16_t	esc_TDHr;	/* internal read version of TDH */
2789e749f25SAlexander Motin 	uint16_t	esc_TDT;	/* x3818 desc table tail idx */
2799e749f25SAlexander Motin 	uint32_t	esc_TIDV;	/* x3820 intr delay */
2809e749f25SAlexander Motin 	uint32_t	esc_TXDCTL;	/* x3828 desc control */
2819e749f25SAlexander Motin 	uint32_t	esc_TADV;	/* x382C intr absolute delay */
2829e749f25SAlexander Motin 
2839e749f25SAlexander Motin 	/* L2 frame acceptance */
2849e749f25SAlexander Motin 	struct eth_uni	esc_uni[16];	/* 16 x unicast MAC addresses */
2859e749f25SAlexander Motin 	uint32_t	esc_fmcast[128]; /* Multicast filter bit-match */
2869e749f25SAlexander Motin 	uint32_t	esc_fvlan[128]; /* VLAN 4096-bit filter */
2879e749f25SAlexander Motin 
2889e749f25SAlexander Motin 	/* Receive */
2899e749f25SAlexander Motin 	struct e1000_rx_desc *esc_rxdesc;
2909e749f25SAlexander Motin 	pthread_cond_t	esc_rx_cond;
2919e749f25SAlexander Motin 	int		esc_rx_enabled;
2929e749f25SAlexander Motin 	int		esc_rx_active;
2939e749f25SAlexander Motin 	int		esc_rx_loopback;
2949e749f25SAlexander Motin 	uint32_t	esc_RCTL;	/* x0100 receive ctl */
2959e749f25SAlexander Motin 	uint32_t	esc_FCRTL;	/* x2160 flow cntl thresh, low */
2969e749f25SAlexander Motin 	uint32_t	esc_FCRTH;	/* x2168 flow cntl thresh, hi */
2979e749f25SAlexander Motin 	uint64_t	esc_rdba;	/* verified 64-bit desc table addr */
2989e749f25SAlexander Motin 	uint32_t	esc_RDBAL;	/* x2800 desc table addr, low bits */
2999e749f25SAlexander Motin 	uint32_t	esc_RDBAH;	/* x2804 desc table addr, hi 32-bits*/
3009e749f25SAlexander Motin 	uint32_t	esc_RDLEN;	/* x2808 #descriptors */
3019e749f25SAlexander Motin 	uint16_t	esc_RDH;	/* x2810 desc table head idx */
3029e749f25SAlexander Motin 	uint16_t	esc_RDT;	/* x2818 desc table tail idx */
3039e749f25SAlexander Motin 	uint32_t	esc_RDTR;	/* x2820 intr delay */
3049e749f25SAlexander Motin 	uint32_t	esc_RXDCTL;	/* x2828 desc control */
3059e749f25SAlexander Motin 	uint32_t	esc_RADV;	/* x282C intr absolute delay */
3069e749f25SAlexander Motin 	uint32_t	esc_RSRPD;	/* x2C00 recv small packet detect */
3079e749f25SAlexander Motin 	uint32_t	esc_RXCSUM;     /* x5000 receive cksum ctl */
3089e749f25SAlexander Motin 
3099e749f25SAlexander Motin 	/* IO Port register access */
3109e749f25SAlexander Motin 	uint32_t io_addr;
3119e749f25SAlexander Motin 
3129e749f25SAlexander Motin 	/* Shadow copy of MDIC */
3139e749f25SAlexander Motin 	uint32_t mdi_control;
3149e749f25SAlexander Motin 	/* Shadow copy of EECD */
3159e749f25SAlexander Motin 	uint32_t eeprom_control;
3169e749f25SAlexander Motin 	/* Latest NVM in/out */
3179e749f25SAlexander Motin 	uint16_t nvm_data;
3189e749f25SAlexander Motin 	uint16_t nvm_opaddr;
3199e749f25SAlexander Motin 	/* stats */
3209e749f25SAlexander Motin 	uint32_t missed_pkt_count; /* dropped for no room in rx queue */
3219e749f25SAlexander Motin 	uint32_t pkt_rx_by_size[6];
3229e749f25SAlexander Motin 	uint32_t pkt_tx_by_size[6];
3239e749f25SAlexander Motin 	uint32_t good_pkt_rx_count;
3249e749f25SAlexander Motin 	uint32_t bcast_pkt_rx_count;
3259e749f25SAlexander Motin 	uint32_t mcast_pkt_rx_count;
3269e749f25SAlexander Motin 	uint32_t good_pkt_tx_count;
3279e749f25SAlexander Motin 	uint32_t bcast_pkt_tx_count;
3289e749f25SAlexander Motin 	uint32_t mcast_pkt_tx_count;
3299e749f25SAlexander Motin 	uint32_t oversize_rx_count;
3309e749f25SAlexander Motin 	uint32_t tso_tx_count;
3319e749f25SAlexander Motin 	uint64_t good_octets_rx;
3329e749f25SAlexander Motin 	uint64_t good_octets_tx;
3339e749f25SAlexander Motin 	uint64_t missed_octets; /* counts missed and oversized */
3349e749f25SAlexander Motin 
3359e749f25SAlexander Motin 	uint8_t nvm_bits:6; /* number of bits remaining in/out */
3369e749f25SAlexander Motin 	uint8_t nvm_mode:2;
3379e749f25SAlexander Motin #define E82545_NVM_MODE_OPADDR  0x0
3389e749f25SAlexander Motin #define E82545_NVM_MODE_DATAIN  0x1
3399e749f25SAlexander Motin #define E82545_NVM_MODE_DATAOUT 0x2
3409e749f25SAlexander Motin         /* EEPROM data */
3419e749f25SAlexander Motin         uint16_t eeprom_data[E82545_NVM_EEPROM_SIZE];
3429e749f25SAlexander Motin };
3439e749f25SAlexander Motin 
3449e749f25SAlexander Motin static void e82545_reset(struct e82545_softc *sc, int dev);
3459e749f25SAlexander Motin static void e82545_rx_enable(struct e82545_softc *sc);
3469e749f25SAlexander Motin static void e82545_rx_disable(struct e82545_softc *sc);
3479e749f25SAlexander Motin static void e82545_tap_callback(int fd, enum ev_type type, void *param);
3489e749f25SAlexander Motin static void e82545_tx_start(struct e82545_softc *sc);
3499e749f25SAlexander Motin static void e82545_tx_enable(struct e82545_softc *sc);
3509e749f25SAlexander Motin static void e82545_tx_disable(struct e82545_softc *sc);
3519e749f25SAlexander Motin 
3529e749f25SAlexander Motin static inline int
3539e749f25SAlexander Motin e82545_size_stat_index(uint32_t size)
3549e749f25SAlexander Motin {
3559e749f25SAlexander Motin 	if (size <= 64) {
3569e749f25SAlexander Motin 		return 0;
3579e749f25SAlexander Motin 	} else if (size >= 1024) {
3589e749f25SAlexander Motin 		return 5;
3599e749f25SAlexander Motin 	} else {
3609e749f25SAlexander Motin 		/* should be 1-4 */
3619e749f25SAlexander Motin 		return (ffs(size) - 6);
3629e749f25SAlexander Motin 	}
3639e749f25SAlexander Motin }
3649e749f25SAlexander Motin 
3659e749f25SAlexander Motin static void
3669e749f25SAlexander Motin e82545_init_eeprom(struct e82545_softc *sc)
3679e749f25SAlexander Motin {
3689e749f25SAlexander Motin 	uint16_t checksum, i;
3699e749f25SAlexander Motin 
3709e749f25SAlexander Motin         /* mac addr */
3719e749f25SAlexander Motin 	sc->eeprom_data[NVM_MAC_ADDR] = ((uint16_t)sc->esc_mac.octet[0]) |
3729e749f25SAlexander Motin 		(((uint16_t)sc->esc_mac.octet[1]) << 8);
3739e749f25SAlexander Motin 	sc->eeprom_data[NVM_MAC_ADDR+1] = ((uint16_t)sc->esc_mac.octet[2]) |
3749e749f25SAlexander Motin 		(((uint16_t)sc->esc_mac.octet[3]) << 8);
3759e749f25SAlexander Motin 	sc->eeprom_data[NVM_MAC_ADDR+2] = ((uint16_t)sc->esc_mac.octet[4]) |
3769e749f25SAlexander Motin 		(((uint16_t)sc->esc_mac.octet[5]) << 8);
3779e749f25SAlexander Motin 
3789e749f25SAlexander Motin 	/* pci ids */
3799e749f25SAlexander Motin 	sc->eeprom_data[NVM_SUB_DEV_ID] = E82545_SUBDEV_ID;
3809e749f25SAlexander Motin 	sc->eeprom_data[NVM_SUB_VEN_ID] = E82545_VENDOR_ID_INTEL;
3819e749f25SAlexander Motin 	sc->eeprom_data[NVM_DEV_ID] = E82545_DEV_ID_82545EM_COPPER;
3829e749f25SAlexander Motin 	sc->eeprom_data[NVM_VEN_ID] = E82545_VENDOR_ID_INTEL;
3839e749f25SAlexander Motin 
3849e749f25SAlexander Motin 	/* fill in the checksum */
3859e749f25SAlexander Motin         checksum = 0;
3869e749f25SAlexander Motin 	for (i = 0; i < NVM_CHECKSUM_REG; i++) {
3879e749f25SAlexander Motin 		checksum += sc->eeprom_data[i];
3889e749f25SAlexander Motin 	}
3899e749f25SAlexander Motin 	checksum = NVM_SUM - checksum;
3909e749f25SAlexander Motin 	sc->eeprom_data[NVM_CHECKSUM_REG] = checksum;
3919e749f25SAlexander Motin 	DPRINTF("eeprom checksum: 0x%x\r\n", checksum);
3929e749f25SAlexander Motin }
3939e749f25SAlexander Motin 
3949e749f25SAlexander Motin static void
3959e749f25SAlexander Motin e82545_write_mdi(struct e82545_softc *sc, uint8_t reg_addr,
3969e749f25SAlexander Motin 			uint8_t phy_addr, uint32_t data)
3979e749f25SAlexander Motin {
3989e749f25SAlexander Motin 	DPRINTF("Write mdi reg:0x%x phy:0x%x data: 0x%x\r\n", reg_addr, phy_addr, data);
3999e749f25SAlexander Motin }
4009e749f25SAlexander Motin 
4019e749f25SAlexander Motin static uint32_t
4029e749f25SAlexander Motin e82545_read_mdi(struct e82545_softc *sc, uint8_t reg_addr,
4039e749f25SAlexander Motin 			uint8_t phy_addr)
4049e749f25SAlexander Motin {
4059e749f25SAlexander Motin 	//DPRINTF("Read mdi reg:0x%x phy:0x%x\r\n", reg_addr, phy_addr);
4069e749f25SAlexander Motin 	switch (reg_addr) {
4079e749f25SAlexander Motin 	case PHY_STATUS:
4089e749f25SAlexander Motin 		return (MII_SR_LINK_STATUS | MII_SR_AUTONEG_CAPS |
4099e749f25SAlexander Motin 			MII_SR_AUTONEG_COMPLETE);
4109e749f25SAlexander Motin 	case PHY_AUTONEG_ADV:
4119e749f25SAlexander Motin 		return NWAY_AR_SELECTOR_FIELD;
4129e749f25SAlexander Motin 	case PHY_LP_ABILITY:
4139e749f25SAlexander Motin 		return 0;
4149e749f25SAlexander Motin 	case PHY_1000T_STATUS:
4159e749f25SAlexander Motin 		return (SR_1000T_LP_FD_CAPS | SR_1000T_REMOTE_RX_STATUS |
4169e749f25SAlexander Motin 			SR_1000T_LOCAL_RX_STATUS);
4179e749f25SAlexander Motin 	case PHY_ID1:
4189e749f25SAlexander Motin 		return (M88E1011_I_PHY_ID >> 16) & 0xFFFF;
4199e749f25SAlexander Motin 	case PHY_ID2:
4209e749f25SAlexander Motin 		return (M88E1011_I_PHY_ID | E82545_REVISION_4) & 0xFFFF;
4219e749f25SAlexander Motin 	default:
4229e749f25SAlexander Motin 		DPRINTF("Unknown mdi read reg:0x%x phy:0x%x\r\n", reg_addr, phy_addr);
4239e749f25SAlexander Motin 		return 0;
4249e749f25SAlexander Motin 	}
4259e749f25SAlexander Motin 	/* not reached */
4269e749f25SAlexander Motin }
4279e749f25SAlexander Motin 
4289e749f25SAlexander Motin static void
4299e749f25SAlexander Motin e82545_eecd_strobe(struct e82545_softc *sc)
4309e749f25SAlexander Motin {
4319e749f25SAlexander Motin 	/* Microwire state machine */
4329e749f25SAlexander Motin 	/*
4339e749f25SAlexander Motin 	DPRINTF("eeprom state machine srtobe "
4349e749f25SAlexander Motin 		"0x%x 0x%x 0x%x 0x%x\r\n",
4359e749f25SAlexander Motin 		sc->nvm_mode, sc->nvm_bits,
4369e749f25SAlexander Motin 		sc->nvm_opaddr, sc->nvm_data);*/
4379e749f25SAlexander Motin 
4389e749f25SAlexander Motin 	if (sc->nvm_bits == 0) {
4399e749f25SAlexander Motin 		DPRINTF("eeprom state machine not expecting data! "
4409e749f25SAlexander Motin 			"0x%x 0x%x 0x%x 0x%x\r\n",
4419e749f25SAlexander Motin 			sc->nvm_mode, sc->nvm_bits,
4429e749f25SAlexander Motin 			sc->nvm_opaddr, sc->nvm_data);
4439e749f25SAlexander Motin 		return;
4449e749f25SAlexander Motin 	}
4459e749f25SAlexander Motin 	sc->nvm_bits--;
4469e749f25SAlexander Motin 	if (sc->nvm_mode == E82545_NVM_MODE_DATAOUT) {
4479e749f25SAlexander Motin 		/* shifting out */
4489e749f25SAlexander Motin 		if (sc->nvm_data & 0x8000) {
4499e749f25SAlexander Motin 			sc->eeprom_control |= E1000_EECD_DO;
4509e749f25SAlexander Motin 		} else {
4519e749f25SAlexander Motin 			sc->eeprom_control &= ~E1000_EECD_DO;
4529e749f25SAlexander Motin 		}
4539e749f25SAlexander Motin 		sc->nvm_data <<= 1;
4549e749f25SAlexander Motin 		if (sc->nvm_bits == 0) {
4559e749f25SAlexander Motin 			/* read done, back to opcode mode. */
4569e749f25SAlexander Motin 			sc->nvm_opaddr = 0;
4579e749f25SAlexander Motin 			sc->nvm_mode = E82545_NVM_MODE_OPADDR;
4589e749f25SAlexander Motin 			sc->nvm_bits = E82545_NVM_OPADDR_BITS;
4599e749f25SAlexander Motin 		}
4609e749f25SAlexander Motin 	} else if (sc->nvm_mode == E82545_NVM_MODE_DATAIN) {
4619e749f25SAlexander Motin 		/* shifting in */
4629e749f25SAlexander Motin 		sc->nvm_data <<= 1;
4639e749f25SAlexander Motin 		if (sc->eeprom_control & E1000_EECD_DI) {
4649e749f25SAlexander Motin 			sc->nvm_data |= 1;
4659e749f25SAlexander Motin 		}
4669e749f25SAlexander Motin 		if (sc->nvm_bits == 0) {
4679e749f25SAlexander Motin 			/* eeprom write */
4689e749f25SAlexander Motin 			uint16_t op = sc->nvm_opaddr & E82545_NVM_OPCODE_MASK;
4699e749f25SAlexander Motin 			uint16_t addr = sc->nvm_opaddr & E82545_NVM_ADDR_MASK;
4709e749f25SAlexander Motin 			if (op != E82545_NVM_OPCODE_WRITE) {
4719e749f25SAlexander Motin 				DPRINTF("Illegal eeprom write op 0x%x\r\n",
4729e749f25SAlexander Motin 					sc->nvm_opaddr);
4739e749f25SAlexander Motin 			} else if (addr >= E82545_NVM_EEPROM_SIZE) {
4749e749f25SAlexander Motin 				DPRINTF("Illegal eeprom write addr 0x%x\r\n",
4759e749f25SAlexander Motin 					sc->nvm_opaddr);
4769e749f25SAlexander Motin 			} else {
4779e749f25SAlexander Motin 				DPRINTF("eeprom write eeprom[0x%x] = 0x%x\r\n",
4789e749f25SAlexander Motin 				addr, sc->nvm_data);
4799e749f25SAlexander Motin 				sc->eeprom_data[addr] = sc->nvm_data;
4809e749f25SAlexander Motin 			}
4819e749f25SAlexander Motin 			/* back to opcode mode */
4829e749f25SAlexander Motin 			sc->nvm_opaddr = 0;
4839e749f25SAlexander Motin 			sc->nvm_mode = E82545_NVM_MODE_OPADDR;
4849e749f25SAlexander Motin 			sc->nvm_bits = E82545_NVM_OPADDR_BITS;
4859e749f25SAlexander Motin 		}
4869e749f25SAlexander Motin 	} else if (sc->nvm_mode == E82545_NVM_MODE_OPADDR) {
4879e749f25SAlexander Motin 		sc->nvm_opaddr <<= 1;
4889e749f25SAlexander Motin 		if (sc->eeprom_control & E1000_EECD_DI) {
4899e749f25SAlexander Motin 			sc->nvm_opaddr |= 1;
4909e749f25SAlexander Motin 		}
4919e749f25SAlexander Motin 		if (sc->nvm_bits == 0) {
4929e749f25SAlexander Motin 			uint16_t op = sc->nvm_opaddr & E82545_NVM_OPCODE_MASK;
4939e749f25SAlexander Motin 			switch (op) {
4949e749f25SAlexander Motin 			case E82545_NVM_OPCODE_EWEN:
4959e749f25SAlexander Motin 				DPRINTF("eeprom write enable: 0x%x\r\n",
4969e749f25SAlexander Motin 					sc->nvm_opaddr);
4979e749f25SAlexander Motin 				/* back to opcode mode */
4989e749f25SAlexander Motin 				sc->nvm_opaddr = 0;
4999e749f25SAlexander Motin 				sc->nvm_mode = E82545_NVM_MODE_OPADDR;
5009e749f25SAlexander Motin 				sc->nvm_bits = E82545_NVM_OPADDR_BITS;
5019e749f25SAlexander Motin 				break;
5029e749f25SAlexander Motin 			case E82545_NVM_OPCODE_READ:
5039e749f25SAlexander Motin 			{
5049e749f25SAlexander Motin 				uint16_t addr = sc->nvm_opaddr &
5059e749f25SAlexander Motin 					E82545_NVM_ADDR_MASK;
5069e749f25SAlexander Motin 				sc->nvm_mode = E82545_NVM_MODE_DATAOUT;
5079e749f25SAlexander Motin 				sc->nvm_bits = E82545_NVM_DATA_BITS;
5089e749f25SAlexander Motin 				if (addr < E82545_NVM_EEPROM_SIZE) {
5099e749f25SAlexander Motin 					sc->nvm_data = sc->eeprom_data[addr];
5109e749f25SAlexander Motin 					DPRINTF("eeprom read: eeprom[0x%x] = 0x%x\r\n",
5119e749f25SAlexander Motin 						addr, sc->nvm_data);
5129e749f25SAlexander Motin 				} else {
5139e749f25SAlexander Motin 					DPRINTF("eeprom illegal read: 0x%x\r\n",
5149e749f25SAlexander Motin 						sc->nvm_opaddr);
5159e749f25SAlexander Motin 					sc->nvm_data = 0;
5169e749f25SAlexander Motin 				}
5179e749f25SAlexander Motin 				break;
5189e749f25SAlexander Motin 			}
5199e749f25SAlexander Motin 			case E82545_NVM_OPCODE_WRITE:
5209e749f25SAlexander Motin 				sc->nvm_mode = E82545_NVM_MODE_DATAIN;
5219e749f25SAlexander Motin 				sc->nvm_bits = E82545_NVM_DATA_BITS;
5229e749f25SAlexander Motin 				sc->nvm_data = 0;
5239e749f25SAlexander Motin 				break;
5249e749f25SAlexander Motin 			default:
5259e749f25SAlexander Motin 				DPRINTF("eeprom unknown op: 0x%x\r\r",
5269e749f25SAlexander Motin 					sc->nvm_opaddr);
5279e749f25SAlexander Motin 				/* back to opcode mode */
5289e749f25SAlexander Motin 				sc->nvm_opaddr = 0;
5299e749f25SAlexander Motin 				sc->nvm_mode = E82545_NVM_MODE_OPADDR;
5309e749f25SAlexander Motin 				sc->nvm_bits = E82545_NVM_OPADDR_BITS;
5319e749f25SAlexander Motin 			}
5329e749f25SAlexander Motin 		}
5339e749f25SAlexander Motin 	} else {
5349e749f25SAlexander Motin 		DPRINTF("eeprom state machine wrong state! "
5359e749f25SAlexander Motin 			"0x%x 0x%x 0x%x 0x%x\r\n",
5369e749f25SAlexander Motin 			sc->nvm_mode, sc->nvm_bits,
5379e749f25SAlexander Motin 			sc->nvm_opaddr, sc->nvm_data);
5389e749f25SAlexander Motin 	}
5399e749f25SAlexander Motin }
5409e749f25SAlexander Motin 
5419e749f25SAlexander Motin static void
5429e749f25SAlexander Motin e82545_itr_callback(int fd, enum ev_type type, void *param)
5439e749f25SAlexander Motin {
5449e749f25SAlexander Motin 	uint32_t new;
5459e749f25SAlexander Motin 	struct e82545_softc *sc = param;
5469e749f25SAlexander Motin 
5479e749f25SAlexander Motin 	pthread_mutex_lock(&sc->esc_mtx);
5489e749f25SAlexander Motin 	new = sc->esc_ICR & sc->esc_IMS;
5499e749f25SAlexander Motin 	if (new && !sc->esc_irq_asserted) {
5509e749f25SAlexander Motin 		DPRINTF("itr callback: lintr assert %x\r\n", new);
5519e749f25SAlexander Motin 		sc->esc_irq_asserted = 1;
5529e749f25SAlexander Motin 		pci_lintr_assert(sc->esc_pi);
5539e749f25SAlexander Motin 	} else {
5549e749f25SAlexander Motin 		mevent_delete(sc->esc_mevpitr);
5559e749f25SAlexander Motin 		sc->esc_mevpitr = NULL;
5569e749f25SAlexander Motin 	}
5579e749f25SAlexander Motin 	pthread_mutex_unlock(&sc->esc_mtx);
5589e749f25SAlexander Motin }
5599e749f25SAlexander Motin 
5609e749f25SAlexander Motin static void
5619e749f25SAlexander Motin e82545_icr_assert(struct e82545_softc *sc, uint32_t bits)
5629e749f25SAlexander Motin {
5639e749f25SAlexander Motin 	uint32_t new;
5649e749f25SAlexander Motin 
5659e749f25SAlexander Motin 	DPRINTF("icr assert: 0x%x\r\n", bits);
5669e749f25SAlexander Motin 
5679e749f25SAlexander Motin 	/*
5689e749f25SAlexander Motin 	 * An interrupt is only generated if bits are set that
5699e749f25SAlexander Motin 	 * aren't already in the ICR, these bits are unmasked,
5709e749f25SAlexander Motin 	 * and there isn't an interrupt already pending.
5719e749f25SAlexander Motin 	 */
5729e749f25SAlexander Motin 	new = bits & ~sc->esc_ICR & sc->esc_IMS;
5739e749f25SAlexander Motin 	sc->esc_ICR |= bits;
5749e749f25SAlexander Motin 
5759e749f25SAlexander Motin 	if (new == 0) {
5769e749f25SAlexander Motin 		DPRINTF("icr assert: masked %x, ims %x\r\n", new, sc->esc_IMS);
5779e749f25SAlexander Motin 	} else if (sc->esc_mevpitr != NULL) {
5789e749f25SAlexander Motin 		DPRINTF("icr assert: throttled %x, ims %x\r\n", new, sc->esc_IMS);
5799e749f25SAlexander Motin 	} else if (!sc->esc_irq_asserted) {
5809e749f25SAlexander Motin 		DPRINTF("icr assert: lintr assert %x\r\n", new);
5819e749f25SAlexander Motin 		sc->esc_irq_asserted = 1;
5829e749f25SAlexander Motin 		pci_lintr_assert(sc->esc_pi);
5839e749f25SAlexander Motin 		if (sc->esc_ITR != 0) {
5849e749f25SAlexander Motin 			sc->esc_mevpitr = mevent_add(
5859e749f25SAlexander Motin 			    (sc->esc_ITR + 3905) / 3906,  /* 256ns -> 1ms */
5869e749f25SAlexander Motin 			    EVF_TIMER, e82545_itr_callback, sc);
5879e749f25SAlexander Motin 		}
5889e749f25SAlexander Motin 	}
5899e749f25SAlexander Motin }
5909e749f25SAlexander Motin 
5919e749f25SAlexander Motin static void
5929e749f25SAlexander Motin e82545_ims_change(struct e82545_softc *sc, uint32_t bits)
5939e749f25SAlexander Motin {
5949e749f25SAlexander Motin 	uint32_t new;
5959e749f25SAlexander Motin 
5969e749f25SAlexander Motin 	/*
5979e749f25SAlexander Motin 	 * Changing the mask may allow previously asserted
5989e749f25SAlexander Motin 	 * but masked interrupt requests to generate an interrupt.
5999e749f25SAlexander Motin 	 */
6009e749f25SAlexander Motin 	new = bits & sc->esc_ICR & ~sc->esc_IMS;
6019e749f25SAlexander Motin 	sc->esc_IMS |= bits;
6029e749f25SAlexander Motin 
6039e749f25SAlexander Motin 	if (new == 0) {
6049e749f25SAlexander Motin 		DPRINTF("ims change: masked %x, ims %x\r\n", new, sc->esc_IMS);
6059e749f25SAlexander Motin 	} else if (sc->esc_mevpitr != NULL) {
6069e749f25SAlexander Motin 		DPRINTF("ims change: throttled %x, ims %x\r\n", new, sc->esc_IMS);
6079e749f25SAlexander Motin 	} else if (!sc->esc_irq_asserted) {
6089e749f25SAlexander Motin 		DPRINTF("ims change: lintr assert %x\n\r", new);
6099e749f25SAlexander Motin 		sc->esc_irq_asserted = 1;
6109e749f25SAlexander Motin 		pci_lintr_assert(sc->esc_pi);
6119e749f25SAlexander Motin 		if (sc->esc_ITR != 0) {
6129e749f25SAlexander Motin 			sc->esc_mevpitr = mevent_add(
6139e749f25SAlexander Motin 			    (sc->esc_ITR + 3905) / 3906,  /* 256ns -> 1ms */
6149e749f25SAlexander Motin 			    EVF_TIMER, e82545_itr_callback, sc);
6159e749f25SAlexander Motin 		}
6169e749f25SAlexander Motin 	}
6179e749f25SAlexander Motin }
6189e749f25SAlexander Motin 
6199e749f25SAlexander Motin static void
6209e749f25SAlexander Motin e82545_icr_deassert(struct e82545_softc *sc, uint32_t bits)
6219e749f25SAlexander Motin {
6229e749f25SAlexander Motin 
6239e749f25SAlexander Motin 	DPRINTF("icr deassert: 0x%x\r\n", bits);
6249e749f25SAlexander Motin 	sc->esc_ICR &= ~bits;
6259e749f25SAlexander Motin 
6269e749f25SAlexander Motin 	/*
6279e749f25SAlexander Motin 	 * If there are no longer any interrupt sources and there
6289e749f25SAlexander Motin 	 * was an asserted interrupt, clear it
6299e749f25SAlexander Motin 	 */
6309e749f25SAlexander Motin 	if (sc->esc_irq_asserted && !(sc->esc_ICR & sc->esc_IMS)) {
6319e749f25SAlexander Motin 		DPRINTF("icr deassert: lintr deassert %x\r\n", bits);
6329e749f25SAlexander Motin 		pci_lintr_deassert(sc->esc_pi);
6339e749f25SAlexander Motin 		sc->esc_irq_asserted = 0;
6349e749f25SAlexander Motin 	}
6359e749f25SAlexander Motin }
6369e749f25SAlexander Motin 
6379e749f25SAlexander Motin static void
6389e749f25SAlexander Motin e82545_intr_write(struct e82545_softc *sc, uint32_t offset, uint32_t value)
6399e749f25SAlexander Motin {
6409e749f25SAlexander Motin 
6419e749f25SAlexander Motin 	DPRINTF("intr_write: off %x, val %x\n\r", offset, value);
6429e749f25SAlexander Motin 
6439e749f25SAlexander Motin 	switch (offset) {
6449e749f25SAlexander Motin 	case E1000_ICR:
6459e749f25SAlexander Motin 		e82545_icr_deassert(sc, value);
6469e749f25SAlexander Motin 		break;
6479e749f25SAlexander Motin 	case E1000_ITR:
6489e749f25SAlexander Motin 		sc->esc_ITR = value;
6499e749f25SAlexander Motin 		break;
6509e749f25SAlexander Motin 	case E1000_ICS:
6519e749f25SAlexander Motin 		sc->esc_ICS = value;	/* not used: store for debug */
6529e749f25SAlexander Motin 		e82545_icr_assert(sc, value);
6539e749f25SAlexander Motin 		break;
6549e749f25SAlexander Motin 	case E1000_IMS:
6559e749f25SAlexander Motin 		e82545_ims_change(sc, value);
6569e749f25SAlexander Motin 		break;
6579e749f25SAlexander Motin 	case E1000_IMC:
6589e749f25SAlexander Motin 		sc->esc_IMC = value;	/* for debug */
6599e749f25SAlexander Motin 		sc->esc_IMS &= ~value;
6609e749f25SAlexander Motin 		// XXX clear interrupts if all ICR bits now masked
6619e749f25SAlexander Motin 		// and interrupt was pending ?
6629e749f25SAlexander Motin 		break;
6639e749f25SAlexander Motin 	default:
6649e749f25SAlexander Motin 		break;
6659e749f25SAlexander Motin 	}
6669e749f25SAlexander Motin }
6679e749f25SAlexander Motin 
6689e749f25SAlexander Motin static uint32_t
6699e749f25SAlexander Motin e82545_intr_read(struct e82545_softc *sc, uint32_t offset)
6709e749f25SAlexander Motin {
6719e749f25SAlexander Motin 	uint32_t retval;
6729e749f25SAlexander Motin 
6739e749f25SAlexander Motin 	retval = 0;
6749e749f25SAlexander Motin 
6759e749f25SAlexander Motin 	DPRINTF("intr_read: off %x\n\r", offset);
6769e749f25SAlexander Motin 
6779e749f25SAlexander Motin 	switch (offset) {
6789e749f25SAlexander Motin 	case E1000_ICR:
6799e749f25SAlexander Motin 		retval = sc->esc_ICR;
6809e749f25SAlexander Motin 		sc->esc_ICR = 0;
6819e749f25SAlexander Motin 		e82545_icr_deassert(sc, ~0);
6829e749f25SAlexander Motin 		break;
6839e749f25SAlexander Motin 	case E1000_ITR:
6849e749f25SAlexander Motin 		retval = sc->esc_ITR;
6859e749f25SAlexander Motin 		break;
6869e749f25SAlexander Motin 	case E1000_ICS:
6879e749f25SAlexander Motin 		/* write-only register */
6889e749f25SAlexander Motin 		break;
6899e749f25SAlexander Motin 	case E1000_IMS:
6909e749f25SAlexander Motin 		retval = sc->esc_IMS;
6919e749f25SAlexander Motin 		break;
6929e749f25SAlexander Motin 	case E1000_IMC:
6939e749f25SAlexander Motin 		/* write-only register */
6949e749f25SAlexander Motin 		break;
6959e749f25SAlexander Motin 	default:
6969e749f25SAlexander Motin 		break;
6979e749f25SAlexander Motin 	}
6989e749f25SAlexander Motin 
6999e749f25SAlexander Motin 	return (retval);
7009e749f25SAlexander Motin }
7019e749f25SAlexander Motin 
7029e749f25SAlexander Motin static void
7039e749f25SAlexander Motin e82545_devctl(struct e82545_softc *sc, uint32_t val)
7049e749f25SAlexander Motin {
7059e749f25SAlexander Motin 
7069e749f25SAlexander Motin 	sc->esc_CTRL = val & ~E1000_CTRL_RST;
7079e749f25SAlexander Motin 
7089e749f25SAlexander Motin 	if (val & E1000_CTRL_RST) {
7099e749f25SAlexander Motin 		DPRINTF("e1k: s/w reset, ctl %x\n", val);
7109e749f25SAlexander Motin 		e82545_reset(sc, 1);
7119e749f25SAlexander Motin 	}
7129e749f25SAlexander Motin 	/* XXX check for phy reset ? */
7139e749f25SAlexander Motin }
7149e749f25SAlexander Motin 
7159e749f25SAlexander Motin static void
7169e749f25SAlexander Motin e82545_rx_update_rdba(struct e82545_softc *sc)
7179e749f25SAlexander Motin {
7189e749f25SAlexander Motin 
7199e749f25SAlexander Motin 	/* XXX verify desc base/len within phys mem range */
7209e749f25SAlexander Motin 	sc->esc_rdba = (uint64_t)sc->esc_RDBAH << 32 |
7219e749f25SAlexander Motin 	    sc->esc_RDBAL;
7229e749f25SAlexander Motin 
7239e749f25SAlexander Motin 	/* Cache host mapping of guest descriptor array */
7249e749f25SAlexander Motin 	sc->esc_rxdesc = paddr_guest2host(sc->esc_ctx,
7259e749f25SAlexander Motin 	    sc->esc_rdba, sc->esc_RDLEN);
7269e749f25SAlexander Motin }
7279e749f25SAlexander Motin 
7289e749f25SAlexander Motin static void
7299e749f25SAlexander Motin e82545_rx_ctl(struct e82545_softc *sc, uint32_t val)
7309e749f25SAlexander Motin {
7319e749f25SAlexander Motin 	int on;
7329e749f25SAlexander Motin 
7339e749f25SAlexander Motin 	on = ((val & E1000_RCTL_EN) == E1000_RCTL_EN);
7349e749f25SAlexander Motin 
7359e749f25SAlexander Motin 	/* Save RCTL after stripping reserved bits 31:27,24,21,14,11:10,0 */
7369e749f25SAlexander Motin 	sc->esc_RCTL = val & ~0xF9204c01;
7379e749f25SAlexander Motin 
7389e749f25SAlexander Motin 	DPRINTF("rx_ctl - %s RCTL %x, val %x\n",
7399e749f25SAlexander Motin 		on ? "on" : "off", sc->esc_RCTL, val);
7409e749f25SAlexander Motin 
7419e749f25SAlexander Motin 	/* state change requested */
7429e749f25SAlexander Motin 	if (on != sc->esc_rx_enabled) {
7439e749f25SAlexander Motin 		if (on) {
7449e749f25SAlexander Motin 			/* Catch disallowed/unimplemented settings */
7459e749f25SAlexander Motin 			//assert(!(val & E1000_RCTL_LBM_TCVR));
7469e749f25SAlexander Motin 
7479e749f25SAlexander Motin 			if (sc->esc_RCTL & E1000_RCTL_LBM_TCVR) {
7489e749f25SAlexander Motin 				sc->esc_rx_loopback = 1;
7499e749f25SAlexander Motin 			} else {
7509e749f25SAlexander Motin 				sc->esc_rx_loopback = 0;
7519e749f25SAlexander Motin 			}
7529e749f25SAlexander Motin 
7539e749f25SAlexander Motin 			e82545_rx_update_rdba(sc);
7549e749f25SAlexander Motin 			e82545_rx_enable(sc);
7559e749f25SAlexander Motin 		} else {
7569e749f25SAlexander Motin 			e82545_rx_disable(sc);
7579e749f25SAlexander Motin 			sc->esc_rx_loopback = 0;
7589e749f25SAlexander Motin 			sc->esc_rdba = 0;
7599e749f25SAlexander Motin 			sc->esc_rxdesc = NULL;
7609e749f25SAlexander Motin 		}
7619e749f25SAlexander Motin 	}
7629e749f25SAlexander Motin }
7639e749f25SAlexander Motin 
7649e749f25SAlexander Motin static void
7659e749f25SAlexander Motin e82545_tx_update_tdba(struct e82545_softc *sc)
7669e749f25SAlexander Motin {
7679e749f25SAlexander Motin 
7689e749f25SAlexander Motin 	/* XXX verify desc base/len within phys mem range */
7699e749f25SAlexander Motin 	sc->esc_tdba = (uint64_t)sc->esc_TDBAH << 32 | sc->esc_TDBAL;
7709e749f25SAlexander Motin 
7719e749f25SAlexander Motin 	/* Cache host mapping of guest descriptor array */
7729e749f25SAlexander Motin 	sc->esc_txdesc = paddr_guest2host(sc->esc_ctx, sc->esc_tdba,
7739e749f25SAlexander Motin             sc->esc_TDLEN);
7749e749f25SAlexander Motin }
7759e749f25SAlexander Motin 
7769e749f25SAlexander Motin static void
7779e749f25SAlexander Motin e82545_tx_ctl(struct e82545_softc *sc, uint32_t val)
7789e749f25SAlexander Motin {
7799e749f25SAlexander Motin 	int on;
7809e749f25SAlexander Motin 
7819e749f25SAlexander Motin 	on = ((val & E1000_TCTL_EN) == E1000_TCTL_EN);
7829e749f25SAlexander Motin 
7839e749f25SAlexander Motin 	/* ignore TCTL_EN settings that don't change state */
7849e749f25SAlexander Motin 	if (on == sc->esc_tx_enabled)
7859e749f25SAlexander Motin 		return;
7869e749f25SAlexander Motin 
7879e749f25SAlexander Motin 	if (on) {
7889e749f25SAlexander Motin 		e82545_tx_update_tdba(sc);
7899e749f25SAlexander Motin 		e82545_tx_enable(sc);
7909e749f25SAlexander Motin 	} else {
7919e749f25SAlexander Motin 		e82545_tx_disable(sc);
7929e749f25SAlexander Motin 		sc->esc_tdba = 0;
7939e749f25SAlexander Motin 		sc->esc_txdesc = NULL;
7949e749f25SAlexander Motin 	}
7959e749f25SAlexander Motin 
7969e749f25SAlexander Motin 	/* Save TCTL value after stripping reserved bits 31:25,23,2,0 */
7979e749f25SAlexander Motin 	sc->esc_TCTL = val & ~0xFE800005;
7989e749f25SAlexander Motin }
7999e749f25SAlexander Motin 
8009e749f25SAlexander Motin int
8019e749f25SAlexander Motin e82545_bufsz(uint32_t rctl)
8029e749f25SAlexander Motin {
8039e749f25SAlexander Motin 
8049e749f25SAlexander Motin 	switch (rctl & (E1000_RCTL_BSEX | E1000_RCTL_SZ_256)) {
8059e749f25SAlexander Motin 	case (E1000_RCTL_SZ_2048): return (2048);
8069e749f25SAlexander Motin 	case (E1000_RCTL_SZ_1024): return (1024);
8079e749f25SAlexander Motin 	case (E1000_RCTL_SZ_512): return (512);
8089e749f25SAlexander Motin 	case (E1000_RCTL_SZ_256): return (256);
8099e749f25SAlexander Motin 	case (E1000_RCTL_BSEX|E1000_RCTL_SZ_16384): return (16384);
8109e749f25SAlexander Motin 	case (E1000_RCTL_BSEX|E1000_RCTL_SZ_8192): return (8192);
8119e749f25SAlexander Motin 	case (E1000_RCTL_BSEX|E1000_RCTL_SZ_4096): return (4096);
8129e749f25SAlexander Motin 	}
8139e749f25SAlexander Motin 	return (256);	/* Forbidden value. */
8149e749f25SAlexander Motin }
8159e749f25SAlexander Motin 
8169e749f25SAlexander Motin static uint8_t dummybuf[2048];
8179e749f25SAlexander Motin 
8189e749f25SAlexander Motin /* XXX one packet at a time until this is debugged */
8199e749f25SAlexander Motin static void
8209e749f25SAlexander Motin e82545_tap_callback(int fd, enum ev_type type, void *param)
8219e749f25SAlexander Motin {
8229e749f25SAlexander Motin 	struct e82545_softc *sc = param;
8239e749f25SAlexander Motin 	struct e1000_rx_desc *rxd;
8249e749f25SAlexander Motin 	struct iovec vec[64];
8259e749f25SAlexander Motin 	int left, len, lim, maxpktsz, maxpktdesc, bufsz, i, n, size;
8269e749f25SAlexander Motin 	uint32_t cause = 0;
8279e749f25SAlexander Motin 	uint16_t *tp, tag, head;
8289e749f25SAlexander Motin 
8299e749f25SAlexander Motin 	pthread_mutex_lock(&sc->esc_mtx);
8309e749f25SAlexander Motin 	DPRINTF("rx_run: head %x, tail %x\r\n", sc->esc_RDH, sc->esc_RDT);
8319e749f25SAlexander Motin 
8329e749f25SAlexander Motin 	if (!sc->esc_rx_enabled || sc->esc_rx_loopback) {
8339e749f25SAlexander Motin 		DPRINTF("rx disabled (!%d || %d) -- packet(s) dropped\r\n",
8349e749f25SAlexander Motin 		    sc->esc_rx_enabled, sc->esc_rx_loopback);
8359e749f25SAlexander Motin 		while (read(sc->esc_tapfd, dummybuf, sizeof(dummybuf)) > 0) {
8369e749f25SAlexander Motin 		}
8379e749f25SAlexander Motin 		goto done1;
8389e749f25SAlexander Motin 	}
8399e749f25SAlexander Motin 	bufsz = e82545_bufsz(sc->esc_RCTL);
8409e749f25SAlexander Motin 	maxpktsz = (sc->esc_RCTL & E1000_RCTL_LPE) ? 16384 : 1522;
8419e749f25SAlexander Motin 	maxpktdesc = (maxpktsz + bufsz - 1) / bufsz;
8429e749f25SAlexander Motin 	size = sc->esc_RDLEN / 16;
8439e749f25SAlexander Motin 	head = sc->esc_RDH;
8449e749f25SAlexander Motin 	left = (size + sc->esc_RDT - head) % size;
8459e749f25SAlexander Motin 	if (left < maxpktdesc) {
8469e749f25SAlexander Motin 		DPRINTF("rx overflow (%d < %d) -- packet(s) dropped\r\n",
8479e749f25SAlexander Motin 		    left, maxpktdesc);
8489e749f25SAlexander Motin 		while (read(sc->esc_tapfd, dummybuf, sizeof(dummybuf)) > 0) {
8499e749f25SAlexander Motin 		}
8509e749f25SAlexander Motin 		goto done1;
8519e749f25SAlexander Motin 	}
8529e749f25SAlexander Motin 
8539e749f25SAlexander Motin 	sc->esc_rx_active = 1;
8549e749f25SAlexander Motin 	pthread_mutex_unlock(&sc->esc_mtx);
8559e749f25SAlexander Motin 
8569e749f25SAlexander Motin 	for (lim = size / 4; lim > 0 && left >= maxpktdesc; lim -= n) {
8579e749f25SAlexander Motin 
8589e749f25SAlexander Motin 		/* Grab rx descriptor pointed to by the head pointer */
8599e749f25SAlexander Motin 		for (i = 0; i < maxpktdesc; i++) {
8609e749f25SAlexander Motin 			rxd = &sc->esc_rxdesc[(head + i) % size];
8619e749f25SAlexander Motin 			vec[i].iov_base = paddr_guest2host(sc->esc_ctx,
8629e749f25SAlexander Motin 			    rxd->buffer_addr, bufsz);
8639e749f25SAlexander Motin 			vec[i].iov_len = bufsz;
8649e749f25SAlexander Motin 		}
8659e749f25SAlexander Motin 		len = readv(sc->esc_tapfd, vec, maxpktdesc);
8669e749f25SAlexander Motin 		if (len <= 0) {
8679e749f25SAlexander Motin 			DPRINTF("tap: readv() returned %d\n", len);
8689e749f25SAlexander Motin 			goto done;
8699e749f25SAlexander Motin 		}
8709e749f25SAlexander Motin 
8719e749f25SAlexander Motin 		/*
8729e749f25SAlexander Motin 		 * Adjust the packet length based on whether the CRC needs
8739e749f25SAlexander Motin 		 * to be stripped or if the packet is less than the minimum
8749e749f25SAlexander Motin 		 * eth packet size.
8759e749f25SAlexander Motin 		 */
8769e749f25SAlexander Motin 		if (len < ETHER_MIN_LEN - ETHER_CRC_LEN)
8779e749f25SAlexander Motin 			len = ETHER_MIN_LEN - ETHER_CRC_LEN;
8789e749f25SAlexander Motin 		if (!(sc->esc_RCTL & E1000_RCTL_SECRC))
8799e749f25SAlexander Motin 			len += ETHER_CRC_LEN;
8809e749f25SAlexander Motin 		n = (len + bufsz - 1) / bufsz;
8819e749f25SAlexander Motin 
8829e749f25SAlexander Motin 		DPRINTF("packet read %d bytes, %d segs, head %d\r\n",
8839e749f25SAlexander Motin 		    len, n, head);
8849e749f25SAlexander Motin 
8859e749f25SAlexander Motin 		/* Apply VLAN filter. */
8869e749f25SAlexander Motin 		tp = (uint16_t *)vec[0].iov_base + 6;
8879e749f25SAlexander Motin 		if ((sc->esc_RCTL & E1000_RCTL_VFE) &&
8889e749f25SAlexander Motin 		    (ntohs(tp[0]) == sc->esc_VET)) {
8899e749f25SAlexander Motin 			tag = ntohs(tp[1]) & 0x0fff;
8909e749f25SAlexander Motin 			if ((sc->esc_fvlan[tag >> 5] &
8919e749f25SAlexander Motin 			    (1 << (tag & 0x1f))) != 0) {
8929e749f25SAlexander Motin 				DPRINTF("known VLAN %d\r\n", tag);
8939e749f25SAlexander Motin 			} else {
8949e749f25SAlexander Motin 				DPRINTF("unknown VLAN %d\r\n", tag);
8959e749f25SAlexander Motin 				n = 0;
8969e749f25SAlexander Motin 				continue;
8979e749f25SAlexander Motin 			}
8989e749f25SAlexander Motin 		}
8999e749f25SAlexander Motin 
9009e749f25SAlexander Motin 		/* Update all consumed descriptors. */
9019e749f25SAlexander Motin 		for (i = 0; i < n - 1; i++) {
9029e749f25SAlexander Motin 			rxd = &sc->esc_rxdesc[(head + i) % size];
9039e749f25SAlexander Motin 			rxd->length = bufsz;
9049e749f25SAlexander Motin 			rxd->csum = 0;
9059e749f25SAlexander Motin 			rxd->errors = 0;
9069e749f25SAlexander Motin 			rxd->special = 0;
9079e749f25SAlexander Motin 			rxd->status = E1000_RXD_STAT_DD;
9089e749f25SAlexander Motin 		}
9099e749f25SAlexander Motin 		rxd = &sc->esc_rxdesc[(head + i) % size];
9109e749f25SAlexander Motin 		rxd->length = len % bufsz;
9119e749f25SAlexander Motin 		rxd->csum = 0;
9129e749f25SAlexander Motin 		rxd->errors = 0;
9139e749f25SAlexander Motin 		rxd->special = 0;
9149e749f25SAlexander Motin 		/* XXX signal no checksum for now */
9159e749f25SAlexander Motin 		rxd->status = E1000_RXD_STAT_PIF | E1000_RXD_STAT_IXSM |
9169e749f25SAlexander Motin 		    E1000_RXD_STAT_EOP | E1000_RXD_STAT_DD;
9179e749f25SAlexander Motin 
9189e749f25SAlexander Motin 		/* Schedule receive interrupts. */
9199e749f25SAlexander Motin 		if (len <= sc->esc_RSRPD) {
9209e749f25SAlexander Motin 			cause |= E1000_ICR_SRPD | E1000_ICR_RXT0;
9219e749f25SAlexander Motin 		} else {
9229e749f25SAlexander Motin 			/* XXX: RDRT and RADV timers should be here. */
9239e749f25SAlexander Motin 			cause |= E1000_ICR_RXT0;
9249e749f25SAlexander Motin 		}
9259e749f25SAlexander Motin 
9269e749f25SAlexander Motin 		head = (head + n) % size;
9279e749f25SAlexander Motin 		left -= n;
9289e749f25SAlexander Motin 	}
9299e749f25SAlexander Motin 
9309e749f25SAlexander Motin done:
9319e749f25SAlexander Motin 	pthread_mutex_lock(&sc->esc_mtx);
9329e749f25SAlexander Motin 	sc->esc_rx_active = 0;
9339e749f25SAlexander Motin 	if (sc->esc_rx_enabled == 0)
9349e749f25SAlexander Motin 		pthread_cond_signal(&sc->esc_rx_cond);
9359e749f25SAlexander Motin 
9369e749f25SAlexander Motin 	sc->esc_RDH = head;
9379e749f25SAlexander Motin 	/* Respect E1000_RCTL_RDMTS */
9389e749f25SAlexander Motin 	left = (size + sc->esc_RDT - head) % size;
9399e749f25SAlexander Motin 	if (left < (size >> (((sc->esc_RCTL >> 8) & 3) + 1)))
9409e749f25SAlexander Motin 		cause |= E1000_ICR_RXDMT0;
9419e749f25SAlexander Motin 	/* Assert all accumulated interrupts. */
9429e749f25SAlexander Motin 	if (cause != 0)
9439e749f25SAlexander Motin 		e82545_icr_assert(sc, cause);
9449e749f25SAlexander Motin done1:
9459e749f25SAlexander Motin 	DPRINTF("rx_run done: head %x, tail %x\r\n", sc->esc_RDH, sc->esc_RDT);
9469e749f25SAlexander Motin 	pthread_mutex_unlock(&sc->esc_mtx);
9479e749f25SAlexander Motin }
9489e749f25SAlexander Motin 
9499e749f25SAlexander Motin static uint16_t
9509e749f25SAlexander Motin e82545_carry(uint32_t sum)
9519e749f25SAlexander Motin {
9529e749f25SAlexander Motin 
9539e749f25SAlexander Motin 	sum = (sum & 0xFFFF) + (sum >> 16);
9549e749f25SAlexander Motin 	if (sum > 0xFFFF)
9559e749f25SAlexander Motin 		sum -= 0xFFFF;
9569e749f25SAlexander Motin 	return (sum);
9579e749f25SAlexander Motin }
9589e749f25SAlexander Motin 
9599e749f25SAlexander Motin static uint16_t
9609e749f25SAlexander Motin e82545_buf_checksum(uint8_t *buf, int len)
9619e749f25SAlexander Motin {
9629e749f25SAlexander Motin 	int i;
9639e749f25SAlexander Motin 	uint32_t sum = 0;
9649e749f25SAlexander Motin 
9659e749f25SAlexander Motin 	/* Checksum all the pairs of bytes first... */
9669e749f25SAlexander Motin 	for (i = 0; i < (len & ~1U); i += 2)
9679e749f25SAlexander Motin 		sum += *((u_int16_t *)(buf + i));
9689e749f25SAlexander Motin 
9699e749f25SAlexander Motin 	/*
9709e749f25SAlexander Motin 	 * If there's a single byte left over, checksum it, too.
9719e749f25SAlexander Motin 	 * Network byte order is big-endian, so the remaining byte is
9729e749f25SAlexander Motin 	 * the high byte.
9739e749f25SAlexander Motin 	 */
9749e749f25SAlexander Motin 	if (i < len)
9759e749f25SAlexander Motin 		sum += htons(buf[i] << 8);
9769e749f25SAlexander Motin 
9779e749f25SAlexander Motin 	return (e82545_carry(sum));
9789e749f25SAlexander Motin }
9799e749f25SAlexander Motin 
9809e749f25SAlexander Motin static uint16_t
9819e749f25SAlexander Motin e82545_iov_checksum(struct iovec *iov, int iovcnt, int off, int len)
9829e749f25SAlexander Motin {
9839e749f25SAlexander Motin 	int now, odd;
9849e749f25SAlexander Motin 	uint32_t sum = 0, s;
9859e749f25SAlexander Motin 
9869e749f25SAlexander Motin 	/* Skip completely unneeded vectors. */
9879e749f25SAlexander Motin 	while (iovcnt > 0 && iov->iov_len <= off && off > 0) {
9889e749f25SAlexander Motin 		off -= iov->iov_len;
9899e749f25SAlexander Motin 		iov++;
9909e749f25SAlexander Motin 		iovcnt--;
9919e749f25SAlexander Motin 	}
9929e749f25SAlexander Motin 
9939e749f25SAlexander Motin 	/* Calculate checksum of requested range. */
9949e749f25SAlexander Motin 	odd = 0;
9959e749f25SAlexander Motin 	while (len > 0 && iovcnt > 0) {
9969e749f25SAlexander Motin 		now = MIN(len, iov->iov_len - off);
9979e749f25SAlexander Motin 		s = e82545_buf_checksum(iov->iov_base + off, now);
9989e749f25SAlexander Motin 		sum += odd ? (s << 8) : s;
9999e749f25SAlexander Motin 		odd ^= (now & 1);
10009e749f25SAlexander Motin 		len -= now;
10019e749f25SAlexander Motin 		off = 0;
10029e749f25SAlexander Motin 		iov++;
10039e749f25SAlexander Motin 		iovcnt--;
10049e749f25SAlexander Motin 	}
10059e749f25SAlexander Motin 
10069e749f25SAlexander Motin 	return (e82545_carry(sum));
10079e749f25SAlexander Motin }
10089e749f25SAlexander Motin 
10099e749f25SAlexander Motin /*
10109e749f25SAlexander Motin  * Return the transmit descriptor type.
10119e749f25SAlexander Motin  */
10129e749f25SAlexander Motin int
10139e749f25SAlexander Motin e82545_txdesc_type(uint32_t lower)
10149e749f25SAlexander Motin {
10159e749f25SAlexander Motin 	int type;
10169e749f25SAlexander Motin 
10179e749f25SAlexander Motin 	type = 0;
10189e749f25SAlexander Motin 
10199e749f25SAlexander Motin 	if (lower & E1000_TXD_CMD_DEXT)
10209e749f25SAlexander Motin 		type = lower & E1000_TXD_MASK;
10219e749f25SAlexander Motin 
10229e749f25SAlexander Motin 	return (type);
10239e749f25SAlexander Motin }
10249e749f25SAlexander Motin 
10259e749f25SAlexander Motin static void
10269e749f25SAlexander Motin e82545_transmit_checksum(struct iovec *iov, int iovcnt, struct ck_info *ck)
10279e749f25SAlexander Motin {
10289e749f25SAlexander Motin 	uint16_t cksum;
10299e749f25SAlexander Motin 	int cklen;
10309e749f25SAlexander Motin 
10319e749f25SAlexander Motin 	DPRINTF("tx cksum: iovcnt/s/off/len %d/%d/%d/%d\r\n",
10329e749f25SAlexander Motin 	    iovcnt, ck->ck_start, ck->ck_off, ck->ck_len);
10339e749f25SAlexander Motin 	cklen = ck->ck_len ? ck->ck_len - ck->ck_start + 1 : INT_MAX;
10349e749f25SAlexander Motin 	cksum = e82545_iov_checksum(iov, iovcnt, ck->ck_start, cklen);
10359e749f25SAlexander Motin 	*(uint16_t *)((uint8_t *)iov[0].iov_base + ck->ck_off) = ~cksum;
10369e749f25SAlexander Motin }
10379e749f25SAlexander Motin 
10389e749f25SAlexander Motin static void
10399e749f25SAlexander Motin e82545_transmit_backend(struct e82545_softc *sc, struct iovec *iov, int iovcnt)
10409e749f25SAlexander Motin {
10419e749f25SAlexander Motin 
10429e749f25SAlexander Motin 	if (sc->esc_tapfd == -1)
10439e749f25SAlexander Motin 		return;
10449e749f25SAlexander Motin 
10459e749f25SAlexander Motin 	(void) writev(sc->esc_tapfd, iov, iovcnt);
10469e749f25SAlexander Motin }
10479e749f25SAlexander Motin 
10489e749f25SAlexander Motin static void
1049*ee7230f4SAlexander Motin e82545_transmit_done(struct e82545_softc *sc, uint16_t head, uint16_t tail,
1050*ee7230f4SAlexander Motin     uint16_t dsize, int *tdwb)
10519e749f25SAlexander Motin {
1052*ee7230f4SAlexander Motin 	union e1000_tx_udesc *dsc;
10539e749f25SAlexander Motin 
1054*ee7230f4SAlexander Motin 	for ( ; head != tail; head = (head + 1) % dsize) {
1055*ee7230f4SAlexander Motin 		dsc = &sc->esc_txdesc[head];
1056*ee7230f4SAlexander Motin 		if (dsc->td.lower.data & E1000_TXD_CMD_RS) {
1057*ee7230f4SAlexander Motin 			dsc->td.upper.data |= E1000_TXD_STAT_DD;
1058*ee7230f4SAlexander Motin 			*tdwb = 1;
1059*ee7230f4SAlexander Motin 		}
1060*ee7230f4SAlexander Motin 	}
10619e749f25SAlexander Motin }
10629e749f25SAlexander Motin 
10639e749f25SAlexander Motin static int
10649e749f25SAlexander Motin e82545_transmit(struct e82545_softc *sc, uint16_t head, uint16_t tail,
10659e749f25SAlexander Motin     uint16_t dsize, uint16_t *rhead, int *tdwb)
10669e749f25SAlexander Motin {
10679e749f25SAlexander Motin 	uint8_t *hdr, *hdrp;
10689e749f25SAlexander Motin 	struct iovec iovb[I82545_MAX_TXSEGS + 2];
10699e749f25SAlexander Motin 	struct iovec tiov[I82545_MAX_TXSEGS + 2];
10709e749f25SAlexander Motin 	struct e1000_context_desc *cd;
10719e749f25SAlexander Motin 	struct ck_info ckinfo[2];
10729e749f25SAlexander Motin 	struct iovec *iov;
10739e749f25SAlexander Motin 	union  e1000_tx_udesc *dsc;
1074*ee7230f4SAlexander Motin 	int desc, dtype, len, ntype, iovcnt, tlen, hdrlen, vlen, tcp, tso;
10759e749f25SAlexander Motin 	int mss, paylen, seg, tiovcnt, left, now, nleft, nnow, pv, pvoff;
10769e749f25SAlexander Motin 	uint32_t tcpsum, tcpseq;
1077*ee7230f4SAlexander Motin 	uint16_t ipcs, tcpcs, ipid, ohead;
10789e749f25SAlexander Motin 
10799e749f25SAlexander Motin 	ckinfo[0].ck_valid = ckinfo[1].ck_valid = 0;
10809e749f25SAlexander Motin 	iovcnt = 0;
10819e749f25SAlexander Motin 	tlen = 0;
10829e749f25SAlexander Motin 	ntype = 0;
10839e749f25SAlexander Motin 	tso = 0;
1084*ee7230f4SAlexander Motin 	ohead = head;
10859e749f25SAlexander Motin 
10869e749f25SAlexander Motin 	/* iovb[0/1] may be used for writable copy of headers. */
10879e749f25SAlexander Motin 	iov = &iovb[2];
10889e749f25SAlexander Motin 
10899e749f25SAlexander Motin 	for (desc = 0; ; desc++, head = (head + 1) % dsize) {
10909e749f25SAlexander Motin 		if (head == tail) {
10919e749f25SAlexander Motin 			*rhead = head;
10929e749f25SAlexander Motin 			return (0);
10939e749f25SAlexander Motin 		}
10949e749f25SAlexander Motin 		dsc = &sc->esc_txdesc[head];
10959e749f25SAlexander Motin 		dtype = e82545_txdesc_type(dsc->td.lower.data);
10969e749f25SAlexander Motin 
10979e749f25SAlexander Motin 		if (desc == 0) {
10989e749f25SAlexander Motin 			switch (dtype) {
10999e749f25SAlexander Motin 			case E1000_TXD_TYP_C:
11009e749f25SAlexander Motin 				DPRINTF("tx ctxt desc idx %d: %016jx "
11019e749f25SAlexander Motin 				    "%08x%08x\r\n",
11029e749f25SAlexander Motin 				    head, dsc->td.buffer_addr,
11039e749f25SAlexander Motin 				    dsc->td.upper.data, dsc->td.lower.data);
11049e749f25SAlexander Motin 				/* Save context and return */
11059e749f25SAlexander Motin 				sc->esc_txctx = dsc->cd;
1106*ee7230f4SAlexander Motin 				goto done;
11079e749f25SAlexander Motin 			case E1000_TXD_TYP_L:
11089e749f25SAlexander Motin 				DPRINTF("tx legacy desc idx %d: %08x%08x\r\n",
11099e749f25SAlexander Motin 				    head, dsc->td.upper.data, dsc->td.lower.data);
11109e749f25SAlexander Motin 				/*
11119e749f25SAlexander Motin 				 * legacy cksum start valid in first descriptor
11129e749f25SAlexander Motin 				 */
11139e749f25SAlexander Motin 				ntype = dtype;
11149e749f25SAlexander Motin 				ckinfo[0].ck_start = dsc->td.upper.fields.css;
11159e749f25SAlexander Motin 				break;
11169e749f25SAlexander Motin 			case E1000_TXD_TYP_D:
11179e749f25SAlexander Motin 				DPRINTF("tx data desc idx %d: %08x%08x\r\n",
11189e749f25SAlexander Motin 				    head, dsc->td.upper.data, dsc->td.lower.data);
11199e749f25SAlexander Motin 				ntype = dtype;
11209e749f25SAlexander Motin 				break;
11219e749f25SAlexander Motin 			default:
11229e749f25SAlexander Motin 				break;
11239e749f25SAlexander Motin 			}
11249e749f25SAlexander Motin 		} else {
11259e749f25SAlexander Motin 			/* Descriptor type must be consistent */
11269e749f25SAlexander Motin 			assert(dtype == ntype);
11279e749f25SAlexander Motin 			DPRINTF("tx next desc idx %d: %08x%08x\r\n",
11289e749f25SAlexander Motin 			    head, dsc->td.upper.data, dsc->td.lower.data);
11299e749f25SAlexander Motin 		}
11309e749f25SAlexander Motin 
11319e749f25SAlexander Motin 		len = (dtype == E1000_TXD_TYP_L) ? dsc->td.lower.flags.length :
11329e749f25SAlexander Motin 		    dsc->dd.lower.data & 0xFFFFF;
11339e749f25SAlexander Motin 
11349e749f25SAlexander Motin 		if (len > 0) {
11359e749f25SAlexander Motin 			/* Strip checksum supplied by guest. */
11369e749f25SAlexander Motin 			if ((dsc->td.lower.data & E1000_TXD_CMD_EOP) != 0 &&
11379e749f25SAlexander Motin 			    (dsc->td.lower.data & E1000_TXD_CMD_IFCS) == 0)
11389e749f25SAlexander Motin 				len -= 2;
11399e749f25SAlexander Motin 			tlen += len;
1140*ee7230f4SAlexander Motin 			if (iovcnt < I82545_MAX_TXSEGS) {
1141*ee7230f4SAlexander Motin 				iov[iovcnt].iov_base = paddr_guest2host(
1142*ee7230f4SAlexander Motin 				    sc->esc_ctx, dsc->td.buffer_addr, len);
11439e749f25SAlexander Motin 				iov[iovcnt].iov_len = len;
1144*ee7230f4SAlexander Motin 			}
11459e749f25SAlexander Motin 			iovcnt++;
11469e749f25SAlexander Motin 		}
11479e749f25SAlexander Motin 
11489e749f25SAlexander Motin 		/*
11499e749f25SAlexander Motin 		 * Pull out info that is valid in the final descriptor
11509e749f25SAlexander Motin 		 * and exit descriptor loop.
11519e749f25SAlexander Motin 		 */
11529e749f25SAlexander Motin 		if (dsc->td.lower.data & E1000_TXD_CMD_EOP) {
11539e749f25SAlexander Motin 			if (dtype == E1000_TXD_TYP_L) {
11549e749f25SAlexander Motin 				if (dsc->td.lower.data & E1000_TXD_CMD_IC) {
11559e749f25SAlexander Motin 					ckinfo[0].ck_valid = 1;
11569e749f25SAlexander Motin 					ckinfo[0].ck_off =
11579e749f25SAlexander Motin 					    dsc->td.lower.flags.cso;
11589e749f25SAlexander Motin 					ckinfo[0].ck_len = 0;
11599e749f25SAlexander Motin 				}
11609e749f25SAlexander Motin 			} else {
11619e749f25SAlexander Motin 				cd = &sc->esc_txctx;
11629e749f25SAlexander Motin 				if (dsc->dd.lower.data & E1000_TXD_CMD_TSE)
11639e749f25SAlexander Motin 					tso = 1;
11649e749f25SAlexander Motin 				if (dsc->dd.upper.fields.popts &
11659e749f25SAlexander Motin 				    E1000_TXD_POPTS_IXSM)
11669e749f25SAlexander Motin 					ckinfo[0].ck_valid = 1;
11679e749f25SAlexander Motin 				if (dsc->dd.upper.fields.popts &
11689e749f25SAlexander Motin 				    E1000_TXD_POPTS_IXSM || tso) {
11699e749f25SAlexander Motin 					ckinfo[0].ck_start =
11709e749f25SAlexander Motin 					    cd->lower_setup.ip_fields.ipcss;
11719e749f25SAlexander Motin 					ckinfo[0].ck_off =
11729e749f25SAlexander Motin 					    cd->lower_setup.ip_fields.ipcso;
11739e749f25SAlexander Motin 					ckinfo[0].ck_len =
11749e749f25SAlexander Motin 					    cd->lower_setup.ip_fields.ipcse;
11759e749f25SAlexander Motin 				}
11769e749f25SAlexander Motin 				if (dsc->dd.upper.fields.popts &
11779e749f25SAlexander Motin 				    E1000_TXD_POPTS_TXSM)
11789e749f25SAlexander Motin 					ckinfo[1].ck_valid = 1;
11799e749f25SAlexander Motin 				if (dsc->dd.upper.fields.popts &
11809e749f25SAlexander Motin 				    E1000_TXD_POPTS_TXSM || tso) {
11819e749f25SAlexander Motin 					ckinfo[1].ck_start =
11829e749f25SAlexander Motin 					    cd->upper_setup.tcp_fields.tucss;
11839e749f25SAlexander Motin 					ckinfo[1].ck_off =
11849e749f25SAlexander Motin 					    cd->upper_setup.tcp_fields.tucso;
11859e749f25SAlexander Motin 					ckinfo[1].ck_len =
11869e749f25SAlexander Motin 					    cd->upper_setup.tcp_fields.tucse;
11879e749f25SAlexander Motin 				}
11889e749f25SAlexander Motin 			}
11899e749f25SAlexander Motin 			break;
11909e749f25SAlexander Motin 		}
11919e749f25SAlexander Motin 	}
11929e749f25SAlexander Motin 
1193*ee7230f4SAlexander Motin 	if (iovcnt > I82545_MAX_TXSEGS) {
1194*ee7230f4SAlexander Motin 		WPRINTF("tx too many descriptors (%d > %d) -- dropped\r\n",
1195*ee7230f4SAlexander Motin 		    iovcnt, I82545_MAX_TXSEGS);
1196*ee7230f4SAlexander Motin 		goto done;
1197*ee7230f4SAlexander Motin 	}
1198*ee7230f4SAlexander Motin 
11999e749f25SAlexander Motin 	hdrlen = vlen = 0;
12009e749f25SAlexander Motin 	/* Estimate writable space for VLAN header insertion. */
12019e749f25SAlexander Motin 	if ((sc->esc_CTRL & E1000_CTRL_VME) &&
12029e749f25SAlexander Motin 	    (dsc->td.lower.data & E1000_TXD_CMD_VLE)) {
12039e749f25SAlexander Motin 		hdrlen = ETHER_ADDR_LEN*2;
12049e749f25SAlexander Motin 		vlen = ETHER_VLAN_ENCAP_LEN;
12059e749f25SAlexander Motin 	}
12069e749f25SAlexander Motin 	if (!tso) {
12079e749f25SAlexander Motin 		/* Estimate required writable space for checksums. */
12089e749f25SAlexander Motin 		if (ckinfo[0].ck_valid)
12099e749f25SAlexander Motin 			hdrlen = MAX(hdrlen, ckinfo[0].ck_off + 2);
12109e749f25SAlexander Motin 		if (ckinfo[1].ck_valid)
12119e749f25SAlexander Motin 			hdrlen = MAX(hdrlen, ckinfo[1].ck_off + 2);
12129e749f25SAlexander Motin 		/* Round up writable space to the first vector. */
12139e749f25SAlexander Motin 		if (hdrlen != 0 && iov[0].iov_len > hdrlen &&
12149e749f25SAlexander Motin 		    iov[0].iov_len < hdrlen + 100)
12159e749f25SAlexander Motin 			hdrlen = iov[0].iov_len;
12169e749f25SAlexander Motin 	} else {
12179e749f25SAlexander Motin 		/* In case of TSO header length provided by software. */
12189e749f25SAlexander Motin 		hdrlen = sc->esc_txctx.tcp_seg_setup.fields.hdr_len;
12199e749f25SAlexander Motin 	}
12209e749f25SAlexander Motin 
12219e749f25SAlexander Motin 	/* Allocate, fill and prepend writable header vector. */
12229e749f25SAlexander Motin 	if (hdrlen != 0) {
12239e749f25SAlexander Motin 		hdr = __builtin_alloca(hdrlen + vlen);
12249e749f25SAlexander Motin 		hdr += vlen;
12259e749f25SAlexander Motin 		for (left = hdrlen, hdrp = hdr; left > 0;
12269e749f25SAlexander Motin 		    left -= now, hdrp += now) {
12279e749f25SAlexander Motin 			now = MIN(left, iov->iov_len);
12289e749f25SAlexander Motin 			memcpy(hdrp, iov->iov_base, now);
12299e749f25SAlexander Motin 			iov->iov_base += now;
12309e749f25SAlexander Motin 			iov->iov_len -= now;
12319e749f25SAlexander Motin 			if (iov->iov_len == 0) {
12329e749f25SAlexander Motin 				iov++;
12339e749f25SAlexander Motin 				iovcnt--;
12349e749f25SAlexander Motin 			}
12359e749f25SAlexander Motin 		}
12369e749f25SAlexander Motin 		iov--;
12379e749f25SAlexander Motin 		iovcnt++;
12389e749f25SAlexander Motin 		iov->iov_base = hdr;
12399e749f25SAlexander Motin 		iov->iov_len = hdrlen;
12409e749f25SAlexander Motin 	}
12419e749f25SAlexander Motin 
12429e749f25SAlexander Motin 	/* Insert VLAN tag. */
12439e749f25SAlexander Motin 	if (vlen != 0) {
12449e749f25SAlexander Motin 		hdr -= ETHER_VLAN_ENCAP_LEN;
12459e749f25SAlexander Motin 		memmove(hdr, hdr + ETHER_VLAN_ENCAP_LEN, ETHER_ADDR_LEN*2);
12469e749f25SAlexander Motin 		hdrlen += ETHER_VLAN_ENCAP_LEN;
12479e749f25SAlexander Motin 		hdr[ETHER_ADDR_LEN*2 + 0] = sc->esc_VET >> 8;
12489e749f25SAlexander Motin 		hdr[ETHER_ADDR_LEN*2 + 1] = sc->esc_VET & 0xff;
12499e749f25SAlexander Motin 		hdr[ETHER_ADDR_LEN*2 + 2] = dsc->td.upper.fields.special >> 8;
12509e749f25SAlexander Motin 		hdr[ETHER_ADDR_LEN*2 + 3] = dsc->td.upper.fields.special & 0xff;
12519e749f25SAlexander Motin 		iov->iov_base = hdr;
12529e749f25SAlexander Motin 		iov->iov_len += ETHER_VLAN_ENCAP_LEN;
12539e749f25SAlexander Motin 		/* Correct checksum offsets after VLAN tag insertion. */
12549e749f25SAlexander Motin 		ckinfo[0].ck_start += ETHER_VLAN_ENCAP_LEN;
12559e749f25SAlexander Motin 		ckinfo[0].ck_off += ETHER_VLAN_ENCAP_LEN;
12569e749f25SAlexander Motin 		if (ckinfo[0].ck_len != 0)
12579e749f25SAlexander Motin 			ckinfo[0].ck_len += ETHER_VLAN_ENCAP_LEN;
12589e749f25SAlexander Motin 		ckinfo[1].ck_start += ETHER_VLAN_ENCAP_LEN;
12599e749f25SAlexander Motin 		ckinfo[1].ck_off += ETHER_VLAN_ENCAP_LEN;
12609e749f25SAlexander Motin 		if (ckinfo[1].ck_len != 0)
12619e749f25SAlexander Motin 			ckinfo[1].ck_len += ETHER_VLAN_ENCAP_LEN;
12629e749f25SAlexander Motin 	}
12639e749f25SAlexander Motin 
12649e749f25SAlexander Motin 	/* Simple non-TSO case. */
12659e749f25SAlexander Motin 	if (!tso) {
12669e749f25SAlexander Motin 		/* Calculate checksums and transmit. */
12679e749f25SAlexander Motin 		if (ckinfo[0].ck_valid)
12689e749f25SAlexander Motin 			e82545_transmit_checksum(iov, iovcnt, &ckinfo[0]);
12699e749f25SAlexander Motin 		if (ckinfo[1].ck_valid)
12709e749f25SAlexander Motin 			e82545_transmit_checksum(iov, iovcnt, &ckinfo[1]);
12719e749f25SAlexander Motin 		e82545_transmit_backend(sc, iov, iovcnt);
12729e749f25SAlexander Motin 		goto done;
12739e749f25SAlexander Motin 	}
12749e749f25SAlexander Motin 
12759e749f25SAlexander Motin 	/* Doing TSO. */
12769e749f25SAlexander Motin 	tcp = (sc->esc_txctx.cmd_and_length & E1000_TXD_CMD_TCP) != 0;
12779e749f25SAlexander Motin 	mss = sc->esc_txctx.tcp_seg_setup.fields.mss;
12789e749f25SAlexander Motin 	paylen = (sc->esc_txctx.cmd_and_length & 0x000fffff);
12799e749f25SAlexander Motin 	DPRINTF("tx %s segmentation offload %d+%d/%d bytes %d iovs\r\n",
12809e749f25SAlexander Motin 	    tcp ? "TCP" : "UDP", hdrlen, paylen, mss, iovcnt);
12819e749f25SAlexander Motin 	ipid = ntohs(*(uint16_t *)&hdr[ckinfo[0].ck_start + 4]);
12829e749f25SAlexander Motin 	tcpseq = ntohl(*(uint32_t *)&hdr[ckinfo[1].ck_start + 4]);
12839e749f25SAlexander Motin 	ipcs = *(uint16_t *)&hdr[ckinfo[0].ck_off];
12849e749f25SAlexander Motin 	tcpcs = 0;
12859e749f25SAlexander Motin 	if (ckinfo[1].ck_valid)	/* Save partial pseudo-header checksum. */
12869e749f25SAlexander Motin 		tcpcs = *(uint16_t *)&hdr[ckinfo[1].ck_off];
12879e749f25SAlexander Motin 	pv = 1;
12889e749f25SAlexander Motin 	pvoff = 0;
12899e749f25SAlexander Motin 	for (seg = 0, left = paylen; left > 0; seg++, left -= now) {
12909e749f25SAlexander Motin 		now = MIN(left, mss);
12919e749f25SAlexander Motin 
12929e749f25SAlexander Motin 		/* Construct IOVs for the segment. */
12939e749f25SAlexander Motin 		/* Include whole original header. */
12949e749f25SAlexander Motin 		tiov[0].iov_base = hdr;
12959e749f25SAlexander Motin 		tiov[0].iov_len = hdrlen;
12969e749f25SAlexander Motin 		tiovcnt = 1;
12979e749f25SAlexander Motin 		/* Include respective part of payload IOV. */
12989e749f25SAlexander Motin 		for (nleft = now; pv < iovcnt && nleft > 0; nleft -= nnow) {
12999e749f25SAlexander Motin 			nnow = MIN(nleft, iov[pv].iov_len - pvoff);
13009e749f25SAlexander Motin 			tiov[tiovcnt].iov_base = iov[pv].iov_base + pvoff;
13019e749f25SAlexander Motin 			tiov[tiovcnt++].iov_len = nnow;
13029e749f25SAlexander Motin 			if (pvoff + nnow == iov[pv].iov_len) {
13039e749f25SAlexander Motin 				pv++;
13049e749f25SAlexander Motin 				pvoff = 0;
13059e749f25SAlexander Motin 			} else
13069e749f25SAlexander Motin 				pvoff += nnow;
13079e749f25SAlexander Motin 		}
13089e749f25SAlexander Motin 		DPRINTF("tx segment %d %d+%d bytes %d iovs\r\n",
13099e749f25SAlexander Motin 		    seg, hdrlen, now, tiovcnt);
13109e749f25SAlexander Motin 
13119e749f25SAlexander Motin 		/* Update IP header. */
13129e749f25SAlexander Motin 		if (sc->esc_txctx.cmd_and_length & E1000_TXD_CMD_IP) {
13139e749f25SAlexander Motin 			/* IPv4 -- set length and ID */
13149e749f25SAlexander Motin 			*(uint16_t *)&hdr[ckinfo[0].ck_start + 2] =
13159e749f25SAlexander Motin 			    htons(hdrlen - ckinfo[0].ck_start + now);
13169e749f25SAlexander Motin 			*(uint16_t *)&hdr[ckinfo[0].ck_start + 4] =
13179e749f25SAlexander Motin 			    htons(ipid + seg);
13189e749f25SAlexander Motin 		} else {
13199e749f25SAlexander Motin 			/* IPv6 -- set length */
13209e749f25SAlexander Motin 			*(uint16_t *)&hdr[ckinfo[0].ck_start + 4] =
13219e749f25SAlexander Motin 			    htons(hdrlen - ckinfo[0].ck_start - 40 +
13229e749f25SAlexander Motin 				  now);
13239e749f25SAlexander Motin 		}
13249e749f25SAlexander Motin 
13259e749f25SAlexander Motin 		/* Update pseudo-header checksum. */
13269e749f25SAlexander Motin 		tcpsum = tcpcs;
13279e749f25SAlexander Motin 		tcpsum += htons(hdrlen - ckinfo[1].ck_start + now);
13289e749f25SAlexander Motin 
13299e749f25SAlexander Motin 		/* Update TCP/UDP headers. */
13309e749f25SAlexander Motin 		if (tcp) {
13319e749f25SAlexander Motin 			/* Update sequence number and FIN/PUSH flags. */
13329e749f25SAlexander Motin 			*(uint32_t *)&hdr[ckinfo[1].ck_start + 4] =
13339e749f25SAlexander Motin 			    htonl(tcpseq + paylen - left);
13349e749f25SAlexander Motin 			if (now < left) {
13359e749f25SAlexander Motin 				hdr[ckinfo[1].ck_start + 13] &=
13369e749f25SAlexander Motin 				    ~(TH_FIN | TH_PUSH);
13379e749f25SAlexander Motin 			}
13389e749f25SAlexander Motin 		} else {
13399e749f25SAlexander Motin 			/* Update payload length. */
13409e749f25SAlexander Motin 			*(uint32_t *)&hdr[ckinfo[1].ck_start + 4] =
13419e749f25SAlexander Motin 			    hdrlen - ckinfo[1].ck_start + now;
13429e749f25SAlexander Motin 		}
13439e749f25SAlexander Motin 
13449e749f25SAlexander Motin 		/* Calculate checksums and transmit. */
13459e749f25SAlexander Motin 		if (ckinfo[0].ck_valid) {
13469e749f25SAlexander Motin 			*(uint16_t *)&hdr[ckinfo[0].ck_off] = ipcs;
13479e749f25SAlexander Motin 			e82545_transmit_checksum(tiov, tiovcnt, &ckinfo[0]);
13489e749f25SAlexander Motin 		}
13499e749f25SAlexander Motin 		if (ckinfo[1].ck_valid) {
13509e749f25SAlexander Motin 			*(uint16_t *)&hdr[ckinfo[1].ck_off] =
13519e749f25SAlexander Motin 			    e82545_carry(tcpsum);
13529e749f25SAlexander Motin 			e82545_transmit_checksum(tiov, tiovcnt, &ckinfo[1]);
13539e749f25SAlexander Motin 		}
13549e749f25SAlexander Motin 		e82545_transmit_backend(sc, tiov, tiovcnt);
13559e749f25SAlexander Motin 	}
13569e749f25SAlexander Motin 
13579e749f25SAlexander Motin done:
1358*ee7230f4SAlexander Motin 	head = (head + 1) % dsize;
1359*ee7230f4SAlexander Motin 	e82545_transmit_done(sc, ohead, head, dsize, tdwb);
13609e749f25SAlexander Motin 
1361*ee7230f4SAlexander Motin 	*rhead = head;
13629e749f25SAlexander Motin 	return (desc + 1);
13639e749f25SAlexander Motin }
13649e749f25SAlexander Motin 
13659e749f25SAlexander Motin static void
13669e749f25SAlexander Motin e82545_tx_run(struct e82545_softc *sc)
13679e749f25SAlexander Motin {
13689e749f25SAlexander Motin 	uint32_t cause;
13699e749f25SAlexander Motin 	uint16_t head, rhead, tail, size;
13709e749f25SAlexander Motin 	int lim, tdwb, sent;
13719e749f25SAlexander Motin 
13729e749f25SAlexander Motin 	head = sc->esc_TDH;
13739e749f25SAlexander Motin 	tail = sc->esc_TDT;
13749e749f25SAlexander Motin 	size = sc->esc_TDLEN / 16;
13759e749f25SAlexander Motin 	DPRINTF("tx_run: head %x, rhead %x, tail %x\r\n",
13769e749f25SAlexander Motin 	    sc->esc_TDH, sc->esc_TDHr, sc->esc_TDT);
13779e749f25SAlexander Motin 
13789e749f25SAlexander Motin 	pthread_mutex_unlock(&sc->esc_mtx);
13799e749f25SAlexander Motin 	rhead = head;
13809e749f25SAlexander Motin 	tdwb = 0;
13819e749f25SAlexander Motin 	for (lim = size / 4; sc->esc_tx_enabled && lim > 0; lim -= sent) {
13829e749f25SAlexander Motin 		sent = e82545_transmit(sc, head, tail, size, &rhead, &tdwb);
13839e749f25SAlexander Motin 		if (sent == 0)
13849e749f25SAlexander Motin 			break;
13859e749f25SAlexander Motin 		head = rhead;
13869e749f25SAlexander Motin 	}
13879e749f25SAlexander Motin 	pthread_mutex_lock(&sc->esc_mtx);
13889e749f25SAlexander Motin 
13899e749f25SAlexander Motin 	sc->esc_TDH = head;
13909e749f25SAlexander Motin 	sc->esc_TDHr = rhead;
13919e749f25SAlexander Motin 	cause = 0;
13929e749f25SAlexander Motin 	if (tdwb)
13939e749f25SAlexander Motin 		cause |= E1000_ICR_TXDW;
13949e749f25SAlexander Motin 	if (lim != size / 4 && sc->esc_TDH == sc->esc_TDT)
13959e749f25SAlexander Motin 		cause |= E1000_ICR_TXQE;
13969e749f25SAlexander Motin 	if (cause)
13979e749f25SAlexander Motin 		e82545_icr_assert(sc, cause);
13989e749f25SAlexander Motin 
13999e749f25SAlexander Motin 	DPRINTF("tx_run done: head %x, rhead %x, tail %x\r\n",
14009e749f25SAlexander Motin 	    sc->esc_TDH, sc->esc_TDHr, sc->esc_TDT);
14019e749f25SAlexander Motin }
14029e749f25SAlexander Motin 
14039e749f25SAlexander Motin static void *
14049e749f25SAlexander Motin e82545_tx_thread(void *param)
14059e749f25SAlexander Motin {
14069e749f25SAlexander Motin 	struct e82545_softc *sc = param;
14079e749f25SAlexander Motin 
14089e749f25SAlexander Motin 	pthread_mutex_lock(&sc->esc_mtx);
14099e749f25SAlexander Motin 	for (;;) {
14109e749f25SAlexander Motin 		while (!sc->esc_tx_enabled || sc->esc_TDHr == sc->esc_TDT) {
14119e749f25SAlexander Motin 			if (sc->esc_tx_enabled && sc->esc_TDHr != sc->esc_TDT)
14129e749f25SAlexander Motin 				break;
14139e749f25SAlexander Motin 			sc->esc_tx_active = 0;
14149e749f25SAlexander Motin 			if (sc->esc_tx_enabled == 0)
14159e749f25SAlexander Motin 				pthread_cond_signal(&sc->esc_tx_cond);
14169e749f25SAlexander Motin 			pthread_cond_wait(&sc->esc_tx_cond, &sc->esc_mtx);
14179e749f25SAlexander Motin 		}
14189e749f25SAlexander Motin 		sc->esc_tx_active = 1;
14199e749f25SAlexander Motin 
14209e749f25SAlexander Motin 		/* Process some tx descriptors.  Lock dropped inside. */
14219e749f25SAlexander Motin 		e82545_tx_run(sc);
14229e749f25SAlexander Motin 	}
14239e749f25SAlexander Motin }
14249e749f25SAlexander Motin 
14259e749f25SAlexander Motin static void
14269e749f25SAlexander Motin e82545_tx_start(struct e82545_softc *sc)
14279e749f25SAlexander Motin {
14289e749f25SAlexander Motin 
14299e749f25SAlexander Motin 	if (sc->esc_tx_active == 0)
14309e749f25SAlexander Motin 		pthread_cond_signal(&sc->esc_tx_cond);
14319e749f25SAlexander Motin }
14329e749f25SAlexander Motin 
14339e749f25SAlexander Motin static void
14349e749f25SAlexander Motin e82545_tx_enable(struct e82545_softc *sc)
14359e749f25SAlexander Motin {
14369e749f25SAlexander Motin 
14379e749f25SAlexander Motin 	sc->esc_tx_enabled = 1;
14389e749f25SAlexander Motin }
14399e749f25SAlexander Motin 
14409e749f25SAlexander Motin static void
14419e749f25SAlexander Motin e82545_tx_disable(struct e82545_softc *sc)
14429e749f25SAlexander Motin {
14439e749f25SAlexander Motin 
14449e749f25SAlexander Motin 	sc->esc_tx_enabled = 0;
14459e749f25SAlexander Motin 	while (sc->esc_tx_active)
14469e749f25SAlexander Motin 		pthread_cond_wait(&sc->esc_tx_cond, &sc->esc_mtx);
14479e749f25SAlexander Motin }
14489e749f25SAlexander Motin 
14499e749f25SAlexander Motin static void
14509e749f25SAlexander Motin e82545_rx_enable(struct e82545_softc *sc)
14519e749f25SAlexander Motin {
14529e749f25SAlexander Motin 
14539e749f25SAlexander Motin 	sc->esc_rx_enabled = 1;
14549e749f25SAlexander Motin }
14559e749f25SAlexander Motin 
14569e749f25SAlexander Motin static void
14579e749f25SAlexander Motin e82545_rx_disable(struct e82545_softc *sc)
14589e749f25SAlexander Motin {
14599e749f25SAlexander Motin 
14609e749f25SAlexander Motin 	sc->esc_rx_enabled = 0;
14619e749f25SAlexander Motin 	while (sc->esc_rx_active)
14629e749f25SAlexander Motin 		pthread_cond_wait(&sc->esc_rx_cond, &sc->esc_mtx);
14639e749f25SAlexander Motin }
14649e749f25SAlexander Motin 
14659e749f25SAlexander Motin static void
14669e749f25SAlexander Motin e82545_write_ra(struct e82545_softc *sc, int reg, uint32_t wval)
14679e749f25SAlexander Motin {
14689e749f25SAlexander Motin         struct eth_uni *eu;
14699e749f25SAlexander Motin 	int idx;
14709e749f25SAlexander Motin 
14719e749f25SAlexander Motin 	idx = reg >> 1;
14729e749f25SAlexander Motin 	assert(idx < 15);
14739e749f25SAlexander Motin 
14749e749f25SAlexander Motin 	eu = &sc->esc_uni[idx];
14759e749f25SAlexander Motin 
14769e749f25SAlexander Motin 	if (reg & 0x1) {
14779e749f25SAlexander Motin 		/* RAH */
14789e749f25SAlexander Motin 		eu->eu_valid = ((wval & E1000_RAH_AV) == E1000_RAH_AV);
14799e749f25SAlexander Motin 		eu->eu_addrsel = (wval >> 16) & 0x3;
14809e749f25SAlexander Motin 		eu->eu_eth.octet[5] = wval >> 8;
14819e749f25SAlexander Motin 		eu->eu_eth.octet[4] = wval;
14829e749f25SAlexander Motin 	} else {
14839e749f25SAlexander Motin 		/* RAL */
14849e749f25SAlexander Motin 		eu->eu_eth.octet[3] = wval >> 24;
14859e749f25SAlexander Motin 		eu->eu_eth.octet[2] = wval >> 16;
14869e749f25SAlexander Motin 		eu->eu_eth.octet[1] = wval >> 8;
14879e749f25SAlexander Motin 		eu->eu_eth.octet[0] = wval;
14889e749f25SAlexander Motin 	}
14899e749f25SAlexander Motin }
14909e749f25SAlexander Motin 
14919e749f25SAlexander Motin static uint32_t
14929e749f25SAlexander Motin e82545_read_ra(struct e82545_softc *sc, int reg)
14939e749f25SAlexander Motin {
14949e749f25SAlexander Motin         struct eth_uni *eu;
14959e749f25SAlexander Motin 	uint32_t retval;
14969e749f25SAlexander Motin 	int idx;
14979e749f25SAlexander Motin 
14989e749f25SAlexander Motin 	idx = reg >> 1;
14999e749f25SAlexander Motin 	assert(idx < 15);
15009e749f25SAlexander Motin 
15019e749f25SAlexander Motin 	eu = &sc->esc_uni[idx];
15029e749f25SAlexander Motin 
15039e749f25SAlexander Motin 	if (reg & 0x1) {
15049e749f25SAlexander Motin 		/* RAH */
15059e749f25SAlexander Motin 		retval = (eu->eu_valid << 31) |
15069e749f25SAlexander Motin 			 (eu->eu_addrsel << 16) |
15079e749f25SAlexander Motin 			 (eu->eu_eth.octet[5] << 8) |
15089e749f25SAlexander Motin 			 eu->eu_eth.octet[4];
15099e749f25SAlexander Motin 	} else {
15109e749f25SAlexander Motin 		/* RAL */
15119e749f25SAlexander Motin 		retval = (eu->eu_eth.octet[3] << 24) |
15129e749f25SAlexander Motin 			 (eu->eu_eth.octet[2] << 16) |
15139e749f25SAlexander Motin 			 (eu->eu_eth.octet[1] << 8) |
15149e749f25SAlexander Motin 			 eu->eu_eth.octet[0];
15159e749f25SAlexander Motin 	}
15169e749f25SAlexander Motin 
15179e749f25SAlexander Motin 	return (retval);
15189e749f25SAlexander Motin }
15199e749f25SAlexander Motin 
15209e749f25SAlexander Motin static void
15219e749f25SAlexander Motin e82545_write_register(struct e82545_softc *sc, uint32_t offset, uint32_t value)
15229e749f25SAlexander Motin {
15239e749f25SAlexander Motin 	int ridx;
15249e749f25SAlexander Motin 
15259e749f25SAlexander Motin 	if (offset & 0x3) {
15269e749f25SAlexander Motin 		DPRINTF("Unaligned register write offset:0x%x value:0x%x\r\n", offset, value);
15279e749f25SAlexander Motin 		return;
15289e749f25SAlexander Motin 	}
15299e749f25SAlexander Motin 	DPRINTF("Register write: 0x%x value: 0x%x\r\n", offset, value);
15309e749f25SAlexander Motin 
15319e749f25SAlexander Motin 	switch (offset) {
15329e749f25SAlexander Motin 	case E1000_CTRL:
15339e749f25SAlexander Motin 	case E1000_CTRL_DUP:
15349e749f25SAlexander Motin 		e82545_devctl(sc, value);
15359e749f25SAlexander Motin 		break;
15369e749f25SAlexander Motin 	case E1000_FCAL:
15379e749f25SAlexander Motin 		sc->esc_FCAL = value;
15389e749f25SAlexander Motin 		break;
15399e749f25SAlexander Motin 	case E1000_FCAH:
15409e749f25SAlexander Motin 		sc->esc_FCAH = value & ~0xFFFF0000;
15419e749f25SAlexander Motin 		break;
15429e749f25SAlexander Motin 	case E1000_FCT:
15439e749f25SAlexander Motin 		sc->esc_FCT = value & ~0xFFFF0000;
15449e749f25SAlexander Motin 		break;
15459e749f25SAlexander Motin 	case E1000_VET:
15469e749f25SAlexander Motin 		sc->esc_VET = value & ~0xFFFF0000;
15479e749f25SAlexander Motin 		break;
15489e749f25SAlexander Motin 	case E1000_FCTTV:
15499e749f25SAlexander Motin 		sc->esc_FCTTV = value & ~0xFFFF0000;
15509e749f25SAlexander Motin 		break;
15519e749f25SAlexander Motin 	case E1000_LEDCTL:
15529e749f25SAlexander Motin 		sc->esc_LEDCTL = value & ~0x30303000;
15539e749f25SAlexander Motin 		break;
15549e749f25SAlexander Motin 	case E1000_PBA:
15559e749f25SAlexander Motin 		sc->esc_PBA = value & 0x0000FF80;
15569e749f25SAlexander Motin 		break;
15579e749f25SAlexander Motin 	case E1000_ICR:
15589e749f25SAlexander Motin 	case E1000_ITR:
15599e749f25SAlexander Motin 	case E1000_ICS:
15609e749f25SAlexander Motin 	case E1000_IMS:
15619e749f25SAlexander Motin 	case E1000_IMC:
15629e749f25SAlexander Motin 		e82545_intr_write(sc, offset, value);
15639e749f25SAlexander Motin 		break;
15649e749f25SAlexander Motin 	case E1000_RCTL:
15659e749f25SAlexander Motin 		e82545_rx_ctl(sc, value);
15669e749f25SAlexander Motin 		break;
15679e749f25SAlexander Motin 	case E1000_FCRTL:
15689e749f25SAlexander Motin 		sc->esc_FCRTL = value & ~0xFFFF0007;
15699e749f25SAlexander Motin 		break;
15709e749f25SAlexander Motin 	case E1000_FCRTH:
15719e749f25SAlexander Motin 		sc->esc_FCRTH = value & ~0xFFFF0007;
15729e749f25SAlexander Motin 		break;
15739e749f25SAlexander Motin 	case E1000_RDBAL(0):
15749e749f25SAlexander Motin 		sc->esc_RDBAL = value & ~0xF;
15759e749f25SAlexander Motin 		if (sc->esc_rx_enabled) {
15769e749f25SAlexander Motin 			/* Apparently legal: update cached address */
15779e749f25SAlexander Motin 			e82545_rx_update_rdba(sc);
15789e749f25SAlexander Motin 		}
15799e749f25SAlexander Motin 		break;
15809e749f25SAlexander Motin 	case E1000_RDBAH(0):
15819e749f25SAlexander Motin 		assert(!sc->esc_rx_enabled);
15829e749f25SAlexander Motin 		sc->esc_RDBAH = value;
15839e749f25SAlexander Motin 		break;
15849e749f25SAlexander Motin 	case E1000_RDLEN(0):
15859e749f25SAlexander Motin 		assert(!sc->esc_rx_enabled);
15869e749f25SAlexander Motin 		sc->esc_RDLEN = value & ~0xFFF0007F;
15879e749f25SAlexander Motin 		break;
15889e749f25SAlexander Motin 	case E1000_RDH(0):
15899e749f25SAlexander Motin 		/* XXX should only ever be zero ? Range check ? */
15909e749f25SAlexander Motin 		sc->esc_RDH = value;
15919e749f25SAlexander Motin 		break;
15929e749f25SAlexander Motin 	case E1000_RDT(0):
15939e749f25SAlexander Motin 		/* XXX if this opens up the rx ring, do something ? */
15949e749f25SAlexander Motin 		sc->esc_RDT = value;
15959e749f25SAlexander Motin 		break;
15969e749f25SAlexander Motin 	case E1000_RDTR:
15979e749f25SAlexander Motin 		/* ignore FPD bit 31 */
15989e749f25SAlexander Motin 		sc->esc_RDTR = value & ~0xFFFF0000;
15999e749f25SAlexander Motin 		break;
16009e749f25SAlexander Motin 	case E1000_RXDCTL(0):
16019e749f25SAlexander Motin 		sc->esc_RXDCTL = value & ~0xFEC0C0C0;
16029e749f25SAlexander Motin 		break;
16039e749f25SAlexander Motin 	case E1000_RADV:
16049e749f25SAlexander Motin 		sc->esc_RADV = value & ~0xFFFF0000;
16059e749f25SAlexander Motin 		break;
16069e749f25SAlexander Motin 	case E1000_RSRPD:
16079e749f25SAlexander Motin 		sc->esc_RSRPD = value & ~0xFFFFF000;
16089e749f25SAlexander Motin 		break;
16099e749f25SAlexander Motin 	case E1000_RXCSUM:
16109e749f25SAlexander Motin 		sc->esc_RXCSUM = value & ~0xFFFFF800;
16119e749f25SAlexander Motin 		break;
16129e749f25SAlexander Motin 	case E1000_TXCW:
16139e749f25SAlexander Motin 		sc->esc_TXCW = value & ~0x3FFF0000;
16149e749f25SAlexander Motin 		break;
16159e749f25SAlexander Motin 	case E1000_TCTL:
16169e749f25SAlexander Motin 		e82545_tx_ctl(sc, value);
16179e749f25SAlexander Motin 		break;
16189e749f25SAlexander Motin 	case E1000_TIPG:
16199e749f25SAlexander Motin 		sc->esc_TIPG = value;
16209e749f25SAlexander Motin 		break;
16219e749f25SAlexander Motin 	case E1000_AIT:
16229e749f25SAlexander Motin 		sc->esc_AIT = value;
16239e749f25SAlexander Motin 		break;
16249e749f25SAlexander Motin 	case E1000_TDBAL(0):
16259e749f25SAlexander Motin 		sc->esc_TDBAL = value & ~0xF;
16269e749f25SAlexander Motin 		if (sc->esc_tx_enabled) {
16279e749f25SAlexander Motin 			/* Apparently legal */
16289e749f25SAlexander Motin 			e82545_tx_update_tdba(sc);
16299e749f25SAlexander Motin 		}
16309e749f25SAlexander Motin 		break;
16319e749f25SAlexander Motin 	case E1000_TDBAH(0):
16329e749f25SAlexander Motin 		//assert(!sc->esc_tx_enabled);
16339e749f25SAlexander Motin 		sc->esc_TDBAH = value;
16349e749f25SAlexander Motin 		break;
16359e749f25SAlexander Motin 	case E1000_TDLEN(0):
16369e749f25SAlexander Motin 		//assert(!sc->esc_tx_enabled);
16379e749f25SAlexander Motin 		sc->esc_TDLEN = value & ~0xFFF0007F;
16389e749f25SAlexander Motin 		break;
16399e749f25SAlexander Motin 	case E1000_TDH(0):
16409e749f25SAlexander Motin 		//assert(!sc->esc_tx_enabled);
16419e749f25SAlexander Motin 		/* XXX should only ever be zero ? Range check ? */
16429e749f25SAlexander Motin 		sc->esc_TDHr = sc->esc_TDH = value;
16439e749f25SAlexander Motin 		break;
16449e749f25SAlexander Motin 	case E1000_TDT(0):
16459e749f25SAlexander Motin 		/* XXX range check ? */
16469e749f25SAlexander Motin 		sc->esc_TDT = value;
16479e749f25SAlexander Motin 		if (sc->esc_tx_enabled)
16489e749f25SAlexander Motin 			e82545_tx_start(sc);
16499e749f25SAlexander Motin 		break;
16509e749f25SAlexander Motin 	case E1000_TIDV:
16519e749f25SAlexander Motin 		sc->esc_TIDV = value & ~0xFFFF0000;
16529e749f25SAlexander Motin 		break;
16539e749f25SAlexander Motin 	case E1000_TXDCTL(0):
16549e749f25SAlexander Motin 		//assert(!sc->esc_tx_enabled);
16559e749f25SAlexander Motin 		sc->esc_TXDCTL = value & ~0xC0C0C0;
16569e749f25SAlexander Motin 		break;
16579e749f25SAlexander Motin 	case E1000_TADV:
16589e749f25SAlexander Motin 		sc->esc_TADV = value & ~0xFFFF0000;
16599e749f25SAlexander Motin 		break;
16609e749f25SAlexander Motin 	case E1000_RAL(0) ... E1000_RAH(15):
16619e749f25SAlexander Motin 		/* convert to u32 offset */
16629e749f25SAlexander Motin 		ridx = (offset - E1000_RAL(0)) >> 2;
16639e749f25SAlexander Motin 		e82545_write_ra(sc, ridx, value);
16649e749f25SAlexander Motin 		break;
16659e749f25SAlexander Motin 	case E1000_MTA ... (E1000_MTA + (127*4)):
16669e749f25SAlexander Motin 		sc->esc_fmcast[(offset - E1000_MTA) >> 2] = value;
16679e749f25SAlexander Motin 		break;
16689e749f25SAlexander Motin 	case E1000_VFTA ... (E1000_VFTA + (127*4)):
16699e749f25SAlexander Motin 		sc->esc_fvlan[(offset - E1000_VFTA) >> 2] = value;
16709e749f25SAlexander Motin 		break;
16719e749f25SAlexander Motin 	case E1000_EECD:
16729e749f25SAlexander Motin 	{
16739e749f25SAlexander Motin 		//DPRINTF("EECD write 0x%x -> 0x%x\r\n", sc->eeprom_control, value);
16749e749f25SAlexander Motin 		/* edge triggered low->high */
16759e749f25SAlexander Motin 		uint32_t eecd_strobe = ((sc->eeprom_control & E1000_EECD_SK) ?
16769e749f25SAlexander Motin 			0 : (value & E1000_EECD_SK));
16779e749f25SAlexander Motin 		uint32_t eecd_mask = (E1000_EECD_SK|E1000_EECD_CS|
16789e749f25SAlexander Motin 					E1000_EECD_DI|E1000_EECD_REQ);
16799e749f25SAlexander Motin 		sc->eeprom_control &= ~eecd_mask;
16809e749f25SAlexander Motin 		sc->eeprom_control |= (value & eecd_mask);
16819e749f25SAlexander Motin 		/* grant/revoke immediately */
16829e749f25SAlexander Motin 		if (value & E1000_EECD_REQ) {
16839e749f25SAlexander Motin 			sc->eeprom_control |= E1000_EECD_GNT;
16849e749f25SAlexander Motin 		} else {
16859e749f25SAlexander Motin                         sc->eeprom_control &= ~E1000_EECD_GNT;
16869e749f25SAlexander Motin 		}
16879e749f25SAlexander Motin 		if (eecd_strobe && (sc->eeprom_control & E1000_EECD_CS)) {
16889e749f25SAlexander Motin 			e82545_eecd_strobe(sc);
16899e749f25SAlexander Motin 		}
16909e749f25SAlexander Motin 		return;
16919e749f25SAlexander Motin 	}
16929e749f25SAlexander Motin 	case E1000_MDIC:
16939e749f25SAlexander Motin 	{
16949e749f25SAlexander Motin 		uint8_t reg_addr = (uint8_t)((value & E1000_MDIC_REG_MASK) >>
16959e749f25SAlexander Motin 						E1000_MDIC_REG_SHIFT);
16969e749f25SAlexander Motin 		uint8_t phy_addr = (uint8_t)((value & E1000_MDIC_PHY_MASK) >>
16979e749f25SAlexander Motin 						E1000_MDIC_PHY_SHIFT);
16989e749f25SAlexander Motin 		sc->mdi_control =
16999e749f25SAlexander Motin 			(value & ~(E1000_MDIC_ERROR|E1000_MDIC_DEST));
17009e749f25SAlexander Motin 		if ((value & E1000_MDIC_READY) != 0) {
17019e749f25SAlexander Motin 			DPRINTF("Incorrect MDIC ready bit: 0x%x\r\n", value);
17029e749f25SAlexander Motin 			return;
17039e749f25SAlexander Motin 		}
17049e749f25SAlexander Motin 		switch (value & E82545_MDIC_OP_MASK) {
17059e749f25SAlexander Motin 		case E1000_MDIC_OP_READ:
17069e749f25SAlexander Motin 			sc->mdi_control &= ~E82545_MDIC_DATA_MASK;
17079e749f25SAlexander Motin 			sc->mdi_control |= e82545_read_mdi(sc, reg_addr, phy_addr);
17089e749f25SAlexander Motin 			break;
17099e749f25SAlexander Motin 		case E1000_MDIC_OP_WRITE:
17109e749f25SAlexander Motin 			e82545_write_mdi(sc, reg_addr, phy_addr,
17119e749f25SAlexander Motin 				value & E82545_MDIC_DATA_MASK);
17129e749f25SAlexander Motin 			break;
17139e749f25SAlexander Motin 		default:
17149e749f25SAlexander Motin 			DPRINTF("Unknown MDIC op: 0x%x\r\n", value);
17159e749f25SAlexander Motin 			return;
17169e749f25SAlexander Motin 		}
17179e749f25SAlexander Motin 		/* TODO: barrier? */
17189e749f25SAlexander Motin 		sc->mdi_control |= E1000_MDIC_READY;
17199e749f25SAlexander Motin 		if (value & E82545_MDIC_IE) {
17209e749f25SAlexander Motin 			// TODO: generate interrupt
17219e749f25SAlexander Motin 		}
17229e749f25SAlexander Motin 		return;
17239e749f25SAlexander Motin 	}
17249e749f25SAlexander Motin 	case E1000_MANC:
17259e749f25SAlexander Motin 	case E1000_STATUS:
17269e749f25SAlexander Motin 		return;
17279e749f25SAlexander Motin 	default:
17289e749f25SAlexander Motin 		DPRINTF("Unknown write register: 0x%x value:%x\r\n", offset, value);
17299e749f25SAlexander Motin 		return;
17309e749f25SAlexander Motin 	}
17319e749f25SAlexander Motin }
17329e749f25SAlexander Motin 
17339e749f25SAlexander Motin static uint32_t
17349e749f25SAlexander Motin e82545_read_register(struct e82545_softc *sc, uint32_t offset)
17359e749f25SAlexander Motin {
17369e749f25SAlexander Motin 	uint32_t retval;
17379e749f25SAlexander Motin 	int ridx;
17389e749f25SAlexander Motin 
17399e749f25SAlexander Motin 	if (offset & 0x3) {
17409e749f25SAlexander Motin 		DPRINTF("Unaligned register read offset:0x%x\r\n", offset);
17419e749f25SAlexander Motin 		return 0;
17429e749f25SAlexander Motin 	}
17439e749f25SAlexander Motin 
17449e749f25SAlexander Motin 	DPRINTF("Register read: 0x%x\r\n", offset);
17459e749f25SAlexander Motin 
17469e749f25SAlexander Motin 	switch (offset) {
17479e749f25SAlexander Motin 	case E1000_CTRL:
17489e749f25SAlexander Motin 		retval = sc->esc_CTRL;
17499e749f25SAlexander Motin 		break;
17509e749f25SAlexander Motin 	case E1000_STATUS:
17519e749f25SAlexander Motin 		retval = E1000_STATUS_FD | E1000_STATUS_LU |
17529e749f25SAlexander Motin 		    E1000_STATUS_SPEED_1000;
17539e749f25SAlexander Motin 		break;
17549e749f25SAlexander Motin 	case E1000_FCAL:
17559e749f25SAlexander Motin 		retval = sc->esc_FCAL;
17569e749f25SAlexander Motin 		break;
17579e749f25SAlexander Motin 	case E1000_FCAH:
17589e749f25SAlexander Motin 		retval = sc->esc_FCAH;
17599e749f25SAlexander Motin 		break;
17609e749f25SAlexander Motin 	case E1000_FCT:
17619e749f25SAlexander Motin 		retval = sc->esc_FCT;
17629e749f25SAlexander Motin 		break;
17639e749f25SAlexander Motin 	case E1000_VET:
17649e749f25SAlexander Motin 		retval = sc->esc_VET;
17659e749f25SAlexander Motin 		break;
17669e749f25SAlexander Motin 	case E1000_FCTTV:
17679e749f25SAlexander Motin 		retval = sc->esc_FCTTV;
17689e749f25SAlexander Motin 		break;
17699e749f25SAlexander Motin 	case E1000_LEDCTL:
17709e749f25SAlexander Motin 		retval = sc->esc_LEDCTL;
17719e749f25SAlexander Motin 		break;
17729e749f25SAlexander Motin 	case E1000_PBA:
17739e749f25SAlexander Motin 		retval = sc->esc_PBA;
17749e749f25SAlexander Motin 		break;
17759e749f25SAlexander Motin 	case E1000_ICR:
17769e749f25SAlexander Motin 	case E1000_ITR:
17779e749f25SAlexander Motin 	case E1000_ICS:
17789e749f25SAlexander Motin 	case E1000_IMS:
17799e749f25SAlexander Motin 	case E1000_IMC:
17809e749f25SAlexander Motin 		retval = e82545_intr_read(sc, offset);
17819e749f25SAlexander Motin 		break;
17829e749f25SAlexander Motin 	case E1000_RCTL:
17839e749f25SAlexander Motin 		retval = sc->esc_RCTL;
17849e749f25SAlexander Motin 		break;
17859e749f25SAlexander Motin 	case E1000_FCRTL:
17869e749f25SAlexander Motin 		retval = sc->esc_FCRTL;
17879e749f25SAlexander Motin 		break;
17889e749f25SAlexander Motin 	case E1000_FCRTH:
17899e749f25SAlexander Motin 		retval = sc->esc_FCRTH;
17909e749f25SAlexander Motin 		break;
17919e749f25SAlexander Motin 	case E1000_RDBAL(0):
17929e749f25SAlexander Motin 		retval = sc->esc_RDBAL;
17939e749f25SAlexander Motin 		break;
17949e749f25SAlexander Motin 	case E1000_RDBAH(0):
17959e749f25SAlexander Motin 		retval = sc->esc_RDBAH;
17969e749f25SAlexander Motin 		break;
17979e749f25SAlexander Motin 	case E1000_RDLEN(0):
17989e749f25SAlexander Motin 		retval = sc->esc_RDLEN;
17999e749f25SAlexander Motin 		break;
18009e749f25SAlexander Motin 	case E1000_RDH(0):
18019e749f25SAlexander Motin 		retval = sc->esc_RDH;
18029e749f25SAlexander Motin 		break;
18039e749f25SAlexander Motin 	case E1000_RDT(0):
18049e749f25SAlexander Motin 		retval = sc->esc_RDT;
18059e749f25SAlexander Motin 		break;
18069e749f25SAlexander Motin 	case E1000_RDTR:
18079e749f25SAlexander Motin 		retval = sc->esc_RDTR;
18089e749f25SAlexander Motin 		break;
18099e749f25SAlexander Motin 	case E1000_RXDCTL(0):
18109e749f25SAlexander Motin 		retval = sc->esc_RXDCTL;
18119e749f25SAlexander Motin 		break;
18129e749f25SAlexander Motin 	case E1000_RADV:
18139e749f25SAlexander Motin 		retval = sc->esc_RADV;
18149e749f25SAlexander Motin 		break;
18159e749f25SAlexander Motin 	case E1000_RSRPD:
18169e749f25SAlexander Motin 		retval = sc->esc_RSRPD;
18179e749f25SAlexander Motin 		break;
18189e749f25SAlexander Motin 	case E1000_RXCSUM:
18199e749f25SAlexander Motin 		retval = sc->esc_RXCSUM;
18209e749f25SAlexander Motin 		break;
18219e749f25SAlexander Motin 	case E1000_TXCW:
18229e749f25SAlexander Motin 		retval = sc->esc_TXCW;
18239e749f25SAlexander Motin 		break;
18249e749f25SAlexander Motin 	case E1000_TCTL:
18259e749f25SAlexander Motin 		retval = sc->esc_TCTL;
18269e749f25SAlexander Motin 		break;
18279e749f25SAlexander Motin 	case E1000_TIPG:
18289e749f25SAlexander Motin 		retval = sc->esc_TIPG;
18299e749f25SAlexander Motin 		break;
18309e749f25SAlexander Motin 	case E1000_AIT:
18319e749f25SAlexander Motin 		retval = sc->esc_AIT;
18329e749f25SAlexander Motin 		break;
18339e749f25SAlexander Motin 	case E1000_TDBAL(0):
18349e749f25SAlexander Motin 		retval = sc->esc_TDBAL;
18359e749f25SAlexander Motin 		break;
18369e749f25SAlexander Motin 	case E1000_TDBAH(0):
18379e749f25SAlexander Motin 		retval = sc->esc_TDBAH;
18389e749f25SAlexander Motin 		break;
18399e749f25SAlexander Motin 	case E1000_TDLEN(0):
18409e749f25SAlexander Motin 		retval = sc->esc_TDLEN;
18419e749f25SAlexander Motin 		break;
18429e749f25SAlexander Motin 	case E1000_TDH(0):
18439e749f25SAlexander Motin 		retval = sc->esc_TDH;
18449e749f25SAlexander Motin 		break;
18459e749f25SAlexander Motin 	case E1000_TDT(0):
18469e749f25SAlexander Motin 		retval = sc->esc_TDT;
18479e749f25SAlexander Motin 		break;
18489e749f25SAlexander Motin 	case E1000_TIDV:
18499e749f25SAlexander Motin 		retval = sc->esc_TIDV;
18509e749f25SAlexander Motin 		break;
18519e749f25SAlexander Motin 	case E1000_TXDCTL(0):
18529e749f25SAlexander Motin 		retval = sc->esc_TXDCTL;
18539e749f25SAlexander Motin 		break;
18549e749f25SAlexander Motin 	case E1000_TADV:
18559e749f25SAlexander Motin 		retval = sc->esc_TADV;
18569e749f25SAlexander Motin 		break;
18579e749f25SAlexander Motin 	case E1000_RAL(0) ... E1000_RAH(15):
18589e749f25SAlexander Motin 		/* convert to u32 offset */
18599e749f25SAlexander Motin 		ridx = (offset - E1000_RAL(0)) >> 2;
18609e749f25SAlexander Motin 		retval = e82545_read_ra(sc, ridx);
18619e749f25SAlexander Motin 		break;
18629e749f25SAlexander Motin 	case E1000_MTA ... (E1000_MTA + (127*4)):
18639e749f25SAlexander Motin 		retval = sc->esc_fmcast[(offset - E1000_MTA) >> 2];
18649e749f25SAlexander Motin 		break;
18659e749f25SAlexander Motin 	case E1000_VFTA ... (E1000_VFTA + (127*4)):
18669e749f25SAlexander Motin 		retval = sc->esc_fvlan[(offset - E1000_VFTA) >> 2];
18679e749f25SAlexander Motin 		break;
18689e749f25SAlexander Motin 	case E1000_EECD:
18699e749f25SAlexander Motin 		//DPRINTF("EECD read %x\r\n", sc->eeprom_control);
18709e749f25SAlexander Motin 		retval = sc->eeprom_control;
18719e749f25SAlexander Motin 		break;
18729e749f25SAlexander Motin 	case E1000_MDIC:
18739e749f25SAlexander Motin 		retval = sc->mdi_control;
18749e749f25SAlexander Motin 		break;
18759e749f25SAlexander Motin 	case E1000_MANC:
18769e749f25SAlexander Motin 		retval = 0;
18779e749f25SAlexander Motin 		break;
18789e749f25SAlexander Motin 	/* stats that we emulate. */
18799e749f25SAlexander Motin 	case E1000_MPC:
18809e749f25SAlexander Motin 		retval = sc->missed_pkt_count;
18819e749f25SAlexander Motin 		break;
18829e749f25SAlexander Motin 	case E1000_PRC64:
18839e749f25SAlexander Motin 		retval = sc->pkt_rx_by_size[0];
18849e749f25SAlexander Motin 		break;
18859e749f25SAlexander Motin 	case E1000_PRC127:
18869e749f25SAlexander Motin 		retval = sc->pkt_rx_by_size[1];
18879e749f25SAlexander Motin 		break;
18889e749f25SAlexander Motin 	case E1000_PRC255:
18899e749f25SAlexander Motin 		retval = sc->pkt_rx_by_size[2];
18909e749f25SAlexander Motin 		break;
18919e749f25SAlexander Motin 	case E1000_PRC511:
18929e749f25SAlexander Motin 		retval = sc->pkt_rx_by_size[3];
18939e749f25SAlexander Motin 		break;
18949e749f25SAlexander Motin 	case E1000_PRC1023:
18959e749f25SAlexander Motin 		retval = sc->pkt_rx_by_size[4];
18969e749f25SAlexander Motin 		break;
18979e749f25SAlexander Motin 	case E1000_PRC1522:
18989e749f25SAlexander Motin 		retval = sc->pkt_rx_by_size[5];
18999e749f25SAlexander Motin 		break;
19009e749f25SAlexander Motin 	case E1000_GPRC:
19019e749f25SAlexander Motin 		retval = sc->good_pkt_rx_count;
19029e749f25SAlexander Motin 		break;
19039e749f25SAlexander Motin 	case E1000_BPRC:
19049e749f25SAlexander Motin 		retval = sc->bcast_pkt_rx_count;
19059e749f25SAlexander Motin 		break;
19069e749f25SAlexander Motin 	case E1000_MPRC:
19079e749f25SAlexander Motin 		retval = sc->mcast_pkt_rx_count;
19089e749f25SAlexander Motin 		break;
19099e749f25SAlexander Motin 	case E1000_GPTC:
19109e749f25SAlexander Motin 	case E1000_TPT:
19119e749f25SAlexander Motin 		retval = sc->good_pkt_tx_count;
19129e749f25SAlexander Motin 		break;
19139e749f25SAlexander Motin 	case E1000_GORCL:
19149e749f25SAlexander Motin 		retval = (uint32_t)sc->good_octets_rx;
19159e749f25SAlexander Motin 		break;
19169e749f25SAlexander Motin 	case E1000_GORCH:
19179e749f25SAlexander Motin 		retval = (uint32_t)(sc->good_octets_rx >> 32);
19189e749f25SAlexander Motin 		break;
19199e749f25SAlexander Motin 	case E1000_TOTL:
19209e749f25SAlexander Motin 	case E1000_GOTCL:
19219e749f25SAlexander Motin 		retval = (uint32_t)sc->good_octets_tx;
19229e749f25SAlexander Motin 		break;
19239e749f25SAlexander Motin 	case E1000_TOTH:
19249e749f25SAlexander Motin 	case E1000_GOTCH:
19259e749f25SAlexander Motin 		retval = (uint32_t)(sc->good_octets_tx >> 32);
19269e749f25SAlexander Motin 		break;
19279e749f25SAlexander Motin 	case E1000_ROC:
19289e749f25SAlexander Motin 		retval = sc->oversize_rx_count;
19299e749f25SAlexander Motin 		break;
19309e749f25SAlexander Motin 	case E1000_TORL:
19319e749f25SAlexander Motin 		retval = (uint32_t)(sc->good_octets_rx + sc->missed_octets);
19329e749f25SAlexander Motin 		break;
19339e749f25SAlexander Motin 	case E1000_TORH:
19349e749f25SAlexander Motin 		retval = (uint32_t)((sc->good_octets_rx +
19359e749f25SAlexander Motin 		    sc->missed_octets) >> 32);
19369e749f25SAlexander Motin 		break;
19379e749f25SAlexander Motin 	case E1000_TPR:
19389e749f25SAlexander Motin 		retval = sc->good_pkt_rx_count + sc->missed_pkt_count +
19399e749f25SAlexander Motin 		    sc->oversize_rx_count;
19409e749f25SAlexander Motin 		break;
19419e749f25SAlexander Motin 	case E1000_PTC64:
19429e749f25SAlexander Motin 		retval = sc->pkt_tx_by_size[0];
19439e749f25SAlexander Motin 		break;
19449e749f25SAlexander Motin 	case E1000_PTC127:
19459e749f25SAlexander Motin 		retval = sc->pkt_tx_by_size[1];
19469e749f25SAlexander Motin 		break;
19479e749f25SAlexander Motin 	case E1000_PTC255:
19489e749f25SAlexander Motin 		retval = sc->pkt_tx_by_size[2];
19499e749f25SAlexander Motin 		break;
19509e749f25SAlexander Motin 	case E1000_PTC511:
19519e749f25SAlexander Motin 		retval = sc->pkt_tx_by_size[3];
19529e749f25SAlexander Motin 		break;
19539e749f25SAlexander Motin 	case E1000_PTC1023:
19549e749f25SAlexander Motin 		retval = sc->pkt_tx_by_size[4];
19559e749f25SAlexander Motin 		break;
19569e749f25SAlexander Motin 	case E1000_PTC1522:
19579e749f25SAlexander Motin 		retval = sc->pkt_tx_by_size[5];
19589e749f25SAlexander Motin 		break;
19599e749f25SAlexander Motin 	case E1000_MPTC:
19609e749f25SAlexander Motin 		retval = sc->mcast_pkt_tx_count;
19619e749f25SAlexander Motin 		break;
19629e749f25SAlexander Motin 	case E1000_BPTC:
19639e749f25SAlexander Motin 		retval = sc->bcast_pkt_tx_count;
19649e749f25SAlexander Motin 		break;
19659e749f25SAlexander Motin 	case E1000_TSCTC:
19669e749f25SAlexander Motin 		retval = sc->tso_tx_count;
19679e749f25SAlexander Motin 		break;
19689e749f25SAlexander Motin 	/* stats that are always 0. */
19699e749f25SAlexander Motin 	case E1000_CRCERRS:
19709e749f25SAlexander Motin 	case E1000_ALGNERRC:
19719e749f25SAlexander Motin 	case E1000_SYMERRS:
19729e749f25SAlexander Motin 	case E1000_RXERRC:
19739e749f25SAlexander Motin 	case E1000_SCC:
19749e749f25SAlexander Motin 	case E1000_ECOL:
19759e749f25SAlexander Motin 	case E1000_MCC:
19769e749f25SAlexander Motin 	case E1000_LATECOL:
19779e749f25SAlexander Motin 	case E1000_COLC:
19789e749f25SAlexander Motin 	case E1000_DC:
19799e749f25SAlexander Motin 	case E1000_TNCRS:
19809e749f25SAlexander Motin 	case E1000_SEC:
19819e749f25SAlexander Motin 	case E1000_CEXTERR:
19829e749f25SAlexander Motin 	case E1000_RLEC:
19839e749f25SAlexander Motin 	case E1000_XONRXC:
19849e749f25SAlexander Motin 	case E1000_XONTXC:
19859e749f25SAlexander Motin 	case E1000_XOFFRXC:
19869e749f25SAlexander Motin 	case E1000_XOFFTXC:
19879e749f25SAlexander Motin 	case E1000_FCRUC:
19889e749f25SAlexander Motin 	case E1000_RNBC:
19899e749f25SAlexander Motin 	case E1000_RUC:
19909e749f25SAlexander Motin 	case E1000_RFC:
19919e749f25SAlexander Motin 	case E1000_RJC:
19929e749f25SAlexander Motin 	case E1000_MGTPRC:
19939e749f25SAlexander Motin 	case E1000_MGTPDC:
19949e749f25SAlexander Motin 	case E1000_MGTPTC:
19959e749f25SAlexander Motin 	case E1000_TSCTFC:
19969e749f25SAlexander Motin 		retval = 0;
19979e749f25SAlexander Motin 		break;
19989e749f25SAlexander Motin 	default:
19999e749f25SAlexander Motin 		DPRINTF("Unknown read register: 0x%x\r\n", offset);
2000e95b7573SAlexander Motin 		retval = 0;
20019e749f25SAlexander Motin 		break;
20029e749f25SAlexander Motin 	}
20039e749f25SAlexander Motin 
20049e749f25SAlexander Motin 	return (retval);
20059e749f25SAlexander Motin }
20069e749f25SAlexander Motin 
20079e749f25SAlexander Motin static void
20089e749f25SAlexander Motin e82545_write(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, int baridx,
20099e749f25SAlexander Motin 	     uint64_t offset, int size, uint64_t value)
20109e749f25SAlexander Motin {
20119e749f25SAlexander Motin 	struct e82545_softc *sc;
20129e749f25SAlexander Motin 
20139e749f25SAlexander Motin 	//DPRINTF("Write bar:%d offset:0x%lx value:0x%lx size:%d\r\n", baridx, offset, value, size);
20149e749f25SAlexander Motin 
20159e749f25SAlexander Motin 	sc = pi->pi_arg;
20169e749f25SAlexander Motin 
20179e749f25SAlexander Motin 	pthread_mutex_lock(&sc->esc_mtx);
20189e749f25SAlexander Motin 
20199e749f25SAlexander Motin 	switch (baridx) {
20209e749f25SAlexander Motin 	case E82545_BAR_IO:
20219e749f25SAlexander Motin 		switch (offset) {
20229e749f25SAlexander Motin 		case E82545_IOADDR:
20239e749f25SAlexander Motin 			if (size != 4) {
20249e749f25SAlexander Motin 				DPRINTF("Wrong io addr write sz:%d value:0x%lx\r\n", size, value);
20259e749f25SAlexander Motin 			} else
20269e749f25SAlexander Motin 				sc->io_addr = (uint32_t)value;
20279e749f25SAlexander Motin 			break;
20289e749f25SAlexander Motin 		case E82545_IODATA:
20299e749f25SAlexander Motin 			if (size != 4) {
20309e749f25SAlexander Motin 				DPRINTF("Wrong io data write size:%d value:0x%lx\r\n", size, value);
20319e749f25SAlexander Motin 			} else if (sc->io_addr > E82545_IO_REGISTER_MAX) {
20329e749f25SAlexander Motin 				DPRINTF("Non-register io write addr:0x%x value:0x%lx\r\n", sc->io_addr, value);
20339e749f25SAlexander Motin 			} else
20349e749f25SAlexander Motin 				e82545_write_register(sc, sc->io_addr,
20359e749f25SAlexander Motin 						      (uint32_t)value);
20369e749f25SAlexander Motin 			break;
20379e749f25SAlexander Motin 		default:
20389e749f25SAlexander Motin 			DPRINTF("Unknown io bar write offset:0x%lx value:0x%lx size:%d\r\n", offset, value, size);
20399e749f25SAlexander Motin 			break;
20409e749f25SAlexander Motin 		}
2041a88b19f9SAlexander Motin 		break;
20429e749f25SAlexander Motin 	case E82545_BAR_REGISTER:
20439e749f25SAlexander Motin 		if (size != 4) {
20449e749f25SAlexander Motin 			DPRINTF("Wrong register write size:%d offset:0x%lx value:0x%lx\r\n", size, offset, value);
20459e749f25SAlexander Motin 		} else
20469e749f25SAlexander Motin 			e82545_write_register(sc, (uint32_t)offset,
20479e749f25SAlexander Motin 					      (uint32_t)value);
20489e749f25SAlexander Motin 		break;
20499e749f25SAlexander Motin 	default:
20509e749f25SAlexander Motin 		DPRINTF("Unknown write bar:%d off:0x%lx val:0x%lx size:%d\r\n",
20519e749f25SAlexander Motin 			baridx, offset, value, size);
20529e749f25SAlexander Motin 	}
20539e749f25SAlexander Motin 
20549e749f25SAlexander Motin 	pthread_mutex_unlock(&sc->esc_mtx);
20559e749f25SAlexander Motin }
20569e749f25SAlexander Motin 
20579e749f25SAlexander Motin static uint64_t
20589e749f25SAlexander Motin e82545_read(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, int baridx,
20599e749f25SAlexander Motin 	    uint64_t offset, int size)
20609e749f25SAlexander Motin {
20619e749f25SAlexander Motin 	struct e82545_softc *sc;
20629e749f25SAlexander Motin 	uint64_t retval;
20639e749f25SAlexander Motin 
20649e749f25SAlexander Motin 	//DPRINTF("Read  bar:%d offset:0x%lx size:%d\r\n", baridx, offset, size);
20659e749f25SAlexander Motin 	sc = pi->pi_arg;
20669e749f25SAlexander Motin 	retval = 0;
20679e749f25SAlexander Motin 
20689e749f25SAlexander Motin 	pthread_mutex_lock(&sc->esc_mtx);
20699e749f25SAlexander Motin 
20709e749f25SAlexander Motin 	switch (baridx) {
20719e749f25SAlexander Motin 	case E82545_BAR_IO:
20729e749f25SAlexander Motin 		switch (offset) {
20739e749f25SAlexander Motin 		case E82545_IOADDR:
20749e749f25SAlexander Motin 			if (size != 4) {
20759e749f25SAlexander Motin 				DPRINTF("Wrong io addr read sz:%d\r\n", size);
20769e749f25SAlexander Motin 			} else
20779e749f25SAlexander Motin 				retval = sc->io_addr;
20789e749f25SAlexander Motin 			break;
20799e749f25SAlexander Motin 		case E82545_IODATA:
20809e749f25SAlexander Motin 			if (size != 4) {
20819e749f25SAlexander Motin 				DPRINTF("Wrong io data read sz:%d\r\n", size);
20829e749f25SAlexander Motin 			}
20839e749f25SAlexander Motin 			if (sc->io_addr > E82545_IO_REGISTER_MAX) {
20849e749f25SAlexander Motin 				DPRINTF("Non-register io read addr:0x%x\r\n",
20859e749f25SAlexander Motin 					sc->io_addr);
20869e749f25SAlexander Motin 			} else
20879e749f25SAlexander Motin 				retval = e82545_read_register(sc, sc->io_addr);
20889e749f25SAlexander Motin 			break;
20899e749f25SAlexander Motin 		default:
20909e749f25SAlexander Motin 			DPRINTF("Unknown io bar read offset:0x%lx size:%d\r\n",
20919e749f25SAlexander Motin 				offset, size);
20929e749f25SAlexander Motin 			break;
20939e749f25SAlexander Motin 		}
2094a88b19f9SAlexander Motin 		break;
20959e749f25SAlexander Motin 	case E82545_BAR_REGISTER:
20969e749f25SAlexander Motin 		if (size != 4) {
20979e749f25SAlexander Motin 			DPRINTF("Wrong register read size:%d offset:0x%lx\r\n",
20989e749f25SAlexander Motin 				size, offset);
20999e749f25SAlexander Motin 		} else
21009e749f25SAlexander Motin 			retval = e82545_read_register(sc, (uint32_t)offset);
21019e749f25SAlexander Motin 		break;
21029e749f25SAlexander Motin 	default:
21039e749f25SAlexander Motin 		DPRINTF("Unknown read bar:%d offset:0x%lx size:%d\r\n",
21049e749f25SAlexander Motin 			baridx, offset, size);
21059e749f25SAlexander Motin 		break;
21069e749f25SAlexander Motin 	}
21079e749f25SAlexander Motin 
21089e749f25SAlexander Motin 	pthread_mutex_unlock(&sc->esc_mtx);
21099e749f25SAlexander Motin 
21109e749f25SAlexander Motin 	return (retval);
21119e749f25SAlexander Motin }
21129e749f25SAlexander Motin 
21139e749f25SAlexander Motin static void
21149e749f25SAlexander Motin e82545_reset(struct e82545_softc *sc, int drvr)
21159e749f25SAlexander Motin {
21169e749f25SAlexander Motin 	int i;
21179e749f25SAlexander Motin 
21189e749f25SAlexander Motin 	e82545_rx_disable(sc);
21199e749f25SAlexander Motin 	e82545_tx_disable(sc);
21209e749f25SAlexander Motin 
21219e749f25SAlexander Motin 	/* clear outstanding interrupts */
21229e749f25SAlexander Motin 	if (sc->esc_irq_asserted)
21239e749f25SAlexander Motin 		pci_lintr_deassert(sc->esc_pi);
21249e749f25SAlexander Motin 
21259e749f25SAlexander Motin 	/* misc */
21269e749f25SAlexander Motin 	if (!drvr) {
21279e749f25SAlexander Motin 		sc->esc_FCAL = 0;
21289e749f25SAlexander Motin 		sc->esc_FCAH = 0;
21299e749f25SAlexander Motin 		sc->esc_FCT = 0;
21309e749f25SAlexander Motin 		sc->esc_VET = 0;
21319e749f25SAlexander Motin 		sc->esc_FCTTV = 0;
21329e749f25SAlexander Motin 	}
21339e749f25SAlexander Motin 	sc->esc_LEDCTL = 0x07061302;
21349e749f25SAlexander Motin 	sc->esc_PBA = 0x00100030;
21359e749f25SAlexander Motin 
21369e749f25SAlexander Motin 	/* start nvm in opcode mode. */
21379e749f25SAlexander Motin 	sc->nvm_opaddr = 0;
21389e749f25SAlexander Motin 	sc->nvm_mode = E82545_NVM_MODE_OPADDR;
21399e749f25SAlexander Motin 	sc->nvm_bits = E82545_NVM_OPADDR_BITS;
21409e749f25SAlexander Motin 	sc->eeprom_control = E1000_EECD_PRES | E82545_EECD_FWE_EN;
21419e749f25SAlexander Motin 	e82545_init_eeprom(sc);
21429e749f25SAlexander Motin 
21439e749f25SAlexander Motin 	/* interrupt */
21449e749f25SAlexander Motin 	sc->esc_ICR = 0;
21459e749f25SAlexander Motin 	sc->esc_ITR = 250;
21469e749f25SAlexander Motin 	sc->esc_ICS = 0;
21479e749f25SAlexander Motin 	sc->esc_IMS = 0;
21489e749f25SAlexander Motin 	sc->esc_IMC = 0;
21499e749f25SAlexander Motin 
21509e749f25SAlexander Motin 	/* L2 filters */
21519e749f25SAlexander Motin 	if (!drvr) {
21529e749f25SAlexander Motin 		memset(sc->esc_fvlan, 0, sizeof(sc->esc_fvlan));
21539e749f25SAlexander Motin 		memset(sc->esc_fmcast, 0, sizeof(sc->esc_fmcast));
21549e749f25SAlexander Motin 		memset(sc->esc_uni, 0, sizeof(sc->esc_uni));
21559e749f25SAlexander Motin 
21569e749f25SAlexander Motin 		/* XXX not necessary on 82545 ?? */
21579e749f25SAlexander Motin 		sc->esc_uni[0].eu_valid = 1;
21589e749f25SAlexander Motin 		memcpy(sc->esc_uni[0].eu_eth.octet, sc->esc_mac.octet,
21599e749f25SAlexander Motin 		    ETHER_ADDR_LEN);
21609e749f25SAlexander Motin 	} else {
21619e749f25SAlexander Motin 		/* Clear RAH valid bits */
21629e749f25SAlexander Motin 		for (i = 0; i < 16; i++)
21639e749f25SAlexander Motin 			sc->esc_uni[i].eu_valid = 0;
21649e749f25SAlexander Motin 	}
21659e749f25SAlexander Motin 
21669e749f25SAlexander Motin 	/* receive */
21679e749f25SAlexander Motin 	if (!drvr) {
21689e749f25SAlexander Motin 		sc->esc_RDBAL = 0;
21699e749f25SAlexander Motin 		sc->esc_RDBAH = 0;
21709e749f25SAlexander Motin 	}
21719e749f25SAlexander Motin 	sc->esc_RCTL = 0;
21729e749f25SAlexander Motin 	sc->esc_FCRTL = 0;
21739e749f25SAlexander Motin 	sc->esc_FCRTH = 0;
21749e749f25SAlexander Motin 	sc->esc_RDLEN = 0;
21759e749f25SAlexander Motin 	sc->esc_RDH = 0;
21769e749f25SAlexander Motin 	sc->esc_RDT = 0;
21779e749f25SAlexander Motin 	sc->esc_RDTR = 0;
21789e749f25SAlexander Motin 	sc->esc_RXDCTL = (1 << 24) | (1 << 16); /* default GRAN/WTHRESH */
21799e749f25SAlexander Motin 	sc->esc_RADV = 0;
21809e749f25SAlexander Motin 	sc->esc_RXCSUM = 0;
21819e749f25SAlexander Motin 
21829e749f25SAlexander Motin 	/* transmit */
21839e749f25SAlexander Motin 	if (!drvr) {
21849e749f25SAlexander Motin 		sc->esc_TDBAL = 0;
21859e749f25SAlexander Motin 		sc->esc_TDBAH = 0;
21869e749f25SAlexander Motin 		sc->esc_TIPG = 0;
21879e749f25SAlexander Motin 		sc->esc_AIT = 0;
21889e749f25SAlexander Motin 		sc->esc_TIDV = 0;
21899e749f25SAlexander Motin 		sc->esc_TADV = 0;
21909e749f25SAlexander Motin 	}
21919e749f25SAlexander Motin 	sc->esc_tdba = 0;
21929e749f25SAlexander Motin 	sc->esc_txdesc = NULL;
21939e749f25SAlexander Motin 	sc->esc_TXCW = 0;
21949e749f25SAlexander Motin 	sc->esc_TCTL = 0;
21959e749f25SAlexander Motin 	sc->esc_TDLEN = 0;
21969e749f25SAlexander Motin 	sc->esc_TDT = 0;
21979e749f25SAlexander Motin 	sc->esc_TDHr = sc->esc_TDH = 0;
21989e749f25SAlexander Motin 	sc->esc_TXDCTL = 0;
21999e749f25SAlexander Motin }
22009e749f25SAlexander Motin 
22019e749f25SAlexander Motin static void
22029e749f25SAlexander Motin e82545_open_tap(struct e82545_softc *sc, char *opts)
22039e749f25SAlexander Motin {
22049e749f25SAlexander Motin 	char tbuf[80];
22059e749f25SAlexander Motin 
22069e749f25SAlexander Motin 	if (opts == NULL) {
22079e749f25SAlexander Motin 		sc->esc_tapfd = -1;
22089e749f25SAlexander Motin 		return;
22099e749f25SAlexander Motin 	}
22109e749f25SAlexander Motin 
22119e749f25SAlexander Motin 	strcpy(tbuf, "/dev/");
22129e749f25SAlexander Motin 	strlcat(tbuf, opts, sizeof(tbuf));
22139e749f25SAlexander Motin 
22149e749f25SAlexander Motin 	sc->esc_tapfd = open(tbuf, O_RDWR);
22159e749f25SAlexander Motin 	if (sc->esc_tapfd == -1) {
22169e749f25SAlexander Motin 		DPRINTF("unable to open tap device %s\n", opts);
22179e749f25SAlexander Motin 		exit(1);
22189e749f25SAlexander Motin 	}
22199e749f25SAlexander Motin 
22209e749f25SAlexander Motin 	/*
22219e749f25SAlexander Motin 	 * Set non-blocking and register for read
22229e749f25SAlexander Motin 	 * notifications with the event loop
22239e749f25SAlexander Motin 	 */
22249e749f25SAlexander Motin 	int opt = 1;
22259e749f25SAlexander Motin 	if (ioctl(sc->esc_tapfd, FIONBIO, &opt) < 0) {
22269e749f25SAlexander Motin 		WPRINTF("tap device O_NONBLOCK failed: %d\n", errno);
22279e749f25SAlexander Motin 		close(sc->esc_tapfd);
22289e749f25SAlexander Motin 		sc->esc_tapfd = -1;
22299e749f25SAlexander Motin 	}
22309e749f25SAlexander Motin 
22319e749f25SAlexander Motin 	sc->esc_mevp = mevent_add(sc->esc_tapfd,
22329e749f25SAlexander Motin 				  EVF_READ,
22339e749f25SAlexander Motin 				  e82545_tap_callback,
22349e749f25SAlexander Motin 				  sc);
22359e749f25SAlexander Motin 	if (sc->esc_mevp == NULL) {
22369e749f25SAlexander Motin 		DPRINTF("Could not register mevent %d\n", EVF_READ);
22379e749f25SAlexander Motin 		close(sc->esc_tapfd);
22389e749f25SAlexander Motin 		sc->esc_tapfd = -1;
22399e749f25SAlexander Motin 	}
22409e749f25SAlexander Motin }
22419e749f25SAlexander Motin 
22429e749f25SAlexander Motin static int
22439e749f25SAlexander Motin e82545_parsemac(char *mac_str, uint8_t *mac_addr)
22449e749f25SAlexander Motin {
22459e749f25SAlexander Motin 	struct ether_addr *ea;
22469e749f25SAlexander Motin 	char *tmpstr;
22479e749f25SAlexander Motin 	char zero_addr[ETHER_ADDR_LEN] = { 0, 0, 0, 0, 0, 0 };
22489e749f25SAlexander Motin 
22499e749f25SAlexander Motin 	tmpstr = strsep(&mac_str,"=");
22509e749f25SAlexander Motin 	if ((mac_str != NULL) && (!strcmp(tmpstr,"mac"))) {
22519e749f25SAlexander Motin 		ea = ether_aton(mac_str);
22529e749f25SAlexander Motin 		if (ea == NULL || ETHER_IS_MULTICAST(ea->octet) ||
22539e749f25SAlexander Motin 		    memcmp(ea->octet, zero_addr, ETHER_ADDR_LEN) == 0) {
22549e749f25SAlexander Motin 			fprintf(stderr, "Invalid MAC %s\n", mac_str);
22559e749f25SAlexander Motin 			return (1);
22569e749f25SAlexander Motin 		} else
22579e749f25SAlexander Motin 			memcpy(mac_addr, ea->octet, ETHER_ADDR_LEN);
22589e749f25SAlexander Motin 	}
22599e749f25SAlexander Motin 	return (0);
22609e749f25SAlexander Motin }
22619e749f25SAlexander Motin 
22629e749f25SAlexander Motin static int
22639e749f25SAlexander Motin e82545_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts)
22649e749f25SAlexander Motin {
22659e749f25SAlexander Motin 	DPRINTF("Loading with options: %s\r\n", opts);
22669e749f25SAlexander Motin 
22679e749f25SAlexander Motin 	MD5_CTX mdctx;
22689e749f25SAlexander Motin 	unsigned char digest[16];
22699e749f25SAlexander Motin 	char nstr[80];
22709e749f25SAlexander Motin 	struct e82545_softc *sc;
22719e749f25SAlexander Motin 	char *devname;
22729e749f25SAlexander Motin 	char *vtopts;
22739e749f25SAlexander Motin 	int mac_provided;
22749e749f25SAlexander Motin 
22759e749f25SAlexander Motin 	/* Setup our softc */
22769e749f25SAlexander Motin 	sc = calloc(sizeof(*sc), 1);
22779e749f25SAlexander Motin 
22789e749f25SAlexander Motin 	pi->pi_arg = sc;
22799e749f25SAlexander Motin 	sc->esc_pi = pi;
22809e749f25SAlexander Motin 	sc->esc_ctx = ctx;
22819e749f25SAlexander Motin 
22829e749f25SAlexander Motin 	pthread_mutex_init(&sc->esc_mtx, NULL);
22839e749f25SAlexander Motin 	pthread_cond_init(&sc->esc_rx_cond, NULL);
22849e749f25SAlexander Motin 	pthread_cond_init(&sc->esc_tx_cond, NULL);
22859e749f25SAlexander Motin 	pthread_create(&sc->esc_tx_tid, NULL, e82545_tx_thread, sc);
22869e749f25SAlexander Motin 	snprintf(nstr, sizeof(nstr), "e82545-%d:%d tx", pi->pi_slot,
22879e749f25SAlexander Motin 	    pi->pi_func);
22889e749f25SAlexander Motin         pthread_set_name_np(sc->esc_tx_tid, nstr);
22899e749f25SAlexander Motin 
22909e749f25SAlexander Motin 	pci_set_cfgdata16(pi, PCIR_DEVICE, E82545_DEV_ID_82545EM_COPPER);
22919e749f25SAlexander Motin 	pci_set_cfgdata16(pi, PCIR_VENDOR, E82545_VENDOR_ID_INTEL);
22929e749f25SAlexander Motin 	pci_set_cfgdata8(pi,  PCIR_CLASS, PCIC_NETWORK);
22939e749f25SAlexander Motin 	pci_set_cfgdata8(pi, PCIR_SUBCLASS, PCIS_NETWORK_ETHERNET);
22949e749f25SAlexander Motin 	pci_set_cfgdata16(pi, PCIR_SUBDEV_0, E82545_SUBDEV_ID);
22959e749f25SAlexander Motin 	pci_set_cfgdata16(pi, PCIR_SUBVEND_0, E82545_VENDOR_ID_INTEL);
22969e749f25SAlexander Motin 
22979e749f25SAlexander Motin 	pci_set_cfgdata8(pi,  PCIR_HDRTYPE, PCIM_HDRTYPE_NORMAL);
22989e749f25SAlexander Motin 	pci_set_cfgdata8(pi,  PCIR_INTPIN, 0x1);
22999e749f25SAlexander Motin 
23009e749f25SAlexander Motin 	/* TODO: this card also supports msi, but the freebsd driver for it
23019e749f25SAlexander Motin 	 * does not, so I have not implemented it. */
23029e749f25SAlexander Motin 	pci_lintr_request(pi);
23039e749f25SAlexander Motin 
23049e749f25SAlexander Motin 	pci_emul_alloc_bar(pi, E82545_BAR_REGISTER, PCIBAR_MEM32,
23059e749f25SAlexander Motin 		E82545_BAR_REGISTER_LEN);
23069e749f25SAlexander Motin 	pci_emul_alloc_bar(pi, E82545_BAR_FLASH, PCIBAR_MEM32,
23079e749f25SAlexander Motin 		E82545_BAR_FLASH_LEN);
23089e749f25SAlexander Motin 	pci_emul_alloc_bar(pi, E82545_BAR_IO, PCIBAR_IO,
23099e749f25SAlexander Motin 		E82545_BAR_IO_LEN);
23109e749f25SAlexander Motin 
23119e749f25SAlexander Motin 	/*
23129e749f25SAlexander Motin 	 * Attempt to open the tap device and read the MAC address
23139e749f25SAlexander Motin 	 * if specified.  Copied from virtio-net, slightly modified.
23149e749f25SAlexander Motin 	 */
23159e749f25SAlexander Motin 	mac_provided = 0;
23169e749f25SAlexander Motin 	sc->esc_tapfd = -1;
23179e749f25SAlexander Motin 	if (opts != NULL) {
23189e749f25SAlexander Motin 		int err;
23199e749f25SAlexander Motin 
23209e749f25SAlexander Motin 		devname = vtopts = strdup(opts);
23219e749f25SAlexander Motin 		(void) strsep(&vtopts, ",");
23229e749f25SAlexander Motin 
23239e749f25SAlexander Motin 		if (vtopts != NULL) {
23249e749f25SAlexander Motin 			err = e82545_parsemac(vtopts, sc->esc_mac.octet);
23259e749f25SAlexander Motin 			if (err != 0) {
23269e749f25SAlexander Motin 				free(devname);
23279e749f25SAlexander Motin 				return (err);
23289e749f25SAlexander Motin 			}
23299e749f25SAlexander Motin 			mac_provided = 1;
23309e749f25SAlexander Motin 		}
23319e749f25SAlexander Motin 
23329e749f25SAlexander Motin 		if (strncmp(devname, "tap", 3) == 0 ||
23339e749f25SAlexander Motin 		    strncmp(devname, "vmnet", 5) == 0)
23349e749f25SAlexander Motin 			e82545_open_tap(sc, devname);
23359e749f25SAlexander Motin 
23369e749f25SAlexander Motin 		free(devname);
23379e749f25SAlexander Motin 	}
23389e749f25SAlexander Motin 
23399e749f25SAlexander Motin 	/*
23409e749f25SAlexander Motin 	 * The default MAC address is the standard NetApp OUI of 00-a0-98,
23419e749f25SAlexander Motin 	 * followed by an MD5 of the PCI slot/func number and dev name
23429e749f25SAlexander Motin 	 */
23439e749f25SAlexander Motin 	if (!mac_provided) {
23449e749f25SAlexander Motin 		snprintf(nstr, sizeof(nstr), "%d-%d-%s", pi->pi_slot,
23459e749f25SAlexander Motin 		    pi->pi_func, vmname);
23469e749f25SAlexander Motin 
23479e749f25SAlexander Motin 		MD5Init(&mdctx);
23489e749f25SAlexander Motin 		MD5Update(&mdctx, nstr, strlen(nstr));
23499e749f25SAlexander Motin 		MD5Final(digest, &mdctx);
23509e749f25SAlexander Motin 
23519e749f25SAlexander Motin 		sc->esc_mac.octet[0] = 0x00;
23529e749f25SAlexander Motin 		sc->esc_mac.octet[1] = 0xa0;
23539e749f25SAlexander Motin 		sc->esc_mac.octet[2] = 0x98;
23549e749f25SAlexander Motin 		sc->esc_mac.octet[3] = digest[0];
23559e749f25SAlexander Motin 		sc->esc_mac.octet[4] = digest[1];
23569e749f25SAlexander Motin 		sc->esc_mac.octet[5] = digest[2];
23579e749f25SAlexander Motin 	}
23589e749f25SAlexander Motin 
23599e749f25SAlexander Motin 	/* H/w initiated reset */
23609e749f25SAlexander Motin 	e82545_reset(sc, 0);
23619e749f25SAlexander Motin 
23629e749f25SAlexander Motin 	return (0);
23639e749f25SAlexander Motin }
23649e749f25SAlexander Motin 
23659e749f25SAlexander Motin struct pci_devemu pci_de_e82545 = {
23669e749f25SAlexander Motin 	.pe_emu = 	"e1000",
23679e749f25SAlexander Motin 	.pe_init =	e82545_init,
23689e749f25SAlexander Motin 	.pe_barwrite =	e82545_write,
23699e749f25SAlexander Motin 	.pe_barread =	e82545_read
23709e749f25SAlexander Motin };
23719e749f25SAlexander Motin PCI_EMUL_SET(pci_de_e82545);
23729e749f25SAlexander Motin 
2373