xref: /freebsd/usr.sbin/bhyve/pci_e82545.c (revision 4d65a7c6951cea0333f1a0c1b32c38489cdfa6c5)
19e749f25SAlexander Motin /*
2*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
3ce80faa4SMarcelo Araujo  *
49e749f25SAlexander Motin  * Copyright (c) 2016 Alexander Motin <mav@FreeBSD.org>
59e749f25SAlexander Motin  * Copyright (c) 2015 Peter Grehan <grehan@freebsd.org>
69e749f25SAlexander Motin  * Copyright (c) 2013 Jeremiah Lott, Avere Systems
79e749f25SAlexander Motin  * All rights reserved.
89e749f25SAlexander Motin  *
99e749f25SAlexander Motin  * Redistribution and use in source and binary forms, with or without
109e749f25SAlexander Motin  * modification, are permitted provided that the following conditions
119e749f25SAlexander Motin  * are met:
129e749f25SAlexander Motin  * 1. Redistributions of source code must retain the above copyright
139e749f25SAlexander Motin  *    notice, this list of conditions and the following disclaimer
149e749f25SAlexander Motin  *    in this position and unchanged.
159e749f25SAlexander Motin  * 2. Redistributions in binary form must reproduce the above copyright
169e749f25SAlexander Motin  *    notice, this list of conditions and the following disclaimer in the
179e749f25SAlexander Motin  *    documentation and/or other materials provided with the distribution.
189e749f25SAlexander Motin  *
199e749f25SAlexander Motin  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
209e749f25SAlexander Motin  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
219e749f25SAlexander Motin  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
229e749f25SAlexander Motin  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
239e749f25SAlexander Motin  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
249e749f25SAlexander Motin  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
259e749f25SAlexander Motin  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
269e749f25SAlexander Motin  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
279e749f25SAlexander Motin  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
289e749f25SAlexander Motin  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
299e749f25SAlexander Motin  * SUCH DAMAGE.
309e749f25SAlexander Motin  */
319e749f25SAlexander Motin 
329e749f25SAlexander Motin #include <sys/types.h>
3300ef17beSBartek Rutkowski #ifndef WITHOUT_CAPSICUM
3400ef17beSBartek Rutkowski #include <sys/capsicum.h>
3500ef17beSBartek Rutkowski #endif
369e749f25SAlexander Motin #include <sys/limits.h>
379e749f25SAlexander Motin #include <sys/ioctl.h>
389e749f25SAlexander Motin #include <sys/uio.h>
399e749f25SAlexander Motin #include <net/ethernet.h>
409e749f25SAlexander Motin #include <netinet/in.h>
419e749f25SAlexander Motin #include <netinet/tcp.h>
429e749f25SAlexander Motin 
43abfa3c39SMarcelo Araujo #ifndef WITHOUT_CAPSICUM
44abfa3c39SMarcelo Araujo #include <capsicum_helpers.h>
45abfa3c39SMarcelo Araujo #endif
46483d953aSJohn Baldwin 
4700ef17beSBartek Rutkowski #include <err.h>
489e749f25SAlexander Motin #include <errno.h>
499e749f25SAlexander Motin #include <fcntl.h>
509e749f25SAlexander Motin #include <md5.h>
519e749f25SAlexander Motin #include <stdio.h>
529e749f25SAlexander Motin #include <stdlib.h>
539e749f25SAlexander Motin #include <string.h>
5400ef17beSBartek Rutkowski #include <sysexits.h>
559e749f25SAlexander Motin #include <unistd.h>
569e749f25SAlexander Motin #include <pthread.h>
579e749f25SAlexander Motin #include <pthread_np.h>
589e749f25SAlexander Motin 
599e749f25SAlexander Motin #include "e1000_regs.h"
609e749f25SAlexander Motin #include "e1000_defines.h"
619e749f25SAlexander Motin #include "mii.h"
629e749f25SAlexander Motin 
639e749f25SAlexander Motin #include "bhyverun.h"
64621b5090SJohn Baldwin #include "config.h"
65332eff95SVincenzo Maffione #include "debug.h"
669e749f25SAlexander Motin #include "pci_emul.h"
670f735657SJohn Baldwin #ifdef BHYVE_SNAPSHOT
680f735657SJohn Baldwin #include "snapshot.h"
690f735657SJohn Baldwin #endif
709e749f25SAlexander Motin #include "mevent.h"
714f7c3b7bSVincenzo Maffione #include "net_utils.h"
720ff7076bSVincenzo Maffione #include "net_backends.h"
739e749f25SAlexander Motin 
749e749f25SAlexander Motin /* Hardware/register definitions XXX: move some to common code. */
759e749f25SAlexander Motin #define E82545_VENDOR_ID_INTEL			0x8086
769e749f25SAlexander Motin #define E82545_DEV_ID_82545EM_COPPER		0x100F
779e749f25SAlexander Motin #define E82545_SUBDEV_ID			0x1008
789e749f25SAlexander Motin 
799e749f25SAlexander Motin #define E82545_REVISION_4			4
809e749f25SAlexander Motin 
819e749f25SAlexander Motin #define E82545_MDIC_DATA_MASK			0x0000FFFF
829e749f25SAlexander Motin #define E82545_MDIC_OP_MASK			0x0c000000
839e749f25SAlexander Motin #define E82545_MDIC_IE				0x20000000
849e749f25SAlexander Motin 
859e749f25SAlexander Motin #define E82545_EECD_FWE_DIS	0x00000010 /* Flash writes disabled */
869e749f25SAlexander Motin #define E82545_EECD_FWE_EN	0x00000020 /* Flash writes enabled */
879e749f25SAlexander Motin #define E82545_EECD_FWE_MASK	0x00000030 /* Flash writes mask */
889e749f25SAlexander Motin 
899e749f25SAlexander Motin #define E82545_BAR_REGISTER			0
909e749f25SAlexander Motin #define E82545_BAR_REGISTER_LEN			(128*1024)
919e749f25SAlexander Motin #define E82545_BAR_FLASH			1
929e749f25SAlexander Motin #define E82545_BAR_FLASH_LEN			(64*1024)
939e749f25SAlexander Motin #define E82545_BAR_IO				2
949e749f25SAlexander Motin #define E82545_BAR_IO_LEN			8
959e749f25SAlexander Motin 
969e749f25SAlexander Motin #define E82545_IOADDR				0x00000000
979e749f25SAlexander Motin #define E82545_IODATA				0x00000004
989e749f25SAlexander Motin #define E82545_IO_REGISTER_MAX			0x0001FFFF
999e749f25SAlexander Motin #define E82545_IO_FLASH_BASE			0x00080000
1009e749f25SAlexander Motin #define E82545_IO_FLASH_MAX			0x000FFFFF
1019e749f25SAlexander Motin 
1029e749f25SAlexander Motin #define E82545_ARRAY_ENTRY(reg, offset)		(reg + (offset<<2))
1039e749f25SAlexander Motin #define E82545_RAR_MAX				15
1049e749f25SAlexander Motin #define E82545_MTA_MAX				127
1059e749f25SAlexander Motin #define E82545_VFTA_MAX				127
1069e749f25SAlexander Motin 
1079e749f25SAlexander Motin /* Slightly modified from the driver versions, hardcoded for 3 opcode bits,
1089e749f25SAlexander Motin  * followed by 6 address bits.
1099e749f25SAlexander Motin  * TODO: make opcode bits and addr bits configurable?
1109e749f25SAlexander Motin  * NVM Commands - Microwire */
1119e749f25SAlexander Motin #define E82545_NVM_OPCODE_BITS	3
1129e749f25SAlexander Motin #define E82545_NVM_ADDR_BITS	6
1139e749f25SAlexander Motin #define E82545_NVM_DATA_BITS	16
1149e749f25SAlexander Motin #define E82545_NVM_OPADDR_BITS	(E82545_NVM_OPCODE_BITS + E82545_NVM_ADDR_BITS)
1159e749f25SAlexander Motin #define E82545_NVM_ADDR_MASK	((1 << E82545_NVM_ADDR_BITS)-1)
1169e749f25SAlexander Motin #define E82545_NVM_OPCODE_MASK	\
1179e749f25SAlexander Motin     (((1 << E82545_NVM_OPCODE_BITS) - 1) << E82545_NVM_ADDR_BITS)
1189e749f25SAlexander Motin #define E82545_NVM_OPCODE_READ	(0x6 << E82545_NVM_ADDR_BITS)	/* read */
1199e749f25SAlexander Motin #define E82545_NVM_OPCODE_WRITE	(0x5 << E82545_NVM_ADDR_BITS)	/* write */
1209e749f25SAlexander Motin #define E82545_NVM_OPCODE_ERASE	(0x7 << E82545_NVM_ADDR_BITS)	/* erase */
1219e749f25SAlexander Motin #define	E82545_NVM_OPCODE_EWEN	(0x4 << E82545_NVM_ADDR_BITS)	/* wr-enable */
1229e749f25SAlexander Motin 
1239e749f25SAlexander Motin #define	E82545_NVM_EEPROM_SIZE	64 /* 64 * 16-bit values == 128K */
1249e749f25SAlexander Motin 
1259e749f25SAlexander Motin #define E1000_ICR_SRPD		0x00010000
1269e749f25SAlexander Motin 
127ee7230f4SAlexander Motin /* This is an arbitrary number.  There is no hard limit on the chip. */
128ee7230f4SAlexander Motin #define I82545_MAX_TXSEGS	64
1299e749f25SAlexander Motin 
1309e749f25SAlexander Motin /* Legacy receive descriptor */
1319e749f25SAlexander Motin struct e1000_rx_desc {
1329e749f25SAlexander Motin 	uint64_t buffer_addr;	/* Address of the descriptor's data buffer */
1339e749f25SAlexander Motin 	uint16_t length;	/* Length of data DMAed into data buffer */
1349e749f25SAlexander Motin 	uint16_t csum;		/* Packet checksum */
1359e749f25SAlexander Motin 	uint8_t	 status;       	/* Descriptor status */
1369e749f25SAlexander Motin 	uint8_t  errors;	/* Descriptor Errors */
1379e749f25SAlexander Motin 	uint16_t special;
1389e749f25SAlexander Motin };
1399e749f25SAlexander Motin 
1409e749f25SAlexander Motin /* Transmit descriptor types */
1419e749f25SAlexander Motin #define	E1000_TXD_MASK		(E1000_TXD_CMD_DEXT | 0x00F00000)
1429e749f25SAlexander Motin #define E1000_TXD_TYP_L		(0)
1439e749f25SAlexander Motin #define E1000_TXD_TYP_C		(E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_C)
1449e749f25SAlexander Motin #define E1000_TXD_TYP_D		(E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D)
1459e749f25SAlexander Motin 
1469e749f25SAlexander Motin /* Legacy transmit descriptor */
1479e749f25SAlexander Motin struct e1000_tx_desc {
1489e749f25SAlexander Motin 	uint64_t buffer_addr;   /* Address of the descriptor's data buffer */
1499e749f25SAlexander Motin 	union {
1509e749f25SAlexander Motin 		uint32_t data;
1519e749f25SAlexander Motin 		struct {
1529e749f25SAlexander Motin 			uint16_t length;  /* Data buffer length */
1539e749f25SAlexander Motin 			uint8_t  cso;  /* Checksum offset */
1549e749f25SAlexander Motin 			uint8_t  cmd;  /* Descriptor control */
1559e749f25SAlexander Motin 		} flags;
1569e749f25SAlexander Motin 	} lower;
1579e749f25SAlexander Motin 	union {
1589e749f25SAlexander Motin 		uint32_t data;
1599e749f25SAlexander Motin 		struct {
1609e749f25SAlexander Motin 			uint8_t status; /* Descriptor status */
1619e749f25SAlexander Motin 			uint8_t css;  /* Checksum start */
1629e749f25SAlexander Motin 			uint16_t special;
1639e749f25SAlexander Motin 		} fields;
1649e749f25SAlexander Motin 	} upper;
1659e749f25SAlexander Motin };
1669e749f25SAlexander Motin 
1679e749f25SAlexander Motin /* Context descriptor */
1689e749f25SAlexander Motin struct e1000_context_desc {
1699e749f25SAlexander Motin 	union {
1709e749f25SAlexander Motin 		uint32_t ip_config;
1719e749f25SAlexander Motin 		struct {
1729e749f25SAlexander Motin 			uint8_t ipcss;  /* IP checksum start */
1739e749f25SAlexander Motin 			uint8_t ipcso;  /* IP checksum offset */
1749e749f25SAlexander Motin 			uint16_t ipcse;  /* IP checksum end */
1759e749f25SAlexander Motin 		} ip_fields;
1769e749f25SAlexander Motin 	} lower_setup;
1779e749f25SAlexander Motin 	union {
1789e749f25SAlexander Motin 		uint32_t tcp_config;
1799e749f25SAlexander Motin 		struct {
1809e749f25SAlexander Motin 			uint8_t tucss;  /* TCP checksum start */
1819e749f25SAlexander Motin 			uint8_t tucso;  /* TCP checksum offset */
1829e749f25SAlexander Motin 			uint16_t tucse;  /* TCP checksum end */
1839e749f25SAlexander Motin 		} tcp_fields;
1849e749f25SAlexander Motin 	} upper_setup;
1859e749f25SAlexander Motin 	uint32_t cmd_and_length;
1869e749f25SAlexander Motin 	union {
1879e749f25SAlexander Motin 		uint32_t data;
1889e749f25SAlexander Motin 		struct {
1899e749f25SAlexander Motin 			uint8_t status;  /* Descriptor status */
1909e749f25SAlexander Motin 			uint8_t hdr_len;  /* Header length */
1919e749f25SAlexander Motin 			uint16_t mss;  /* Maximum segment size */
1929e749f25SAlexander Motin 		} fields;
1939e749f25SAlexander Motin 	} tcp_seg_setup;
1949e749f25SAlexander Motin };
1959e749f25SAlexander Motin 
1969e749f25SAlexander Motin /* Data descriptor */
1979e749f25SAlexander Motin struct e1000_data_desc {
1989e749f25SAlexander Motin 	uint64_t buffer_addr;  /* Address of the descriptor's buffer address */
1999e749f25SAlexander Motin 	union {
2009e749f25SAlexander Motin 		uint32_t data;
2019e749f25SAlexander Motin 		struct {
2029e749f25SAlexander Motin 			uint16_t length;  /* Data buffer length */
2039e749f25SAlexander Motin 			uint8_t typ_len_ext;
2049e749f25SAlexander Motin 			uint8_t cmd;
2059e749f25SAlexander Motin 		} flags;
2069e749f25SAlexander Motin 	} lower;
2079e749f25SAlexander Motin 	union {
2089e749f25SAlexander Motin 		uint32_t data;
2099e749f25SAlexander Motin 		struct {
2109e749f25SAlexander Motin 			uint8_t status;  /* Descriptor status */
2119e749f25SAlexander Motin 			uint8_t popts;  /* Packet Options */
2129e749f25SAlexander Motin 			uint16_t special;
2139e749f25SAlexander Motin 		} fields;
2149e749f25SAlexander Motin 	} upper;
2159e749f25SAlexander Motin };
2169e749f25SAlexander Motin 
2179e749f25SAlexander Motin union e1000_tx_udesc {
2189e749f25SAlexander Motin 	struct e1000_tx_desc td;
2199e749f25SAlexander Motin 	struct e1000_context_desc cd;
2209e749f25SAlexander Motin 	struct e1000_data_desc dd;
2219e749f25SAlexander Motin };
2229e749f25SAlexander Motin 
2239e749f25SAlexander Motin /* Tx checksum info for a packet. */
2249e749f25SAlexander Motin struct ck_info {
2259e749f25SAlexander Motin 	int	ck_valid;	/* ck_info is valid */
2269e749f25SAlexander Motin 	uint8_t	ck_start;	/* start byte of cksum calcuation */
2279e749f25SAlexander Motin 	uint8_t	ck_off;		/* offset of cksum insertion */
2289e749f25SAlexander Motin 	uint16_t ck_len;	/* length of cksum calc: 0 is to packet-end */
2299e749f25SAlexander Motin };
2309e749f25SAlexander Motin 
2319e749f25SAlexander Motin /*
2329e749f25SAlexander Motin  * Debug printf
2339e749f25SAlexander Motin  */
2349e749f25SAlexander Motin static int e82545_debug = 0;
235fa46f370SJohn Baldwin #define WPRINTF(msg,params...) PRINTLN("e82545: " msg, ##params)
236332eff95SVincenzo Maffione #define DPRINTF(msg,params...) if (e82545_debug) WPRINTF(msg, params)
2379e749f25SAlexander Motin 
2389e749f25SAlexander Motin #define	MIN(a,b) (((a)<(b))?(a):(b))
2399e749f25SAlexander Motin #define	MAX(a,b) (((a)>(b))?(a):(b))
2409e749f25SAlexander Motin 
2419e749f25SAlexander Motin /* s/w representation of the RAL/RAH regs */
2429e749f25SAlexander Motin struct  eth_uni {
2439e749f25SAlexander Motin 	int		eu_valid;
2449e749f25SAlexander Motin 	int		eu_addrsel;
2459e749f25SAlexander Motin 	struct ether_addr eu_eth;
2469e749f25SAlexander Motin };
2479e749f25SAlexander Motin 
2489e749f25SAlexander Motin 
2499e749f25SAlexander Motin struct e82545_softc {
2509e749f25SAlexander Motin 	struct pci_devinst *esc_pi;
2519e749f25SAlexander Motin 	struct vmctx	*esc_ctx;
2529e749f25SAlexander Motin 	struct mevent   *esc_mevpitr;
2539e749f25SAlexander Motin 	pthread_mutex_t	esc_mtx;
2549e749f25SAlexander Motin 	struct ether_addr esc_mac;
2550ff7076bSVincenzo Maffione 	net_backend_t	*esc_be;
2569e749f25SAlexander Motin 
2579e749f25SAlexander Motin 	/* General */
2589e749f25SAlexander Motin 	uint32_t	esc_CTRL;	/* x0000 device ctl */
2599e749f25SAlexander Motin 	uint32_t	esc_FCAL;	/* x0028 flow ctl addr lo */
2609e749f25SAlexander Motin 	uint32_t	esc_FCAH;	/* x002C flow ctl addr hi */
2619e749f25SAlexander Motin 	uint32_t	esc_FCT;	/* x0030 flow ctl type */
2629e749f25SAlexander Motin 	uint32_t	esc_VET;	/* x0038 VLAN eth type */
2639e749f25SAlexander Motin 	uint32_t	esc_FCTTV;	/* x0170 flow ctl tx timer */
2649e749f25SAlexander Motin 	uint32_t	esc_LEDCTL;	/* x0E00 LED control */
2659e749f25SAlexander Motin 	uint32_t	esc_PBA;	/* x1000 pkt buffer allocation */
2669e749f25SAlexander Motin 
2679e749f25SAlexander Motin 	/* Interrupt control */
2689e749f25SAlexander Motin 	int		esc_irq_asserted;
2699e749f25SAlexander Motin 	uint32_t	esc_ICR;	/* x00C0 cause read/clear */
2709e749f25SAlexander Motin 	uint32_t	esc_ITR;	/* x00C4 intr throttling */
2719e749f25SAlexander Motin 	uint32_t	esc_ICS;	/* x00C8 cause set */
2729e749f25SAlexander Motin 	uint32_t	esc_IMS;	/* x00D0 mask set/read */
2739e749f25SAlexander Motin 	uint32_t	esc_IMC;	/* x00D8 mask clear */
2749e749f25SAlexander Motin 
2759e749f25SAlexander Motin 	/* Transmit */
2769e749f25SAlexander Motin 	union e1000_tx_udesc *esc_txdesc;
2779e749f25SAlexander Motin 	struct e1000_context_desc esc_txctx;
2789e749f25SAlexander Motin 	pthread_t	esc_tx_tid;
2799e749f25SAlexander Motin 	pthread_cond_t	esc_tx_cond;
2809e749f25SAlexander Motin 	int		esc_tx_enabled;
2819e749f25SAlexander Motin 	int		esc_tx_active;
2829e749f25SAlexander Motin 	uint32_t	esc_TXCW;	/* x0178 transmit config */
2839e749f25SAlexander Motin 	uint32_t	esc_TCTL;	/* x0400 transmit ctl */
2849e749f25SAlexander Motin 	uint32_t	esc_TIPG;	/* x0410 inter-packet gap */
2859e749f25SAlexander Motin 	uint16_t	esc_AIT;	/* x0458 Adaptive Interframe Throttle */
2869e749f25SAlexander Motin 	uint64_t	esc_tdba;      	/* verified 64-bit desc table addr */
2879e749f25SAlexander Motin 	uint32_t	esc_TDBAL;	/* x3800 desc table addr, low bits */
2889e749f25SAlexander Motin 	uint32_t	esc_TDBAH;	/* x3804 desc table addr, hi 32-bits */
2899e749f25SAlexander Motin 	uint32_t	esc_TDLEN;	/* x3808 # descriptors in bytes */
2909e749f25SAlexander Motin 	uint16_t	esc_TDH;	/* x3810 desc table head idx */
2919e749f25SAlexander Motin 	uint16_t	esc_TDHr;	/* internal read version of TDH */
2929e749f25SAlexander Motin 	uint16_t	esc_TDT;	/* x3818 desc table tail idx */
2939e749f25SAlexander Motin 	uint32_t	esc_TIDV;	/* x3820 intr delay */
2949e749f25SAlexander Motin 	uint32_t	esc_TXDCTL;	/* x3828 desc control */
2959e749f25SAlexander Motin 	uint32_t	esc_TADV;	/* x382C intr absolute delay */
2969e749f25SAlexander Motin 
2979e749f25SAlexander Motin 	/* L2 frame acceptance */
2989e749f25SAlexander Motin 	struct eth_uni	esc_uni[16];	/* 16 x unicast MAC addresses */
2999e749f25SAlexander Motin 	uint32_t	esc_fmcast[128]; /* Multicast filter bit-match */
3009e749f25SAlexander Motin 	uint32_t	esc_fvlan[128]; /* VLAN 4096-bit filter */
3019e749f25SAlexander Motin 
3029e749f25SAlexander Motin 	/* Receive */
3039e749f25SAlexander Motin 	struct e1000_rx_desc *esc_rxdesc;
3049e749f25SAlexander Motin 	pthread_cond_t	esc_rx_cond;
3059e749f25SAlexander Motin 	int		esc_rx_enabled;
3069e749f25SAlexander Motin 	int		esc_rx_active;
3079e749f25SAlexander Motin 	int		esc_rx_loopback;
3089e749f25SAlexander Motin 	uint32_t	esc_RCTL;	/* x0100 receive ctl */
3099e749f25SAlexander Motin 	uint32_t	esc_FCRTL;	/* x2160 flow cntl thresh, low */
3109e749f25SAlexander Motin 	uint32_t	esc_FCRTH;	/* x2168 flow cntl thresh, hi */
3119e749f25SAlexander Motin 	uint64_t	esc_rdba;	/* verified 64-bit desc table addr */
3129e749f25SAlexander Motin 	uint32_t	esc_RDBAL;	/* x2800 desc table addr, low bits */
3139e749f25SAlexander Motin 	uint32_t	esc_RDBAH;	/* x2804 desc table addr, hi 32-bits*/
3149e749f25SAlexander Motin 	uint32_t	esc_RDLEN;	/* x2808 #descriptors */
3159e749f25SAlexander Motin 	uint16_t	esc_RDH;	/* x2810 desc table head idx */
3169e749f25SAlexander Motin 	uint16_t	esc_RDT;	/* x2818 desc table tail idx */
3179e749f25SAlexander Motin 	uint32_t	esc_RDTR;	/* x2820 intr delay */
3189e749f25SAlexander Motin 	uint32_t	esc_RXDCTL;	/* x2828 desc control */
3199e749f25SAlexander Motin 	uint32_t	esc_RADV;	/* x282C intr absolute delay */
3209e749f25SAlexander Motin 	uint32_t	esc_RSRPD;	/* x2C00 recv small packet detect */
3219e749f25SAlexander Motin 	uint32_t	esc_RXCSUM;     /* x5000 receive cksum ctl */
3229e749f25SAlexander Motin 
3239e749f25SAlexander Motin 	/* IO Port register access */
3249e749f25SAlexander Motin 	uint32_t io_addr;
3259e749f25SAlexander Motin 
3269e749f25SAlexander Motin 	/* Shadow copy of MDIC */
3279e749f25SAlexander Motin 	uint32_t mdi_control;
3289e749f25SAlexander Motin 	/* Shadow copy of EECD */
3299e749f25SAlexander Motin 	uint32_t eeprom_control;
3309e749f25SAlexander Motin 	/* Latest NVM in/out */
3319e749f25SAlexander Motin 	uint16_t nvm_data;
3329e749f25SAlexander Motin 	uint16_t nvm_opaddr;
3339e749f25SAlexander Motin 	/* stats */
3349e749f25SAlexander Motin 	uint32_t missed_pkt_count; /* dropped for no room in rx queue */
3359e749f25SAlexander Motin 	uint32_t pkt_rx_by_size[6];
3369e749f25SAlexander Motin 	uint32_t pkt_tx_by_size[6];
3379e749f25SAlexander Motin 	uint32_t good_pkt_rx_count;
3389e749f25SAlexander Motin 	uint32_t bcast_pkt_rx_count;
3399e749f25SAlexander Motin 	uint32_t mcast_pkt_rx_count;
3409e749f25SAlexander Motin 	uint32_t good_pkt_tx_count;
3419e749f25SAlexander Motin 	uint32_t bcast_pkt_tx_count;
3429e749f25SAlexander Motin 	uint32_t mcast_pkt_tx_count;
3439e749f25SAlexander Motin 	uint32_t oversize_rx_count;
3449e749f25SAlexander Motin 	uint32_t tso_tx_count;
3459e749f25SAlexander Motin 	uint64_t good_octets_rx;
3469e749f25SAlexander Motin 	uint64_t good_octets_tx;
3479e749f25SAlexander Motin 	uint64_t missed_octets; /* counts missed and oversized */
3489e749f25SAlexander Motin 
3499e749f25SAlexander Motin 	uint8_t nvm_bits:6; /* number of bits remaining in/out */
3509e749f25SAlexander Motin 	uint8_t nvm_mode:2;
3519e749f25SAlexander Motin #define E82545_NVM_MODE_OPADDR  0x0
3529e749f25SAlexander Motin #define E82545_NVM_MODE_DATAIN  0x1
3539e749f25SAlexander Motin #define E82545_NVM_MODE_DATAOUT 0x2
3549e749f25SAlexander Motin 	/* EEPROM data */
3559e749f25SAlexander Motin 	uint16_t eeprom_data[E82545_NVM_EEPROM_SIZE];
3569e749f25SAlexander Motin };
3579e749f25SAlexander Motin 
3589e749f25SAlexander Motin static void e82545_reset(struct e82545_softc *sc, int dev);
3599e749f25SAlexander Motin static void e82545_rx_enable(struct e82545_softc *sc);
3609e749f25SAlexander Motin static void e82545_rx_disable(struct e82545_softc *sc);
3610ff7076bSVincenzo Maffione static void e82545_rx_callback(int fd, enum ev_type type, void *param);
3629e749f25SAlexander Motin static void e82545_tx_start(struct e82545_softc *sc);
3639e749f25SAlexander Motin static void e82545_tx_enable(struct e82545_softc *sc);
3649e749f25SAlexander Motin static void e82545_tx_disable(struct e82545_softc *sc);
3659e749f25SAlexander Motin 
366eb805f4eSMark Johnston static inline int __unused
e82545_size_stat_index(uint32_t size)3679e749f25SAlexander Motin e82545_size_stat_index(uint32_t size)
3689e749f25SAlexander Motin {
3699e749f25SAlexander Motin 	if (size <= 64) {
3709e749f25SAlexander Motin 		return 0;
3719e749f25SAlexander Motin 	} else if (size >= 1024) {
3729e749f25SAlexander Motin 		return 5;
3739e749f25SAlexander Motin 	} else {
3749e749f25SAlexander Motin 		/* should be 1-4 */
3759e749f25SAlexander Motin 		return (ffs(size) - 6);
3769e749f25SAlexander Motin 	}
3779e749f25SAlexander Motin }
3789e749f25SAlexander Motin 
3799e749f25SAlexander Motin static void
e82545_init_eeprom(struct e82545_softc * sc)3809e749f25SAlexander Motin e82545_init_eeprom(struct e82545_softc *sc)
3819e749f25SAlexander Motin {
3829e749f25SAlexander Motin 	uint16_t checksum, i;
3839e749f25SAlexander Motin 
3849e749f25SAlexander Motin         /* mac addr */
3859e749f25SAlexander Motin 	sc->eeprom_data[NVM_MAC_ADDR] = ((uint16_t)sc->esc_mac.octet[0]) |
3869e749f25SAlexander Motin 		(((uint16_t)sc->esc_mac.octet[1]) << 8);
3879e749f25SAlexander Motin 	sc->eeprom_data[NVM_MAC_ADDR+1] = ((uint16_t)sc->esc_mac.octet[2]) |
3889e749f25SAlexander Motin 		(((uint16_t)sc->esc_mac.octet[3]) << 8);
3899e749f25SAlexander Motin 	sc->eeprom_data[NVM_MAC_ADDR+2] = ((uint16_t)sc->esc_mac.octet[4]) |
3909e749f25SAlexander Motin 		(((uint16_t)sc->esc_mac.octet[5]) << 8);
3919e749f25SAlexander Motin 
3929e749f25SAlexander Motin 	/* pci ids */
3939e749f25SAlexander Motin 	sc->eeprom_data[NVM_SUB_DEV_ID] = E82545_SUBDEV_ID;
3949e749f25SAlexander Motin 	sc->eeprom_data[NVM_SUB_VEN_ID] = E82545_VENDOR_ID_INTEL;
3959e749f25SAlexander Motin 	sc->eeprom_data[NVM_DEV_ID] = E82545_DEV_ID_82545EM_COPPER;
3969e749f25SAlexander Motin 	sc->eeprom_data[NVM_VEN_ID] = E82545_VENDOR_ID_INTEL;
3979e749f25SAlexander Motin 
3989e749f25SAlexander Motin 	/* fill in the checksum */
3999e749f25SAlexander Motin         checksum = 0;
4009e749f25SAlexander Motin 	for (i = 0; i < NVM_CHECKSUM_REG; i++) {
4019e749f25SAlexander Motin 		checksum += sc->eeprom_data[i];
4029e749f25SAlexander Motin 	}
4039e749f25SAlexander Motin 	checksum = NVM_SUM - checksum;
4049e749f25SAlexander Motin 	sc->eeprom_data[NVM_CHECKSUM_REG] = checksum;
405332eff95SVincenzo Maffione 	DPRINTF("eeprom checksum: 0x%x", checksum);
4069e749f25SAlexander Motin }
4079e749f25SAlexander Motin 
4089e749f25SAlexander Motin static void
e82545_write_mdi(struct e82545_softc * sc __unused,uint8_t reg_addr,uint8_t phy_addr,uint32_t data)40998d920d9SMark Johnston e82545_write_mdi(struct e82545_softc *sc __unused, uint8_t reg_addr,
4109e749f25SAlexander Motin     uint8_t phy_addr, uint32_t data)
4119e749f25SAlexander Motin {
412332eff95SVincenzo Maffione 	DPRINTF("Write mdi reg:0x%x phy:0x%x data: 0x%x", reg_addr, phy_addr, data);
4139e749f25SAlexander Motin }
4149e749f25SAlexander Motin 
4159e749f25SAlexander Motin static uint32_t
e82545_read_mdi(struct e82545_softc * sc __unused,uint8_t reg_addr,uint8_t phy_addr)41698d920d9SMark Johnston e82545_read_mdi(struct e82545_softc *sc __unused, uint8_t reg_addr,
4179e749f25SAlexander Motin     uint8_t phy_addr)
4189e749f25SAlexander Motin {
419332eff95SVincenzo Maffione 	//DPRINTF("Read mdi reg:0x%x phy:0x%x", reg_addr, phy_addr);
4209e749f25SAlexander Motin 	switch (reg_addr) {
4219e749f25SAlexander Motin 	case PHY_STATUS:
4229e749f25SAlexander Motin 		return (MII_SR_LINK_STATUS | MII_SR_AUTONEG_CAPS |
4239e749f25SAlexander Motin 			MII_SR_AUTONEG_COMPLETE);
4249e749f25SAlexander Motin 	case PHY_AUTONEG_ADV:
4259e749f25SAlexander Motin 		return NWAY_AR_SELECTOR_FIELD;
4269e749f25SAlexander Motin 	case PHY_LP_ABILITY:
4279e749f25SAlexander Motin 		return 0;
4289e749f25SAlexander Motin 	case PHY_1000T_STATUS:
4299e749f25SAlexander Motin 		return (SR_1000T_LP_FD_CAPS | SR_1000T_REMOTE_RX_STATUS |
4309e749f25SAlexander Motin 			SR_1000T_LOCAL_RX_STATUS);
4319e749f25SAlexander Motin 	case PHY_ID1:
4329e749f25SAlexander Motin 		return (M88E1011_I_PHY_ID >> 16) & 0xFFFF;
4339e749f25SAlexander Motin 	case PHY_ID2:
4349e749f25SAlexander Motin 		return (M88E1011_I_PHY_ID | E82545_REVISION_4) & 0xFFFF;
4359e749f25SAlexander Motin 	default:
436332eff95SVincenzo Maffione 		DPRINTF("Unknown mdi read reg:0x%x phy:0x%x", reg_addr, phy_addr);
4379e749f25SAlexander Motin 		return 0;
4389e749f25SAlexander Motin 	}
4399e749f25SAlexander Motin 	/* not reached */
4409e749f25SAlexander Motin }
4419e749f25SAlexander Motin 
4429e749f25SAlexander Motin static void
e82545_eecd_strobe(struct e82545_softc * sc)4439e749f25SAlexander Motin e82545_eecd_strobe(struct e82545_softc *sc)
4449e749f25SAlexander Motin {
4459e749f25SAlexander Motin 	/* Microwire state machine */
4469e749f25SAlexander Motin 	/*
4479e749f25SAlexander Motin 	DPRINTF("eeprom state machine srtobe "
448332eff95SVincenzo Maffione 		"0x%x 0x%x 0x%x 0x%x",
4499e749f25SAlexander Motin 		sc->nvm_mode, sc->nvm_bits,
4509e749f25SAlexander Motin 		sc->nvm_opaddr, sc->nvm_data);*/
4519e749f25SAlexander Motin 
4529e749f25SAlexander Motin 	if (sc->nvm_bits == 0) {
4539e749f25SAlexander Motin 		DPRINTF("eeprom state machine not expecting data! "
454332eff95SVincenzo Maffione 			"0x%x 0x%x 0x%x 0x%x",
4559e749f25SAlexander Motin 			sc->nvm_mode, sc->nvm_bits,
4569e749f25SAlexander Motin 			sc->nvm_opaddr, sc->nvm_data);
4579e749f25SAlexander Motin 		return;
4589e749f25SAlexander Motin 	}
4599e749f25SAlexander Motin 	sc->nvm_bits--;
4609e749f25SAlexander Motin 	if (sc->nvm_mode == E82545_NVM_MODE_DATAOUT) {
4619e749f25SAlexander Motin 		/* shifting out */
4629e749f25SAlexander Motin 		if (sc->nvm_data & 0x8000) {
4639e749f25SAlexander Motin 			sc->eeprom_control |= E1000_EECD_DO;
4649e749f25SAlexander Motin 		} else {
4659e749f25SAlexander Motin 			sc->eeprom_control &= ~E1000_EECD_DO;
4669e749f25SAlexander Motin 		}
4679e749f25SAlexander Motin 		sc->nvm_data <<= 1;
4689e749f25SAlexander Motin 		if (sc->nvm_bits == 0) {
4699e749f25SAlexander Motin 			/* read done, back to opcode mode. */
4709e749f25SAlexander Motin 			sc->nvm_opaddr = 0;
4719e749f25SAlexander Motin 			sc->nvm_mode = E82545_NVM_MODE_OPADDR;
4729e749f25SAlexander Motin 			sc->nvm_bits = E82545_NVM_OPADDR_BITS;
4739e749f25SAlexander Motin 		}
4749e749f25SAlexander Motin 	} else if (sc->nvm_mode == E82545_NVM_MODE_DATAIN) {
4759e749f25SAlexander Motin 		/* shifting in */
4769e749f25SAlexander Motin 		sc->nvm_data <<= 1;
4779e749f25SAlexander Motin 		if (sc->eeprom_control & E1000_EECD_DI) {
4789e749f25SAlexander Motin 			sc->nvm_data |= 1;
4799e749f25SAlexander Motin 		}
4809e749f25SAlexander Motin 		if (sc->nvm_bits == 0) {
4819e749f25SAlexander Motin 			/* eeprom write */
4829e749f25SAlexander Motin 			uint16_t op = sc->nvm_opaddr & E82545_NVM_OPCODE_MASK;
4839e749f25SAlexander Motin 			uint16_t addr = sc->nvm_opaddr & E82545_NVM_ADDR_MASK;
4849e749f25SAlexander Motin 			if (op != E82545_NVM_OPCODE_WRITE) {
485332eff95SVincenzo Maffione 				DPRINTF("Illegal eeprom write op 0x%x",
4869e749f25SAlexander Motin 					sc->nvm_opaddr);
4879e749f25SAlexander Motin 			} else if (addr >= E82545_NVM_EEPROM_SIZE) {
488332eff95SVincenzo Maffione 				DPRINTF("Illegal eeprom write addr 0x%x",
4899e749f25SAlexander Motin 					sc->nvm_opaddr);
4909e749f25SAlexander Motin 			} else {
491332eff95SVincenzo Maffione 				DPRINTF("eeprom write eeprom[0x%x] = 0x%x",
4929e749f25SAlexander Motin 				addr, sc->nvm_data);
4939e749f25SAlexander Motin 				sc->eeprom_data[addr] = sc->nvm_data;
4949e749f25SAlexander Motin 			}
4959e749f25SAlexander Motin 			/* back to opcode mode */
4969e749f25SAlexander Motin 			sc->nvm_opaddr = 0;
4979e749f25SAlexander Motin 			sc->nvm_mode = E82545_NVM_MODE_OPADDR;
4989e749f25SAlexander Motin 			sc->nvm_bits = E82545_NVM_OPADDR_BITS;
4999e749f25SAlexander Motin 		}
5009e749f25SAlexander Motin 	} else if (sc->nvm_mode == E82545_NVM_MODE_OPADDR) {
5019e749f25SAlexander Motin 		sc->nvm_opaddr <<= 1;
5029e749f25SAlexander Motin 		if (sc->eeprom_control & E1000_EECD_DI) {
5039e749f25SAlexander Motin 			sc->nvm_opaddr |= 1;
5049e749f25SAlexander Motin 		}
5059e749f25SAlexander Motin 		if (sc->nvm_bits == 0) {
5069e749f25SAlexander Motin 			uint16_t op = sc->nvm_opaddr & E82545_NVM_OPCODE_MASK;
5079e749f25SAlexander Motin 			switch (op) {
5089e749f25SAlexander Motin 			case E82545_NVM_OPCODE_EWEN:
509332eff95SVincenzo Maffione 				DPRINTF("eeprom write enable: 0x%x",
5109e749f25SAlexander Motin 					sc->nvm_opaddr);
5119e749f25SAlexander Motin 				/* back to opcode mode */
5129e749f25SAlexander Motin 				sc->nvm_opaddr = 0;
5139e749f25SAlexander Motin 				sc->nvm_mode = E82545_NVM_MODE_OPADDR;
5149e749f25SAlexander Motin 				sc->nvm_bits = E82545_NVM_OPADDR_BITS;
5159e749f25SAlexander Motin 				break;
5169e749f25SAlexander Motin 			case E82545_NVM_OPCODE_READ:
5179e749f25SAlexander Motin 			{
5189e749f25SAlexander Motin 				uint16_t addr = sc->nvm_opaddr &
5199e749f25SAlexander Motin 					E82545_NVM_ADDR_MASK;
5209e749f25SAlexander Motin 				sc->nvm_mode = E82545_NVM_MODE_DATAOUT;
5219e749f25SAlexander Motin 				sc->nvm_bits = E82545_NVM_DATA_BITS;
5229e749f25SAlexander Motin 				if (addr < E82545_NVM_EEPROM_SIZE) {
5239e749f25SAlexander Motin 					sc->nvm_data = sc->eeprom_data[addr];
524332eff95SVincenzo Maffione 					DPRINTF("eeprom read: eeprom[0x%x] = 0x%x",
5259e749f25SAlexander Motin 						addr, sc->nvm_data);
5269e749f25SAlexander Motin 				} else {
527332eff95SVincenzo Maffione 					DPRINTF("eeprom illegal read: 0x%x",
5289e749f25SAlexander Motin 						sc->nvm_opaddr);
5299e749f25SAlexander Motin 					sc->nvm_data = 0;
5309e749f25SAlexander Motin 				}
5319e749f25SAlexander Motin 				break;
5329e749f25SAlexander Motin 			}
5339e749f25SAlexander Motin 			case E82545_NVM_OPCODE_WRITE:
5349e749f25SAlexander Motin 				sc->nvm_mode = E82545_NVM_MODE_DATAIN;
5359e749f25SAlexander Motin 				sc->nvm_bits = E82545_NVM_DATA_BITS;
5369e749f25SAlexander Motin 				sc->nvm_data = 0;
5379e749f25SAlexander Motin 				break;
5389e749f25SAlexander Motin 			default:
539332eff95SVincenzo Maffione 				DPRINTF("eeprom unknown op: 0x%x",
5409e749f25SAlexander Motin 					sc->nvm_opaddr);
5419e749f25SAlexander Motin 				/* back to opcode mode */
5429e749f25SAlexander Motin 				sc->nvm_opaddr = 0;
5439e749f25SAlexander Motin 				sc->nvm_mode = E82545_NVM_MODE_OPADDR;
5449e749f25SAlexander Motin 				sc->nvm_bits = E82545_NVM_OPADDR_BITS;
5459e749f25SAlexander Motin 			}
5469e749f25SAlexander Motin 		}
5479e749f25SAlexander Motin 	} else {
5489e749f25SAlexander Motin 		DPRINTF("eeprom state machine wrong state! "
549332eff95SVincenzo Maffione 			"0x%x 0x%x 0x%x 0x%x",
5509e749f25SAlexander Motin 			sc->nvm_mode, sc->nvm_bits,
5519e749f25SAlexander Motin 			sc->nvm_opaddr, sc->nvm_data);
5529e749f25SAlexander Motin 	}
5539e749f25SAlexander Motin }
5549e749f25SAlexander Motin 
5559e749f25SAlexander Motin static void
e82545_itr_callback(int fd __unused,enum ev_type type __unused,void * param)55698d920d9SMark Johnston e82545_itr_callback(int fd __unused, enum ev_type type __unused, void *param)
5579e749f25SAlexander Motin {
5589e749f25SAlexander Motin 	uint32_t new;
5599e749f25SAlexander Motin 	struct e82545_softc *sc = param;
5609e749f25SAlexander Motin 
5619e749f25SAlexander Motin 	pthread_mutex_lock(&sc->esc_mtx);
5629e749f25SAlexander Motin 	new = sc->esc_ICR & sc->esc_IMS;
5639e749f25SAlexander Motin 	if (new && !sc->esc_irq_asserted) {
564332eff95SVincenzo Maffione 		DPRINTF("itr callback: lintr assert %x", new);
5659e749f25SAlexander Motin 		sc->esc_irq_asserted = 1;
5669e749f25SAlexander Motin 		pci_lintr_assert(sc->esc_pi);
5679e749f25SAlexander Motin 	} else {
5689e749f25SAlexander Motin 		mevent_delete(sc->esc_mevpitr);
5699e749f25SAlexander Motin 		sc->esc_mevpitr = NULL;
5709e749f25SAlexander Motin 	}
5719e749f25SAlexander Motin 	pthread_mutex_unlock(&sc->esc_mtx);
5729e749f25SAlexander Motin }
5739e749f25SAlexander Motin 
5749e749f25SAlexander Motin static void
e82545_icr_assert(struct e82545_softc * sc,uint32_t bits)5759e749f25SAlexander Motin e82545_icr_assert(struct e82545_softc *sc, uint32_t bits)
5769e749f25SAlexander Motin {
5779e749f25SAlexander Motin 	uint32_t new;
5789e749f25SAlexander Motin 
579332eff95SVincenzo Maffione 	DPRINTF("icr assert: 0x%x", bits);
5809e749f25SAlexander Motin 
5819e749f25SAlexander Motin 	/*
5829e749f25SAlexander Motin 	 * An interrupt is only generated if bits are set that
5839e749f25SAlexander Motin 	 * aren't already in the ICR, these bits are unmasked,
5849e749f25SAlexander Motin 	 * and there isn't an interrupt already pending.
5859e749f25SAlexander Motin 	 */
5869e749f25SAlexander Motin 	new = bits & ~sc->esc_ICR & sc->esc_IMS;
5879e749f25SAlexander Motin 	sc->esc_ICR |= bits;
5889e749f25SAlexander Motin 
5899e749f25SAlexander Motin 	if (new == 0) {
590332eff95SVincenzo Maffione 		DPRINTF("icr assert: masked %x, ims %x", new, sc->esc_IMS);
5919e749f25SAlexander Motin 	} else if (sc->esc_mevpitr != NULL) {
592332eff95SVincenzo Maffione 		DPRINTF("icr assert: throttled %x, ims %x", new, sc->esc_IMS);
5939e749f25SAlexander Motin 	} else if (!sc->esc_irq_asserted) {
594332eff95SVincenzo Maffione 		DPRINTF("icr assert: lintr assert %x", new);
5959e749f25SAlexander Motin 		sc->esc_irq_asserted = 1;
5969e749f25SAlexander Motin 		pci_lintr_assert(sc->esc_pi);
5979e749f25SAlexander Motin 		if (sc->esc_ITR != 0) {
5989e749f25SAlexander Motin 			sc->esc_mevpitr = mevent_add(
5999e749f25SAlexander Motin 			    (sc->esc_ITR + 3905) / 3906,  /* 256ns -> 1ms */
6009e749f25SAlexander Motin 			    EVF_TIMER, e82545_itr_callback, sc);
6019e749f25SAlexander Motin 		}
6029e749f25SAlexander Motin 	}
6039e749f25SAlexander Motin }
6049e749f25SAlexander Motin 
6059e749f25SAlexander Motin static void
e82545_ims_change(struct e82545_softc * sc,uint32_t bits)6069e749f25SAlexander Motin e82545_ims_change(struct e82545_softc *sc, uint32_t bits)
6079e749f25SAlexander Motin {
6089e749f25SAlexander Motin 	uint32_t new;
6099e749f25SAlexander Motin 
6109e749f25SAlexander Motin 	/*
6119e749f25SAlexander Motin 	 * Changing the mask may allow previously asserted
6129e749f25SAlexander Motin 	 * but masked interrupt requests to generate an interrupt.
6139e749f25SAlexander Motin 	 */
6149e749f25SAlexander Motin 	new = bits & sc->esc_ICR & ~sc->esc_IMS;
6159e749f25SAlexander Motin 	sc->esc_IMS |= bits;
6169e749f25SAlexander Motin 
6179e749f25SAlexander Motin 	if (new == 0) {
618332eff95SVincenzo Maffione 		DPRINTF("ims change: masked %x, ims %x", new, sc->esc_IMS);
6199e749f25SAlexander Motin 	} else if (sc->esc_mevpitr != NULL) {
620332eff95SVincenzo Maffione 		DPRINTF("ims change: throttled %x, ims %x", new, sc->esc_IMS);
6219e749f25SAlexander Motin 	} else if (!sc->esc_irq_asserted) {
622332eff95SVincenzo Maffione 		DPRINTF("ims change: lintr assert %x", new);
6239e749f25SAlexander Motin 		sc->esc_irq_asserted = 1;
6249e749f25SAlexander Motin 		pci_lintr_assert(sc->esc_pi);
6259e749f25SAlexander Motin 		if (sc->esc_ITR != 0) {
6269e749f25SAlexander Motin 			sc->esc_mevpitr = mevent_add(
6279e749f25SAlexander Motin 			    (sc->esc_ITR + 3905) / 3906,  /* 256ns -> 1ms */
6289e749f25SAlexander Motin 			    EVF_TIMER, e82545_itr_callback, sc);
6299e749f25SAlexander Motin 		}
6309e749f25SAlexander Motin 	}
6319e749f25SAlexander Motin }
6329e749f25SAlexander Motin 
6339e749f25SAlexander Motin static void
e82545_icr_deassert(struct e82545_softc * sc,uint32_t bits)6349e749f25SAlexander Motin e82545_icr_deassert(struct e82545_softc *sc, uint32_t bits)
6359e749f25SAlexander Motin {
6369e749f25SAlexander Motin 
637332eff95SVincenzo Maffione 	DPRINTF("icr deassert: 0x%x", bits);
6389e749f25SAlexander Motin 	sc->esc_ICR &= ~bits;
6399e749f25SAlexander Motin 
6409e749f25SAlexander Motin 	/*
6419e749f25SAlexander Motin 	 * If there are no longer any interrupt sources and there
6429e749f25SAlexander Motin 	 * was an asserted interrupt, clear it
6439e749f25SAlexander Motin 	 */
6449e749f25SAlexander Motin 	if (sc->esc_irq_asserted && !(sc->esc_ICR & sc->esc_IMS)) {
645332eff95SVincenzo Maffione 		DPRINTF("icr deassert: lintr deassert %x", bits);
6469e749f25SAlexander Motin 		pci_lintr_deassert(sc->esc_pi);
6479e749f25SAlexander Motin 		sc->esc_irq_asserted = 0;
6489e749f25SAlexander Motin 	}
6499e749f25SAlexander Motin }
6509e749f25SAlexander Motin 
6519e749f25SAlexander Motin static void
e82545_intr_write(struct e82545_softc * sc,uint32_t offset,uint32_t value)6529e749f25SAlexander Motin e82545_intr_write(struct e82545_softc *sc, uint32_t offset, uint32_t value)
6539e749f25SAlexander Motin {
6549e749f25SAlexander Motin 
655332eff95SVincenzo Maffione 	DPRINTF("intr_write: off %x, val %x", offset, value);
6569e749f25SAlexander Motin 
6579e749f25SAlexander Motin 	switch (offset) {
6589e749f25SAlexander Motin 	case E1000_ICR:
6599e749f25SAlexander Motin 		e82545_icr_deassert(sc, value);
6609e749f25SAlexander Motin 		break;
6619e749f25SAlexander Motin 	case E1000_ITR:
6629e749f25SAlexander Motin 		sc->esc_ITR = value;
6639e749f25SAlexander Motin 		break;
6649e749f25SAlexander Motin 	case E1000_ICS:
6659e749f25SAlexander Motin 		sc->esc_ICS = value;	/* not used: store for debug */
6669e749f25SAlexander Motin 		e82545_icr_assert(sc, value);
6679e749f25SAlexander Motin 		break;
6689e749f25SAlexander Motin 	case E1000_IMS:
6699e749f25SAlexander Motin 		e82545_ims_change(sc, value);
6709e749f25SAlexander Motin 		break;
6719e749f25SAlexander Motin 	case E1000_IMC:
6729e749f25SAlexander Motin 		sc->esc_IMC = value;	/* for debug */
6739e749f25SAlexander Motin 		sc->esc_IMS &= ~value;
6749e749f25SAlexander Motin 		// XXX clear interrupts if all ICR bits now masked
6759e749f25SAlexander Motin 		// and interrupt was pending ?
6769e749f25SAlexander Motin 		break;
6779e749f25SAlexander Motin 	default:
6789e749f25SAlexander Motin 		break;
6799e749f25SAlexander Motin 	}
6809e749f25SAlexander Motin }
6819e749f25SAlexander Motin 
6829e749f25SAlexander Motin static uint32_t
e82545_intr_read(struct e82545_softc * sc,uint32_t offset)6839e749f25SAlexander Motin e82545_intr_read(struct e82545_softc *sc, uint32_t offset)
6849e749f25SAlexander Motin {
6859e749f25SAlexander Motin 	uint32_t retval;
6869e749f25SAlexander Motin 
6879e749f25SAlexander Motin 	retval = 0;
6889e749f25SAlexander Motin 
689332eff95SVincenzo Maffione 	DPRINTF("intr_read: off %x", offset);
6909e749f25SAlexander Motin 
6919e749f25SAlexander Motin 	switch (offset) {
6929e749f25SAlexander Motin 	case E1000_ICR:
6939e749f25SAlexander Motin 		retval = sc->esc_ICR;
6949e749f25SAlexander Motin 		sc->esc_ICR = 0;
6959e749f25SAlexander Motin 		e82545_icr_deassert(sc, ~0);
6969e749f25SAlexander Motin 		break;
6979e749f25SAlexander Motin 	case E1000_ITR:
6989e749f25SAlexander Motin 		retval = sc->esc_ITR;
6999e749f25SAlexander Motin 		break;
7009e749f25SAlexander Motin 	case E1000_ICS:
7019e749f25SAlexander Motin 		/* write-only register */
7029e749f25SAlexander Motin 		break;
7039e749f25SAlexander Motin 	case E1000_IMS:
7049e749f25SAlexander Motin 		retval = sc->esc_IMS;
7059e749f25SAlexander Motin 		break;
7069e749f25SAlexander Motin 	case E1000_IMC:
7079e749f25SAlexander Motin 		/* write-only register */
7089e749f25SAlexander Motin 		break;
7099e749f25SAlexander Motin 	default:
7109e749f25SAlexander Motin 		break;
7119e749f25SAlexander Motin 	}
7129e749f25SAlexander Motin 
7139e749f25SAlexander Motin 	return (retval);
7149e749f25SAlexander Motin }
7159e749f25SAlexander Motin 
7169e749f25SAlexander Motin static void
e82545_devctl(struct e82545_softc * sc,uint32_t val)7179e749f25SAlexander Motin e82545_devctl(struct e82545_softc *sc, uint32_t val)
7189e749f25SAlexander Motin {
7199e749f25SAlexander Motin 
7209e749f25SAlexander Motin 	sc->esc_CTRL = val & ~E1000_CTRL_RST;
7219e749f25SAlexander Motin 
7229e749f25SAlexander Motin 	if (val & E1000_CTRL_RST) {
723332eff95SVincenzo Maffione 		DPRINTF("e1k: s/w reset, ctl %x", val);
7249e749f25SAlexander Motin 		e82545_reset(sc, 1);
7259e749f25SAlexander Motin 	}
7269e749f25SAlexander Motin 	/* XXX check for phy reset ? */
7279e749f25SAlexander Motin }
7289e749f25SAlexander Motin 
7299e749f25SAlexander Motin static void
e82545_rx_update_rdba(struct e82545_softc * sc)7309e749f25SAlexander Motin e82545_rx_update_rdba(struct e82545_softc *sc)
7319e749f25SAlexander Motin {
7329e749f25SAlexander Motin 
7339e749f25SAlexander Motin 	/* XXX verify desc base/len within phys mem range */
7349e749f25SAlexander Motin 	sc->esc_rdba = (uint64_t)sc->esc_RDBAH << 32 |
7359e749f25SAlexander Motin 	    sc->esc_RDBAL;
7369e749f25SAlexander Motin 
7379e749f25SAlexander Motin 	/* Cache host mapping of guest descriptor array */
7389e749f25SAlexander Motin 	sc->esc_rxdesc = paddr_guest2host(sc->esc_ctx,
7399e749f25SAlexander Motin 	    sc->esc_rdba, sc->esc_RDLEN);
7409e749f25SAlexander Motin }
7419e749f25SAlexander Motin 
7429e749f25SAlexander Motin static void
e82545_rx_ctl(struct e82545_softc * sc,uint32_t val)7439e749f25SAlexander Motin e82545_rx_ctl(struct e82545_softc *sc, uint32_t val)
7449e749f25SAlexander Motin {
7459e749f25SAlexander Motin 	int on;
7469e749f25SAlexander Motin 
7479e749f25SAlexander Motin 	on = ((val & E1000_RCTL_EN) == E1000_RCTL_EN);
7489e749f25SAlexander Motin 
7499e749f25SAlexander Motin 	/* Save RCTL after stripping reserved bits 31:27,24,21,14,11:10,0 */
7509e749f25SAlexander Motin 	sc->esc_RCTL = val & ~0xF9204c01;
7519e749f25SAlexander Motin 
752332eff95SVincenzo Maffione 	DPRINTF("rx_ctl - %s RCTL %x, val %x",
7539e749f25SAlexander Motin 		on ? "on" : "off", sc->esc_RCTL, val);
7549e749f25SAlexander Motin 
7559e749f25SAlexander Motin 	/* state change requested */
7569e749f25SAlexander Motin 	if (on != sc->esc_rx_enabled) {
7579e749f25SAlexander Motin 		if (on) {
7589e749f25SAlexander Motin 			/* Catch disallowed/unimplemented settings */
7599e749f25SAlexander Motin 			//assert(!(val & E1000_RCTL_LBM_TCVR));
7609e749f25SAlexander Motin 
7619e749f25SAlexander Motin 			if (sc->esc_RCTL & E1000_RCTL_LBM_TCVR) {
7629e749f25SAlexander Motin 				sc->esc_rx_loopback = 1;
7639e749f25SAlexander Motin 			} else {
7649e749f25SAlexander Motin 				sc->esc_rx_loopback = 0;
7659e749f25SAlexander Motin 			}
7669e749f25SAlexander Motin 
7679e749f25SAlexander Motin 			e82545_rx_update_rdba(sc);
7689e749f25SAlexander Motin 			e82545_rx_enable(sc);
7699e749f25SAlexander Motin 		} else {
7709e749f25SAlexander Motin 			e82545_rx_disable(sc);
7719e749f25SAlexander Motin 			sc->esc_rx_loopback = 0;
7729e749f25SAlexander Motin 			sc->esc_rdba = 0;
7739e749f25SAlexander Motin 			sc->esc_rxdesc = NULL;
7749e749f25SAlexander Motin 		}
7759e749f25SAlexander Motin 	}
7769e749f25SAlexander Motin }
7779e749f25SAlexander Motin 
7789e749f25SAlexander Motin static void
e82545_tx_update_tdba(struct e82545_softc * sc)7799e749f25SAlexander Motin e82545_tx_update_tdba(struct e82545_softc *sc)
7809e749f25SAlexander Motin {
7819e749f25SAlexander Motin 
7829e749f25SAlexander Motin 	/* XXX verify desc base/len within phys mem range */
7839e749f25SAlexander Motin 	sc->esc_tdba = (uint64_t)sc->esc_TDBAH << 32 | sc->esc_TDBAL;
7849e749f25SAlexander Motin 
7859e749f25SAlexander Motin 	/* Cache host mapping of guest descriptor array */
7869e749f25SAlexander Motin 	sc->esc_txdesc = paddr_guest2host(sc->esc_ctx, sc->esc_tdba,
7879e749f25SAlexander Motin             sc->esc_TDLEN);
7889e749f25SAlexander Motin }
7899e749f25SAlexander Motin 
7909e749f25SAlexander Motin static void
e82545_tx_ctl(struct e82545_softc * sc,uint32_t val)7919e749f25SAlexander Motin e82545_tx_ctl(struct e82545_softc *sc, uint32_t val)
7929e749f25SAlexander Motin {
7939e749f25SAlexander Motin 	int on;
7949e749f25SAlexander Motin 
7959e749f25SAlexander Motin 	on = ((val & E1000_TCTL_EN) == E1000_TCTL_EN);
7969e749f25SAlexander Motin 
7979e749f25SAlexander Motin 	/* ignore TCTL_EN settings that don't change state */
7989e749f25SAlexander Motin 	if (on == sc->esc_tx_enabled)
7999e749f25SAlexander Motin 		return;
8009e749f25SAlexander Motin 
8019e749f25SAlexander Motin 	if (on) {
8029e749f25SAlexander Motin 		e82545_tx_update_tdba(sc);
8039e749f25SAlexander Motin 		e82545_tx_enable(sc);
8049e749f25SAlexander Motin 	} else {
8059e749f25SAlexander Motin 		e82545_tx_disable(sc);
8069e749f25SAlexander Motin 		sc->esc_tdba = 0;
8079e749f25SAlexander Motin 		sc->esc_txdesc = NULL;
8089e749f25SAlexander Motin 	}
8099e749f25SAlexander Motin 
8109e749f25SAlexander Motin 	/* Save TCTL value after stripping reserved bits 31:25,23,2,0 */
8119e749f25SAlexander Motin 	sc->esc_TCTL = val & ~0xFE800005;
8129e749f25SAlexander Motin }
8139e749f25SAlexander Motin 
81437045dfaSMark Johnston static int
e82545_bufsz(uint32_t rctl)8159e749f25SAlexander Motin e82545_bufsz(uint32_t rctl)
8169e749f25SAlexander Motin {
8179e749f25SAlexander Motin 
8189e749f25SAlexander Motin 	switch (rctl & (E1000_RCTL_BSEX | E1000_RCTL_SZ_256)) {
8199e749f25SAlexander Motin 	case (E1000_RCTL_SZ_2048): return (2048);
8209e749f25SAlexander Motin 	case (E1000_RCTL_SZ_1024): return (1024);
8219e749f25SAlexander Motin 	case (E1000_RCTL_SZ_512): return (512);
8229e749f25SAlexander Motin 	case (E1000_RCTL_SZ_256): return (256);
8239e749f25SAlexander Motin 	case (E1000_RCTL_BSEX|E1000_RCTL_SZ_16384): return (16384);
8249e749f25SAlexander Motin 	case (E1000_RCTL_BSEX|E1000_RCTL_SZ_8192): return (8192);
8259e749f25SAlexander Motin 	case (E1000_RCTL_BSEX|E1000_RCTL_SZ_4096): return (4096);
8269e749f25SAlexander Motin 	}
8279e749f25SAlexander Motin 	return (256);	/* Forbidden value. */
8289e749f25SAlexander Motin }
8299e749f25SAlexander Motin 
8309e749f25SAlexander Motin /* XXX one packet at a time until this is debugged */
8319e749f25SAlexander Motin static void
e82545_rx_callback(int fd __unused,enum ev_type type __unused,void * param)83298d920d9SMark Johnston e82545_rx_callback(int fd __unused, enum ev_type type __unused, void *param)
8339e749f25SAlexander Motin {
8349e749f25SAlexander Motin 	struct e82545_softc *sc = param;
8359e749f25SAlexander Motin 	struct e1000_rx_desc *rxd;
8369e749f25SAlexander Motin 	struct iovec vec[64];
837cea34d07SMark Johnston 	ssize_t len;
838cea34d07SMark Johnston 	int left, lim, maxpktsz, maxpktdesc, bufsz, i, n, size;
8399e749f25SAlexander Motin 	uint32_t cause = 0;
8409e749f25SAlexander Motin 	uint16_t *tp, tag, head;
8419e749f25SAlexander Motin 
8429e749f25SAlexander Motin 	pthread_mutex_lock(&sc->esc_mtx);
843332eff95SVincenzo Maffione 	DPRINTF("rx_run: head %x, tail %x", sc->esc_RDH, sc->esc_RDT);
8449e749f25SAlexander Motin 
8459e749f25SAlexander Motin 	if (!sc->esc_rx_enabled || sc->esc_rx_loopback) {
846332eff95SVincenzo Maffione 		DPRINTF("rx disabled (!%d || %d) -- packet(s) dropped",
8479e749f25SAlexander Motin 		    sc->esc_rx_enabled, sc->esc_rx_loopback);
8480ff7076bSVincenzo Maffione 		while (netbe_rx_discard(sc->esc_be) > 0) {
8499e749f25SAlexander Motin 		}
8509e749f25SAlexander Motin 		goto done1;
8519e749f25SAlexander Motin 	}
8529e749f25SAlexander Motin 	bufsz = e82545_bufsz(sc->esc_RCTL);
8539e749f25SAlexander Motin 	maxpktsz = (sc->esc_RCTL & E1000_RCTL_LPE) ? 16384 : 1522;
8549e749f25SAlexander Motin 	maxpktdesc = (maxpktsz + bufsz - 1) / bufsz;
8559e749f25SAlexander Motin 	size = sc->esc_RDLEN / 16;
8569e749f25SAlexander Motin 	head = sc->esc_RDH;
8579e749f25SAlexander Motin 	left = (size + sc->esc_RDT - head) % size;
8589e749f25SAlexander Motin 	if (left < maxpktdesc) {
859332eff95SVincenzo Maffione 		DPRINTF("rx overflow (%d < %d) -- packet(s) dropped",
8609e749f25SAlexander Motin 		    left, maxpktdesc);
8610ff7076bSVincenzo Maffione 		while (netbe_rx_discard(sc->esc_be) > 0) {
8629e749f25SAlexander Motin 		}
8639e749f25SAlexander Motin 		goto done1;
8649e749f25SAlexander Motin 	}
8659e749f25SAlexander Motin 
8669e749f25SAlexander Motin 	sc->esc_rx_active = 1;
8679e749f25SAlexander Motin 	pthread_mutex_unlock(&sc->esc_mtx);
8689e749f25SAlexander Motin 
8699e749f25SAlexander Motin 	for (lim = size / 4; lim > 0 && left >= maxpktdesc; lim -= n) {
8709e749f25SAlexander Motin 
8719e749f25SAlexander Motin 		/* Grab rx descriptor pointed to by the head pointer */
8729e749f25SAlexander Motin 		for (i = 0; i < maxpktdesc; i++) {
8739e749f25SAlexander Motin 			rxd = &sc->esc_rxdesc[(head + i) % size];
8749e749f25SAlexander Motin 			vec[i].iov_base = paddr_guest2host(sc->esc_ctx,
8759e749f25SAlexander Motin 			    rxd->buffer_addr, bufsz);
8769e749f25SAlexander Motin 			vec[i].iov_len = bufsz;
8779e749f25SAlexander Motin 		}
8780ff7076bSVincenzo Maffione 		len = netbe_recv(sc->esc_be, vec, maxpktdesc);
8799e749f25SAlexander Motin 		if (len <= 0) {
880cea34d07SMark Johnston 			DPRINTF("netbe_recv() returned %zd", len);
8819e749f25SAlexander Motin 			goto done;
8829e749f25SAlexander Motin 		}
8839e749f25SAlexander Motin 
8849e749f25SAlexander Motin 		/*
8859e749f25SAlexander Motin 		 * Adjust the packet length based on whether the CRC needs
8869e749f25SAlexander Motin 		 * to be stripped or if the packet is less than the minimum
8879e749f25SAlexander Motin 		 * eth packet size.
8889e749f25SAlexander Motin 		 */
8899e749f25SAlexander Motin 		if (len < ETHER_MIN_LEN - ETHER_CRC_LEN)
8909e749f25SAlexander Motin 			len = ETHER_MIN_LEN - ETHER_CRC_LEN;
8919e749f25SAlexander Motin 		if (!(sc->esc_RCTL & E1000_RCTL_SECRC))
8929e749f25SAlexander Motin 			len += ETHER_CRC_LEN;
8939e749f25SAlexander Motin 		n = (len + bufsz - 1) / bufsz;
8949e749f25SAlexander Motin 
895cea34d07SMark Johnston 		DPRINTF("packet read %zd bytes, %d segs, head %d",
8969e749f25SAlexander Motin 		    len, n, head);
8979e749f25SAlexander Motin 
8989e749f25SAlexander Motin 		/* Apply VLAN filter. */
8999e749f25SAlexander Motin 		tp = (uint16_t *)vec[0].iov_base + 6;
9009e749f25SAlexander Motin 		if ((sc->esc_RCTL & E1000_RCTL_VFE) &&
9019e749f25SAlexander Motin 		    (ntohs(tp[0]) == sc->esc_VET)) {
9029e749f25SAlexander Motin 			tag = ntohs(tp[1]) & 0x0fff;
9039e749f25SAlexander Motin 			if ((sc->esc_fvlan[tag >> 5] &
9049e749f25SAlexander Motin 			    (1 << (tag & 0x1f))) != 0) {
905332eff95SVincenzo Maffione 				DPRINTF("known VLAN %d", tag);
9069e749f25SAlexander Motin 			} else {
907332eff95SVincenzo Maffione 				DPRINTF("unknown VLAN %d", tag);
9089e749f25SAlexander Motin 				n = 0;
9099e749f25SAlexander Motin 				continue;
9109e749f25SAlexander Motin 			}
9119e749f25SAlexander Motin 		}
9129e749f25SAlexander Motin 
9139e749f25SAlexander Motin 		/* Update all consumed descriptors. */
9149e749f25SAlexander Motin 		for (i = 0; i < n - 1; i++) {
9159e749f25SAlexander Motin 			rxd = &sc->esc_rxdesc[(head + i) % size];
9169e749f25SAlexander Motin 			rxd->length = bufsz;
9179e749f25SAlexander Motin 			rxd->csum = 0;
9189e749f25SAlexander Motin 			rxd->errors = 0;
9199e749f25SAlexander Motin 			rxd->special = 0;
9209e749f25SAlexander Motin 			rxd->status = E1000_RXD_STAT_DD;
9219e749f25SAlexander Motin 		}
9229e749f25SAlexander Motin 		rxd = &sc->esc_rxdesc[(head + i) % size];
9239e749f25SAlexander Motin 		rxd->length = len % bufsz;
9249e749f25SAlexander Motin 		rxd->csum = 0;
9259e749f25SAlexander Motin 		rxd->errors = 0;
9269e749f25SAlexander Motin 		rxd->special = 0;
9279e749f25SAlexander Motin 		/* XXX signal no checksum for now */
9289e749f25SAlexander Motin 		rxd->status = E1000_RXD_STAT_PIF | E1000_RXD_STAT_IXSM |
9299e749f25SAlexander Motin 		    E1000_RXD_STAT_EOP | E1000_RXD_STAT_DD;
9309e749f25SAlexander Motin 
9319e749f25SAlexander Motin 		/* Schedule receive interrupts. */
932cea34d07SMark Johnston 		if ((uint32_t)len <= sc->esc_RSRPD) {
9339e749f25SAlexander Motin 			cause |= E1000_ICR_SRPD | E1000_ICR_RXT0;
9349e749f25SAlexander Motin 		} else {
9359e749f25SAlexander Motin 			/* XXX: RDRT and RADV timers should be here. */
9369e749f25SAlexander Motin 			cause |= E1000_ICR_RXT0;
9379e749f25SAlexander Motin 		}
9389e749f25SAlexander Motin 
9399e749f25SAlexander Motin 		head = (head + n) % size;
9409e749f25SAlexander Motin 		left -= n;
9419e749f25SAlexander Motin 	}
9429e749f25SAlexander Motin 
9439e749f25SAlexander Motin done:
9449e749f25SAlexander Motin 	pthread_mutex_lock(&sc->esc_mtx);
9459e749f25SAlexander Motin 	sc->esc_rx_active = 0;
9469e749f25SAlexander Motin 	if (sc->esc_rx_enabled == 0)
9479e749f25SAlexander Motin 		pthread_cond_signal(&sc->esc_rx_cond);
9489e749f25SAlexander Motin 
9499e749f25SAlexander Motin 	sc->esc_RDH = head;
9509e749f25SAlexander Motin 	/* Respect E1000_RCTL_RDMTS */
9519e749f25SAlexander Motin 	left = (size + sc->esc_RDT - head) % size;
9529e749f25SAlexander Motin 	if (left < (size >> (((sc->esc_RCTL >> 8) & 3) + 1)))
9539e749f25SAlexander Motin 		cause |= E1000_ICR_RXDMT0;
9549e749f25SAlexander Motin 	/* Assert all accumulated interrupts. */
9559e749f25SAlexander Motin 	if (cause != 0)
9569e749f25SAlexander Motin 		e82545_icr_assert(sc, cause);
9579e749f25SAlexander Motin done1:
958332eff95SVincenzo Maffione 	DPRINTF("rx_run done: head %x, tail %x", sc->esc_RDH, sc->esc_RDT);
9599e749f25SAlexander Motin 	pthread_mutex_unlock(&sc->esc_mtx);
9609e749f25SAlexander Motin }
9619e749f25SAlexander Motin 
9629e749f25SAlexander Motin static uint16_t
e82545_carry(uint32_t sum)9639e749f25SAlexander Motin e82545_carry(uint32_t sum)
9649e749f25SAlexander Motin {
9659e749f25SAlexander Motin 
9669e749f25SAlexander Motin 	sum = (sum & 0xFFFF) + (sum >> 16);
9679e749f25SAlexander Motin 	if (sum > 0xFFFF)
9689e749f25SAlexander Motin 		sum -= 0xFFFF;
9699e749f25SAlexander Motin 	return (sum);
9709e749f25SAlexander Motin }
9719e749f25SAlexander Motin 
9729e749f25SAlexander Motin static uint16_t
e82545_buf_checksum(uint8_t * buf,int len)9739e749f25SAlexander Motin e82545_buf_checksum(uint8_t *buf, int len)
9749e749f25SAlexander Motin {
9759e749f25SAlexander Motin 	int i;
9769e749f25SAlexander Motin 	uint32_t sum = 0;
9779e749f25SAlexander Motin 
9789e749f25SAlexander Motin 	/* Checksum all the pairs of bytes first... */
979cea34d07SMark Johnston 	for (i = 0; i < (len & ~1); i += 2)
9809e749f25SAlexander Motin 		sum += *((u_int16_t *)(buf + i));
9819e749f25SAlexander Motin 
9829e749f25SAlexander Motin 	/*
9839e749f25SAlexander Motin 	 * If there's a single byte left over, checksum it, too.
9849e749f25SAlexander Motin 	 * Network byte order is big-endian, so the remaining byte is
9859e749f25SAlexander Motin 	 * the high byte.
9869e749f25SAlexander Motin 	 */
9879e749f25SAlexander Motin 	if (i < len)
9889e749f25SAlexander Motin 		sum += htons(buf[i] << 8);
9899e749f25SAlexander Motin 
9909e749f25SAlexander Motin 	return (e82545_carry(sum));
9919e749f25SAlexander Motin }
9929e749f25SAlexander Motin 
9939e749f25SAlexander Motin static uint16_t
e82545_iov_checksum(struct iovec * iov,int iovcnt,unsigned int off,unsigned int len)994cea34d07SMark Johnston e82545_iov_checksum(struct iovec *iov, int iovcnt, unsigned int off,
995cea34d07SMark Johnston     unsigned int len)
9969e749f25SAlexander Motin {
997cea34d07SMark Johnston 	unsigned int now, odd;
9989e749f25SAlexander Motin 	uint32_t sum = 0, s;
9999e749f25SAlexander Motin 
10009e749f25SAlexander Motin 	/* Skip completely unneeded vectors. */
10019e749f25SAlexander Motin 	while (iovcnt > 0 && iov->iov_len <= off && off > 0) {
10029e749f25SAlexander Motin 		off -= iov->iov_len;
10039e749f25SAlexander Motin 		iov++;
10049e749f25SAlexander Motin 		iovcnt--;
10059e749f25SAlexander Motin 	}
10069e749f25SAlexander Motin 
10079e749f25SAlexander Motin 	/* Calculate checksum of requested range. */
10089e749f25SAlexander Motin 	odd = 0;
10099e749f25SAlexander Motin 	while (len > 0 && iovcnt > 0) {
10109e749f25SAlexander Motin 		now = MIN(len, iov->iov_len - off);
101163898728SMark Johnston 		s = e82545_buf_checksum((uint8_t *)iov->iov_base + off, now);
10129e749f25SAlexander Motin 		sum += odd ? (s << 8) : s;
10139e749f25SAlexander Motin 		odd ^= (now & 1);
10149e749f25SAlexander Motin 		len -= now;
10159e749f25SAlexander Motin 		off = 0;
10169e749f25SAlexander Motin 		iov++;
10179e749f25SAlexander Motin 		iovcnt--;
10189e749f25SAlexander Motin 	}
10199e749f25SAlexander Motin 
10209e749f25SAlexander Motin 	return (e82545_carry(sum));
10219e749f25SAlexander Motin }
10229e749f25SAlexander Motin 
10239e749f25SAlexander Motin /*
10249e749f25SAlexander Motin  * Return the transmit descriptor type.
10259e749f25SAlexander Motin  */
102637045dfaSMark Johnston static int
e82545_txdesc_type(uint32_t lower)10279e749f25SAlexander Motin e82545_txdesc_type(uint32_t lower)
10289e749f25SAlexander Motin {
10299e749f25SAlexander Motin 	int type;
10309e749f25SAlexander Motin 
10319e749f25SAlexander Motin 	type = 0;
10329e749f25SAlexander Motin 
10339e749f25SAlexander Motin 	if (lower & E1000_TXD_CMD_DEXT)
10349e749f25SAlexander Motin 		type = lower & E1000_TXD_MASK;
10359e749f25SAlexander Motin 
10369e749f25SAlexander Motin 	return (type);
10379e749f25SAlexander Motin }
10389e749f25SAlexander Motin 
10399e749f25SAlexander Motin static void
e82545_transmit_checksum(struct iovec * iov,int iovcnt,struct ck_info * ck)10409e749f25SAlexander Motin e82545_transmit_checksum(struct iovec *iov, int iovcnt, struct ck_info *ck)
10419e749f25SAlexander Motin {
10429e749f25SAlexander Motin 	uint16_t cksum;
1043cea34d07SMark Johnston 	unsigned int cklen;
10449e749f25SAlexander Motin 
1045332eff95SVincenzo Maffione 	DPRINTF("tx cksum: iovcnt/s/off/len %d/%d/%d/%d",
10469e749f25SAlexander Motin 	    iovcnt, ck->ck_start, ck->ck_off, ck->ck_len);
1047e7cd5fffSJohn Baldwin 	cklen = ck->ck_len ? ck->ck_len - ck->ck_start + 1U : UINT_MAX;
10489e749f25SAlexander Motin 	cksum = e82545_iov_checksum(iov, iovcnt, ck->ck_start, cklen);
10499e749f25SAlexander Motin 	*(uint16_t *)((uint8_t *)iov[0].iov_base + ck->ck_off) = ~cksum;
10509e749f25SAlexander Motin }
10519e749f25SAlexander Motin 
10529e749f25SAlexander Motin static void
e82545_transmit_backend(struct e82545_softc * sc,struct iovec * iov,int iovcnt)10539e749f25SAlexander Motin e82545_transmit_backend(struct e82545_softc *sc, struct iovec *iov, int iovcnt)
10549e749f25SAlexander Motin {
10559e749f25SAlexander Motin 
10560ff7076bSVincenzo Maffione 	if (sc->esc_be == NULL)
10579e749f25SAlexander Motin 		return;
10589e749f25SAlexander Motin 
10590ff7076bSVincenzo Maffione 	(void) netbe_send(sc->esc_be, iov, iovcnt);
10609e749f25SAlexander Motin }
10619e749f25SAlexander Motin 
10629e749f25SAlexander Motin static void
e82545_transmit_done(struct e82545_softc * sc,uint16_t head,uint16_t tail,uint16_t dsize,int * tdwb)1063ee7230f4SAlexander Motin e82545_transmit_done(struct e82545_softc *sc, uint16_t head, uint16_t tail,
1064ee7230f4SAlexander Motin     uint16_t dsize, int *tdwb)
10659e749f25SAlexander Motin {
1066ee7230f4SAlexander Motin 	union e1000_tx_udesc *dsc;
10679e749f25SAlexander Motin 
1068ee7230f4SAlexander Motin 	for ( ; head != tail; head = (head + 1) % dsize) {
1069ee7230f4SAlexander Motin 		dsc = &sc->esc_txdesc[head];
1070ee7230f4SAlexander Motin 		if (dsc->td.lower.data & E1000_TXD_CMD_RS) {
1071ee7230f4SAlexander Motin 			dsc->td.upper.data |= E1000_TXD_STAT_DD;
1072ee7230f4SAlexander Motin 			*tdwb = 1;
1073ee7230f4SAlexander Motin 		}
1074ee7230f4SAlexander Motin 	}
10759e749f25SAlexander Motin }
10769e749f25SAlexander Motin 
10779e749f25SAlexander Motin static int
e82545_transmit(struct e82545_softc * sc,uint16_t head,uint16_t tail,uint16_t dsize,uint16_t * rhead,int * tdwb)10789e749f25SAlexander Motin e82545_transmit(struct e82545_softc *sc, uint16_t head, uint16_t tail,
10799e749f25SAlexander Motin     uint16_t dsize, uint16_t *rhead, int *tdwb)
10809e749f25SAlexander Motin {
10819e749f25SAlexander Motin 	uint8_t *hdr, *hdrp;
10829e749f25SAlexander Motin 	struct iovec iovb[I82545_MAX_TXSEGS + 2];
10839e749f25SAlexander Motin 	struct iovec tiov[I82545_MAX_TXSEGS + 2];
10849e749f25SAlexander Motin 	struct e1000_context_desc *cd;
10859e749f25SAlexander Motin 	struct ck_info ckinfo[2];
10869e749f25SAlexander Motin 	struct iovec *iov;
10879e749f25SAlexander Motin 	union  e1000_tx_udesc *dsc;
1088cea34d07SMark Johnston 	int desc, dtype, ntype, iovcnt, tcp, tso, paylen, seg, tiovcnt, pv;
1089cea34d07SMark Johnston 	unsigned hdrlen, vlen, pktlen, len, left, mss, now, nnow, nleft, pvoff;
10909e749f25SAlexander Motin 	uint32_t tcpsum, tcpseq;
1091ee7230f4SAlexander Motin 	uint16_t ipcs, tcpcs, ipid, ohead;
1092fa46f370SJohn Baldwin 	bool invalid;
10939e749f25SAlexander Motin 
10949e749f25SAlexander Motin 	ckinfo[0].ck_valid = ckinfo[1].ck_valid = 0;
10959e749f25SAlexander Motin 	iovcnt = 0;
10969e749f25SAlexander Motin 	ntype = 0;
10979e749f25SAlexander Motin 	tso = 0;
1098fa46f370SJohn Baldwin 	pktlen = 0;
1099ee7230f4SAlexander Motin 	ohead = head;
1100fa46f370SJohn Baldwin 	invalid = false;
11019e749f25SAlexander Motin 
11029e749f25SAlexander Motin 	/* iovb[0/1] may be used for writable copy of headers. */
11039e749f25SAlexander Motin 	iov = &iovb[2];
11049e749f25SAlexander Motin 
11059e749f25SAlexander Motin 	for (desc = 0; ; desc++, head = (head + 1) % dsize) {
11069e749f25SAlexander Motin 		if (head == tail) {
11079e749f25SAlexander Motin 			*rhead = head;
11089e749f25SAlexander Motin 			return (0);
11099e749f25SAlexander Motin 		}
11109e749f25SAlexander Motin 		dsc = &sc->esc_txdesc[head];
11119e749f25SAlexander Motin 		dtype = e82545_txdesc_type(dsc->td.lower.data);
11129e749f25SAlexander Motin 
11139e749f25SAlexander Motin 		if (desc == 0) {
11149e749f25SAlexander Motin 			switch (dtype) {
11159e749f25SAlexander Motin 			case E1000_TXD_TYP_C:
11169e749f25SAlexander Motin 				DPRINTF("tx ctxt desc idx %d: %016jx "
1117332eff95SVincenzo Maffione 				    "%08x%08x",
11189e749f25SAlexander Motin 				    head, dsc->td.buffer_addr,
11199e749f25SAlexander Motin 				    dsc->td.upper.data, dsc->td.lower.data);
11209e749f25SAlexander Motin 				/* Save context and return */
11219e749f25SAlexander Motin 				sc->esc_txctx = dsc->cd;
1122ee7230f4SAlexander Motin 				goto done;
11239e749f25SAlexander Motin 			case E1000_TXD_TYP_L:
1124332eff95SVincenzo Maffione 				DPRINTF("tx legacy desc idx %d: %08x%08x",
11259e749f25SAlexander Motin 				    head, dsc->td.upper.data, dsc->td.lower.data);
11269e749f25SAlexander Motin 				/*
11279e749f25SAlexander Motin 				 * legacy cksum start valid in first descriptor
11289e749f25SAlexander Motin 				 */
11299e749f25SAlexander Motin 				ntype = dtype;
11309e749f25SAlexander Motin 				ckinfo[0].ck_start = dsc->td.upper.fields.css;
11319e749f25SAlexander Motin 				break;
11329e749f25SAlexander Motin 			case E1000_TXD_TYP_D:
1133332eff95SVincenzo Maffione 				DPRINTF("tx data desc idx %d: %08x%08x",
11349e749f25SAlexander Motin 				    head, dsc->td.upper.data, dsc->td.lower.data);
11359e749f25SAlexander Motin 				ntype = dtype;
11369e749f25SAlexander Motin 				break;
11379e749f25SAlexander Motin 			default:
11389e749f25SAlexander Motin 				break;
11399e749f25SAlexander Motin 			}
11409e749f25SAlexander Motin 		} else {
11419e749f25SAlexander Motin 			/* Descriptor type must be consistent */
11429e749f25SAlexander Motin 			assert(dtype == ntype);
1143332eff95SVincenzo Maffione 			DPRINTF("tx next desc idx %d: %08x%08x",
11449e749f25SAlexander Motin 			    head, dsc->td.upper.data, dsc->td.lower.data);
11459e749f25SAlexander Motin 		}
11469e749f25SAlexander Motin 
11479e749f25SAlexander Motin 		len = (dtype == E1000_TXD_TYP_L) ? dsc->td.lower.flags.length :
11489e749f25SAlexander Motin 		    dsc->dd.lower.data & 0xFFFFF;
11499e749f25SAlexander Motin 
11509e749f25SAlexander Motin 		/* Strip checksum supplied by guest. */
11519e749f25SAlexander Motin 		if ((dsc->td.lower.data & E1000_TXD_CMD_EOP) != 0 &&
1152fa46f370SJohn Baldwin 		    (dsc->td.lower.data & E1000_TXD_CMD_IFCS) == 0) {
1153fa46f370SJohn Baldwin 			if (len <= 2) {
1154fa46f370SJohn Baldwin 				WPRINTF("final descriptor too short (%d) -- dropped",
1155fa46f370SJohn Baldwin 				    len);
1156fa46f370SJohn Baldwin 				invalid = true;
1157fa46f370SJohn Baldwin 			} else
11589e749f25SAlexander Motin 				len -= 2;
1159ee7230f4SAlexander Motin 		}
1160fa46f370SJohn Baldwin 
1161fa46f370SJohn Baldwin 		if (len > 0 && iovcnt < I82545_MAX_TXSEGS) {
1162fa46f370SJohn Baldwin 			iov[iovcnt].iov_base = paddr_guest2host(sc->esc_ctx,
1163fa46f370SJohn Baldwin 			    dsc->td.buffer_addr, len);
1164fa46f370SJohn Baldwin 			iov[iovcnt].iov_len = len;
11659e749f25SAlexander Motin 			iovcnt++;
1166fa46f370SJohn Baldwin 			pktlen += len;
11679e749f25SAlexander Motin 		}
11689e749f25SAlexander Motin 
11699e749f25SAlexander Motin 		/*
11709e749f25SAlexander Motin 		 * Pull out info that is valid in the final descriptor
11719e749f25SAlexander Motin 		 * and exit descriptor loop.
11729e749f25SAlexander Motin 		 */
11739e749f25SAlexander Motin 		if (dsc->td.lower.data & E1000_TXD_CMD_EOP) {
11749e749f25SAlexander Motin 			if (dtype == E1000_TXD_TYP_L) {
11759e749f25SAlexander Motin 				if (dsc->td.lower.data & E1000_TXD_CMD_IC) {
11769e749f25SAlexander Motin 					ckinfo[0].ck_valid = 1;
11779e749f25SAlexander Motin 					ckinfo[0].ck_off =
11789e749f25SAlexander Motin 					    dsc->td.lower.flags.cso;
11799e749f25SAlexander Motin 					ckinfo[0].ck_len = 0;
11809e749f25SAlexander Motin 				}
11819e749f25SAlexander Motin 			} else {
11829e749f25SAlexander Motin 				cd = &sc->esc_txctx;
11839e749f25SAlexander Motin 				if (dsc->dd.lower.data & E1000_TXD_CMD_TSE)
11849e749f25SAlexander Motin 					tso = 1;
11859e749f25SAlexander Motin 				if (dsc->dd.upper.fields.popts &
11869e749f25SAlexander Motin 				    E1000_TXD_POPTS_IXSM)
11879e749f25SAlexander Motin 					ckinfo[0].ck_valid = 1;
11889e749f25SAlexander Motin 				if (dsc->dd.upper.fields.popts &
11899e749f25SAlexander Motin 				    E1000_TXD_POPTS_IXSM || tso) {
11909e749f25SAlexander Motin 					ckinfo[0].ck_start =
11919e749f25SAlexander Motin 					    cd->lower_setup.ip_fields.ipcss;
11929e749f25SAlexander Motin 					ckinfo[0].ck_off =
11939e749f25SAlexander Motin 					    cd->lower_setup.ip_fields.ipcso;
11949e749f25SAlexander Motin 					ckinfo[0].ck_len =
11959e749f25SAlexander Motin 					    cd->lower_setup.ip_fields.ipcse;
11969e749f25SAlexander Motin 				}
11979e749f25SAlexander Motin 				if (dsc->dd.upper.fields.popts &
11989e749f25SAlexander Motin 				    E1000_TXD_POPTS_TXSM)
11999e749f25SAlexander Motin 					ckinfo[1].ck_valid = 1;
12009e749f25SAlexander Motin 				if (dsc->dd.upper.fields.popts &
12019e749f25SAlexander Motin 				    E1000_TXD_POPTS_TXSM || tso) {
12029e749f25SAlexander Motin 					ckinfo[1].ck_start =
12039e749f25SAlexander Motin 					    cd->upper_setup.tcp_fields.tucss;
12049e749f25SAlexander Motin 					ckinfo[1].ck_off =
12059e749f25SAlexander Motin 					    cd->upper_setup.tcp_fields.tucso;
12069e749f25SAlexander Motin 					ckinfo[1].ck_len =
12079e749f25SAlexander Motin 					    cd->upper_setup.tcp_fields.tucse;
12089e749f25SAlexander Motin 				}
12099e749f25SAlexander Motin 			}
12109e749f25SAlexander Motin 			break;
12119e749f25SAlexander Motin 		}
12129e749f25SAlexander Motin 	}
12139e749f25SAlexander Motin 
1214fa46f370SJohn Baldwin 	if (invalid)
1215fa46f370SJohn Baldwin 		goto done;
1216fa46f370SJohn Baldwin 
1217ee7230f4SAlexander Motin 	if (iovcnt > I82545_MAX_TXSEGS) {
1218332eff95SVincenzo Maffione 		WPRINTF("tx too many descriptors (%d > %d) -- dropped",
1219ee7230f4SAlexander Motin 		    iovcnt, I82545_MAX_TXSEGS);
1220ee7230f4SAlexander Motin 		goto done;
1221ee7230f4SAlexander Motin 	}
1222ee7230f4SAlexander Motin 
12239e749f25SAlexander Motin 	hdrlen = vlen = 0;
12249e749f25SAlexander Motin 	/* Estimate writable space for VLAN header insertion. */
12259e749f25SAlexander Motin 	if ((sc->esc_CTRL & E1000_CTRL_VME) &&
12269e749f25SAlexander Motin 	    (dsc->td.lower.data & E1000_TXD_CMD_VLE)) {
12279e749f25SAlexander Motin 		hdrlen = ETHER_ADDR_LEN*2;
12289e749f25SAlexander Motin 		vlen = ETHER_VLAN_ENCAP_LEN;
12299e749f25SAlexander Motin 	}
12309e749f25SAlexander Motin 	if (!tso) {
12319e749f25SAlexander Motin 		/* Estimate required writable space for checksums. */
12329e749f25SAlexander Motin 		if (ckinfo[0].ck_valid)
1233e7cd5fffSJohn Baldwin 			hdrlen = MAX(hdrlen, ckinfo[0].ck_off + 2U);
12349e749f25SAlexander Motin 		if (ckinfo[1].ck_valid)
1235e7cd5fffSJohn Baldwin 			hdrlen = MAX(hdrlen, ckinfo[1].ck_off + 2U);
12369e749f25SAlexander Motin 		/* Round up writable space to the first vector. */
12379e749f25SAlexander Motin 		if (hdrlen != 0 && iov[0].iov_len > hdrlen &&
12389e749f25SAlexander Motin 		    iov[0].iov_len < hdrlen + 100)
12399e749f25SAlexander Motin 			hdrlen = iov[0].iov_len;
12409e749f25SAlexander Motin 	} else {
12419e749f25SAlexander Motin 		/* In case of TSO header length provided by software. */
12429e749f25SAlexander Motin 		hdrlen = sc->esc_txctx.tcp_seg_setup.fields.hdr_len;
1243ed9ffd2fSJohn Baldwin 
1244ed9ffd2fSJohn Baldwin 		/*
1245ed9ffd2fSJohn Baldwin 		 * Cap the header length at 240 based on 7.2.4.5 of
1246ed9ffd2fSJohn Baldwin 		 * the Intel 82576EB (Rev 2.63) datasheet.
1247ed9ffd2fSJohn Baldwin 		 */
1248ed9ffd2fSJohn Baldwin 		if (hdrlen > 240) {
1249332eff95SVincenzo Maffione 			WPRINTF("TSO hdrlen too large: %d", hdrlen);
1250ed9ffd2fSJohn Baldwin 			goto done;
1251ed9ffd2fSJohn Baldwin 		}
1252ed9ffd2fSJohn Baldwin 
1253ed9ffd2fSJohn Baldwin 		/*
1254ed9ffd2fSJohn Baldwin 		 * If VLAN insertion is requested, ensure the header
1255ed9ffd2fSJohn Baldwin 		 * at least holds the amount of data copied during
1256ed9ffd2fSJohn Baldwin 		 * VLAN insertion below.
1257ed9ffd2fSJohn Baldwin 		 *
1258ed9ffd2fSJohn Baldwin 		 * XXX: Realistic packets will include a full Ethernet
1259ed9ffd2fSJohn Baldwin 		 * header before the IP header at ckinfo[0].ck_start,
1260ed9ffd2fSJohn Baldwin 		 * but this check is sufficient to prevent
1261ed9ffd2fSJohn Baldwin 		 * out-of-bounds access below.
1262ed9ffd2fSJohn Baldwin 		 */
1263ed9ffd2fSJohn Baldwin 		if (vlen != 0 && hdrlen < ETHER_ADDR_LEN*2) {
1264ed9ffd2fSJohn Baldwin 			WPRINTF("TSO hdrlen too small for vlan insertion "
1265332eff95SVincenzo Maffione 			    "(%d vs %d) -- dropped", hdrlen,
1266ed9ffd2fSJohn Baldwin 			    ETHER_ADDR_LEN*2);
1267ed9ffd2fSJohn Baldwin 			goto done;
1268ed9ffd2fSJohn Baldwin 		}
1269ed9ffd2fSJohn Baldwin 
1270ed9ffd2fSJohn Baldwin 		/*
1271ed9ffd2fSJohn Baldwin 		 * Ensure that the header length covers the used fields
1272ed9ffd2fSJohn Baldwin 		 * in the IP and TCP headers as well as the IP and TCP
1273ed9ffd2fSJohn Baldwin 		 * checksums.  The following fields are accessed below:
1274ed9ffd2fSJohn Baldwin 		 *
1275ed9ffd2fSJohn Baldwin 		 * Header | Field | Offset | Length
1276ed9ffd2fSJohn Baldwin 		 * -------+-------+--------+-------
1277ed9ffd2fSJohn Baldwin 		 * IPv4   | len   | 2      | 2
1278ed9ffd2fSJohn Baldwin 		 * IPv4   | ID    | 4      | 2
1279ed9ffd2fSJohn Baldwin 		 * IPv6   | len   | 4      | 2
1280ed9ffd2fSJohn Baldwin 		 * TCP    | seq # | 4      | 4
1281ed9ffd2fSJohn Baldwin 		 * TCP    | flags | 13     | 1
1282ed9ffd2fSJohn Baldwin 		 * UDP    | len   | 4      | 4
1283ed9ffd2fSJohn Baldwin 		 */
1284e7cd5fffSJohn Baldwin 		if (hdrlen < ckinfo[0].ck_start + 6U ||
1285e7cd5fffSJohn Baldwin 		    hdrlen < ckinfo[0].ck_off + 2U) {
1286ed9ffd2fSJohn Baldwin 			WPRINTF("TSO hdrlen too small for IP fields (%d) "
1287332eff95SVincenzo Maffione 			    "-- dropped", hdrlen);
1288ed9ffd2fSJohn Baldwin 			goto done;
1289ed9ffd2fSJohn Baldwin 		}
1290ed9ffd2fSJohn Baldwin 		if (sc->esc_txctx.cmd_and_length & E1000_TXD_CMD_TCP) {
1291e7cd5fffSJohn Baldwin 			if (hdrlen < ckinfo[1].ck_start + 14U) {
1292ed9ffd2fSJohn Baldwin 				WPRINTF("TSO hdrlen too small for TCP fields "
1293332eff95SVincenzo Maffione 				    "(%d) -- dropped", hdrlen);
1294ed9ffd2fSJohn Baldwin 				goto done;
1295ed9ffd2fSJohn Baldwin 			}
1296ed9ffd2fSJohn Baldwin 		} else {
1297e7cd5fffSJohn Baldwin 			if (hdrlen < ckinfo[1].ck_start + 8U) {
1298ed9ffd2fSJohn Baldwin 				WPRINTF("TSO hdrlen too small for UDP fields "
1299332eff95SVincenzo Maffione 				    "(%d) -- dropped", hdrlen);
1300ed9ffd2fSJohn Baldwin 				goto done;
1301ed9ffd2fSJohn Baldwin 			}
1302ed9ffd2fSJohn Baldwin 		}
1303e7cd5fffSJohn Baldwin 		if (ckinfo[1].ck_valid && hdrlen < ckinfo[1].ck_off + 2U) {
1304b0aa20beSMark Johnston 			WPRINTF("TSO hdrlen too small for TCP/UDP fields "
1305b0aa20beSMark Johnston 			    "(%d) -- dropped", hdrlen);
1306b0aa20beSMark Johnston 			goto done;
1307b0aa20beSMark Johnston 		}
13089e749f25SAlexander Motin 	}
13099e749f25SAlexander Motin 
1310fa46f370SJohn Baldwin 	if (pktlen < hdrlen + vlen) {
1311fa46f370SJohn Baldwin 		WPRINTF("packet too small for writable header");
1312fa46f370SJohn Baldwin 		goto done;
1313fa46f370SJohn Baldwin 	}
1314fa46f370SJohn Baldwin 
13159e749f25SAlexander Motin 	/* Allocate, fill and prepend writable header vector. */
1316fa46f370SJohn Baldwin 	if (hdrlen + vlen != 0) {
13179e749f25SAlexander Motin 		hdr = __builtin_alloca(hdrlen + vlen);
13189e749f25SAlexander Motin 		hdr += vlen;
13199e749f25SAlexander Motin 		for (left = hdrlen, hdrp = hdr; left > 0;
13209e749f25SAlexander Motin 		    left -= now, hdrp += now) {
13219e749f25SAlexander Motin 			now = MIN(left, iov->iov_len);
13229e749f25SAlexander Motin 			memcpy(hdrp, iov->iov_base, now);
132363898728SMark Johnston 			iov->iov_base = (uint8_t *)iov->iov_base + now;
13249e749f25SAlexander Motin 			iov->iov_len -= now;
13259e749f25SAlexander Motin 			if (iov->iov_len == 0) {
13269e749f25SAlexander Motin 				iov++;
13279e749f25SAlexander Motin 				iovcnt--;
13289e749f25SAlexander Motin 			}
13299e749f25SAlexander Motin 		}
13309e749f25SAlexander Motin 		iov--;
13319e749f25SAlexander Motin 		iovcnt++;
13329e749f25SAlexander Motin 		iov->iov_base = hdr;
13339e749f25SAlexander Motin 		iov->iov_len = hdrlen;
1334ed9ffd2fSJohn Baldwin 	} else
1335ed9ffd2fSJohn Baldwin 		hdr = NULL;
13369e749f25SAlexander Motin 
13379e749f25SAlexander Motin 	/* Insert VLAN tag. */
13389e749f25SAlexander Motin 	if (vlen != 0) {
13399e749f25SAlexander Motin 		hdr -= ETHER_VLAN_ENCAP_LEN;
13409e749f25SAlexander Motin 		memmove(hdr, hdr + ETHER_VLAN_ENCAP_LEN, ETHER_ADDR_LEN*2);
13419e749f25SAlexander Motin 		hdrlen += ETHER_VLAN_ENCAP_LEN;
13429e749f25SAlexander Motin 		hdr[ETHER_ADDR_LEN*2 + 0] = sc->esc_VET >> 8;
13439e749f25SAlexander Motin 		hdr[ETHER_ADDR_LEN*2 + 1] = sc->esc_VET & 0xff;
13449e749f25SAlexander Motin 		hdr[ETHER_ADDR_LEN*2 + 2] = dsc->td.upper.fields.special >> 8;
13459e749f25SAlexander Motin 		hdr[ETHER_ADDR_LEN*2 + 3] = dsc->td.upper.fields.special & 0xff;
13469e749f25SAlexander Motin 		iov->iov_base = hdr;
13479e749f25SAlexander Motin 		iov->iov_len += ETHER_VLAN_ENCAP_LEN;
13489e749f25SAlexander Motin 		/* Correct checksum offsets after VLAN tag insertion. */
13499e749f25SAlexander Motin 		ckinfo[0].ck_start += ETHER_VLAN_ENCAP_LEN;
13509e749f25SAlexander Motin 		ckinfo[0].ck_off += ETHER_VLAN_ENCAP_LEN;
13519e749f25SAlexander Motin 		if (ckinfo[0].ck_len != 0)
13529e749f25SAlexander Motin 			ckinfo[0].ck_len += ETHER_VLAN_ENCAP_LEN;
13539e749f25SAlexander Motin 		ckinfo[1].ck_start += ETHER_VLAN_ENCAP_LEN;
13549e749f25SAlexander Motin 		ckinfo[1].ck_off += ETHER_VLAN_ENCAP_LEN;
13559e749f25SAlexander Motin 		if (ckinfo[1].ck_len != 0)
13569e749f25SAlexander Motin 			ckinfo[1].ck_len += ETHER_VLAN_ENCAP_LEN;
13579e749f25SAlexander Motin 	}
13589e749f25SAlexander Motin 
13599e749f25SAlexander Motin 	/* Simple non-TSO case. */
13609e749f25SAlexander Motin 	if (!tso) {
13619e749f25SAlexander Motin 		/* Calculate checksums and transmit. */
13629e749f25SAlexander Motin 		if (ckinfo[0].ck_valid)
13639e749f25SAlexander Motin 			e82545_transmit_checksum(iov, iovcnt, &ckinfo[0]);
13649e749f25SAlexander Motin 		if (ckinfo[1].ck_valid)
13659e749f25SAlexander Motin 			e82545_transmit_checksum(iov, iovcnt, &ckinfo[1]);
13669e749f25SAlexander Motin 		e82545_transmit_backend(sc, iov, iovcnt);
13679e749f25SAlexander Motin 		goto done;
13689e749f25SAlexander Motin 	}
13699e749f25SAlexander Motin 
13709e749f25SAlexander Motin 	/* Doing TSO. */
13719e749f25SAlexander Motin 	tcp = (sc->esc_txctx.cmd_and_length & E1000_TXD_CMD_TCP) != 0;
13729e749f25SAlexander Motin 	mss = sc->esc_txctx.tcp_seg_setup.fields.mss;
13739e749f25SAlexander Motin 	paylen = (sc->esc_txctx.cmd_and_length & 0x000fffff);
1374cea34d07SMark Johnston 	DPRINTF("tx %s segmentation offload %d+%d/%u bytes %d iovs",
13759e749f25SAlexander Motin 	    tcp ? "TCP" : "UDP", hdrlen, paylen, mss, iovcnt);
13769e749f25SAlexander Motin 	ipid = ntohs(*(uint16_t *)&hdr[ckinfo[0].ck_start + 4]);
1377ed9ffd2fSJohn Baldwin 	tcpseq = 0;
1378ed9ffd2fSJohn Baldwin 	if (tcp)
13799e749f25SAlexander Motin 		tcpseq = ntohl(*(uint32_t *)&hdr[ckinfo[1].ck_start + 4]);
13809e749f25SAlexander Motin 	ipcs = *(uint16_t *)&hdr[ckinfo[0].ck_off];
13819e749f25SAlexander Motin 	tcpcs = 0;
13829e749f25SAlexander Motin 	if (ckinfo[1].ck_valid)	/* Save partial pseudo-header checksum. */
13839e749f25SAlexander Motin 		tcpcs = *(uint16_t *)&hdr[ckinfo[1].ck_off];
13849e749f25SAlexander Motin 	pv = 1;
13859e749f25SAlexander Motin 	pvoff = 0;
13869e749f25SAlexander Motin 	for (seg = 0, left = paylen; left > 0; seg++, left -= now) {
13879e749f25SAlexander Motin 		now = MIN(left, mss);
13889e749f25SAlexander Motin 
13899e749f25SAlexander Motin 		/* Construct IOVs for the segment. */
13909e749f25SAlexander Motin 		/* Include whole original header. */
13919e749f25SAlexander Motin 		tiov[0].iov_base = hdr;
13929e749f25SAlexander Motin 		tiov[0].iov_len = hdrlen;
13939e749f25SAlexander Motin 		tiovcnt = 1;
13949e749f25SAlexander Motin 		/* Include respective part of payload IOV. */
13959e749f25SAlexander Motin 		for (nleft = now; pv < iovcnt && nleft > 0; nleft -= nnow) {
13969e749f25SAlexander Motin 			nnow = MIN(nleft, iov[pv].iov_len - pvoff);
139703f7ccabSMark Johnston 			tiov[tiovcnt].iov_base = (uint8_t *)iov[pv].iov_base +
139803f7ccabSMark Johnston 			    pvoff;
13999e749f25SAlexander Motin 			tiov[tiovcnt++].iov_len = nnow;
14009e749f25SAlexander Motin 			if (pvoff + nnow == iov[pv].iov_len) {
14019e749f25SAlexander Motin 				pv++;
14029e749f25SAlexander Motin 				pvoff = 0;
14039e749f25SAlexander Motin 			} else
14049e749f25SAlexander Motin 				pvoff += nnow;
14059e749f25SAlexander Motin 		}
1406332eff95SVincenzo Maffione 		DPRINTF("tx segment %d %d+%d bytes %d iovs",
14079e749f25SAlexander Motin 		    seg, hdrlen, now, tiovcnt);
14089e749f25SAlexander Motin 
14099e749f25SAlexander Motin 		/* Update IP header. */
14109e749f25SAlexander Motin 		if (sc->esc_txctx.cmd_and_length & E1000_TXD_CMD_IP) {
14119e749f25SAlexander Motin 			/* IPv4 -- set length and ID */
14129e749f25SAlexander Motin 			*(uint16_t *)&hdr[ckinfo[0].ck_start + 2] =
14139e749f25SAlexander Motin 			    htons(hdrlen - ckinfo[0].ck_start + now);
14149e749f25SAlexander Motin 			*(uint16_t *)&hdr[ckinfo[0].ck_start + 4] =
14159e749f25SAlexander Motin 			    htons(ipid + seg);
14169e749f25SAlexander Motin 		} else {
14179e749f25SAlexander Motin 			/* IPv6 -- set length */
14189e749f25SAlexander Motin 			*(uint16_t *)&hdr[ckinfo[0].ck_start + 4] =
14199e749f25SAlexander Motin 			    htons(hdrlen - ckinfo[0].ck_start - 40 +
14209e749f25SAlexander Motin 				  now);
14219e749f25SAlexander Motin 		}
14229e749f25SAlexander Motin 
14239e749f25SAlexander Motin 		/* Update pseudo-header checksum. */
14249e749f25SAlexander Motin 		tcpsum = tcpcs;
14259e749f25SAlexander Motin 		tcpsum += htons(hdrlen - ckinfo[1].ck_start + now);
14269e749f25SAlexander Motin 
14279e749f25SAlexander Motin 		/* Update TCP/UDP headers. */
14289e749f25SAlexander Motin 		if (tcp) {
14299e749f25SAlexander Motin 			/* Update sequence number and FIN/PUSH flags. */
14309e749f25SAlexander Motin 			*(uint32_t *)&hdr[ckinfo[1].ck_start + 4] =
14319e749f25SAlexander Motin 			    htonl(tcpseq + paylen - left);
14329e749f25SAlexander Motin 			if (now < left) {
14339e749f25SAlexander Motin 				hdr[ckinfo[1].ck_start + 13] &=
14349e749f25SAlexander Motin 				    ~(TH_FIN | TH_PUSH);
14359e749f25SAlexander Motin 			}
14369e749f25SAlexander Motin 		} else {
14379e749f25SAlexander Motin 			/* Update payload length. */
14389e749f25SAlexander Motin 			*(uint32_t *)&hdr[ckinfo[1].ck_start + 4] =
14399e749f25SAlexander Motin 			    hdrlen - ckinfo[1].ck_start + now;
14409e749f25SAlexander Motin 		}
14419e749f25SAlexander Motin 
14429e749f25SAlexander Motin 		/* Calculate checksums and transmit. */
14439e749f25SAlexander Motin 		if (ckinfo[0].ck_valid) {
14449e749f25SAlexander Motin 			*(uint16_t *)&hdr[ckinfo[0].ck_off] = ipcs;
14459e749f25SAlexander Motin 			e82545_transmit_checksum(tiov, tiovcnt, &ckinfo[0]);
14469e749f25SAlexander Motin 		}
14479e749f25SAlexander Motin 		if (ckinfo[1].ck_valid) {
14489e749f25SAlexander Motin 			*(uint16_t *)&hdr[ckinfo[1].ck_off] =
14499e749f25SAlexander Motin 			    e82545_carry(tcpsum);
14509e749f25SAlexander Motin 			e82545_transmit_checksum(tiov, tiovcnt, &ckinfo[1]);
14519e749f25SAlexander Motin 		}
14529e749f25SAlexander Motin 		e82545_transmit_backend(sc, tiov, tiovcnt);
14539e749f25SAlexander Motin 	}
14549e749f25SAlexander Motin 
14559e749f25SAlexander Motin done:
1456ee7230f4SAlexander Motin 	head = (head + 1) % dsize;
1457ee7230f4SAlexander Motin 	e82545_transmit_done(sc, ohead, head, dsize, tdwb);
14589e749f25SAlexander Motin 
1459ee7230f4SAlexander Motin 	*rhead = head;
14609e749f25SAlexander Motin 	return (desc + 1);
14619e749f25SAlexander Motin }
14629e749f25SAlexander Motin 
14639e749f25SAlexander Motin static void
e82545_tx_run(struct e82545_softc * sc)14649e749f25SAlexander Motin e82545_tx_run(struct e82545_softc *sc)
14659e749f25SAlexander Motin {
14669e749f25SAlexander Motin 	uint32_t cause;
14679e749f25SAlexander Motin 	uint16_t head, rhead, tail, size;
14689e749f25SAlexander Motin 	int lim, tdwb, sent;
14699e749f25SAlexander Motin 
14709e749f25SAlexander Motin 	size = sc->esc_TDLEN / 16;
14717afe342dSJohn Baldwin 	if (size == 0)
14727afe342dSJohn Baldwin 		return;
14737afe342dSJohn Baldwin 
14747afe342dSJohn Baldwin 	head = sc->esc_TDH % size;
14757afe342dSJohn Baldwin 	tail = sc->esc_TDT % size;
1476332eff95SVincenzo Maffione 	DPRINTF("tx_run: head %x, rhead %x, tail %x",
14779e749f25SAlexander Motin 	    sc->esc_TDH, sc->esc_TDHr, sc->esc_TDT);
14789e749f25SAlexander Motin 
14799e749f25SAlexander Motin 	pthread_mutex_unlock(&sc->esc_mtx);
14809e749f25SAlexander Motin 	rhead = head;
14819e749f25SAlexander Motin 	tdwb = 0;
14829e749f25SAlexander Motin 	for (lim = size / 4; sc->esc_tx_enabled && lim > 0; lim -= sent) {
14839e749f25SAlexander Motin 		sent = e82545_transmit(sc, head, tail, size, &rhead, &tdwb);
14849e749f25SAlexander Motin 		if (sent == 0)
14859e749f25SAlexander Motin 			break;
14869e749f25SAlexander Motin 		head = rhead;
14879e749f25SAlexander Motin 	}
14889e749f25SAlexander Motin 	pthread_mutex_lock(&sc->esc_mtx);
14899e749f25SAlexander Motin 
14909e749f25SAlexander Motin 	sc->esc_TDH = head;
14919e749f25SAlexander Motin 	sc->esc_TDHr = rhead;
14929e749f25SAlexander Motin 	cause = 0;
14939e749f25SAlexander Motin 	if (tdwb)
14949e749f25SAlexander Motin 		cause |= E1000_ICR_TXDW;
14959e749f25SAlexander Motin 	if (lim != size / 4 && sc->esc_TDH == sc->esc_TDT)
14969e749f25SAlexander Motin 		cause |= E1000_ICR_TXQE;
14979e749f25SAlexander Motin 	if (cause)
14989e749f25SAlexander Motin 		e82545_icr_assert(sc, cause);
14999e749f25SAlexander Motin 
1500332eff95SVincenzo Maffione 	DPRINTF("tx_run done: head %x, rhead %x, tail %x",
15019e749f25SAlexander Motin 	    sc->esc_TDH, sc->esc_TDHr, sc->esc_TDT);
15029e749f25SAlexander Motin }
15039e749f25SAlexander Motin 
1504558e4950SRyan Libby static _Noreturn void *
e82545_tx_thread(void * param)15059e749f25SAlexander Motin e82545_tx_thread(void *param)
15069e749f25SAlexander Motin {
15079e749f25SAlexander Motin 	struct e82545_softc *sc = param;
15089e749f25SAlexander Motin 
15099e749f25SAlexander Motin 	pthread_mutex_lock(&sc->esc_mtx);
15109e749f25SAlexander Motin 	for (;;) {
15119e749f25SAlexander Motin 		while (!sc->esc_tx_enabled || sc->esc_TDHr == sc->esc_TDT) {
15129e749f25SAlexander Motin 			if (sc->esc_tx_enabled && sc->esc_TDHr != sc->esc_TDT)
15139e749f25SAlexander Motin 				break;
15149e749f25SAlexander Motin 			sc->esc_tx_active = 0;
15159e749f25SAlexander Motin 			if (sc->esc_tx_enabled == 0)
15169e749f25SAlexander Motin 				pthread_cond_signal(&sc->esc_tx_cond);
15179e749f25SAlexander Motin 			pthread_cond_wait(&sc->esc_tx_cond, &sc->esc_mtx);
15189e749f25SAlexander Motin 		}
15199e749f25SAlexander Motin 		sc->esc_tx_active = 1;
15209e749f25SAlexander Motin 
15219e749f25SAlexander Motin 		/* Process some tx descriptors.  Lock dropped inside. */
15229e749f25SAlexander Motin 		e82545_tx_run(sc);
15239e749f25SAlexander Motin 	}
15249e749f25SAlexander Motin }
15259e749f25SAlexander Motin 
15269e749f25SAlexander Motin static void
e82545_tx_start(struct e82545_softc * sc)15279e749f25SAlexander Motin e82545_tx_start(struct e82545_softc *sc)
15289e749f25SAlexander Motin {
15299e749f25SAlexander Motin 
15309e749f25SAlexander Motin 	if (sc->esc_tx_active == 0)
15319e749f25SAlexander Motin 		pthread_cond_signal(&sc->esc_tx_cond);
15329e749f25SAlexander Motin }
15339e749f25SAlexander Motin 
15349e749f25SAlexander Motin static void
e82545_tx_enable(struct e82545_softc * sc)15359e749f25SAlexander Motin e82545_tx_enable(struct e82545_softc *sc)
15369e749f25SAlexander Motin {
15379e749f25SAlexander Motin 
15389e749f25SAlexander Motin 	sc->esc_tx_enabled = 1;
15399e749f25SAlexander Motin }
15409e749f25SAlexander Motin 
15419e749f25SAlexander Motin static void
e82545_tx_disable(struct e82545_softc * sc)15429e749f25SAlexander Motin e82545_tx_disable(struct e82545_softc *sc)
15439e749f25SAlexander Motin {
15449e749f25SAlexander Motin 
15459e749f25SAlexander Motin 	sc->esc_tx_enabled = 0;
15469e749f25SAlexander Motin 	while (sc->esc_tx_active)
15479e749f25SAlexander Motin 		pthread_cond_wait(&sc->esc_tx_cond, &sc->esc_mtx);
15489e749f25SAlexander Motin }
15499e749f25SAlexander Motin 
15509e749f25SAlexander Motin static void
e82545_rx_enable(struct e82545_softc * sc)15519e749f25SAlexander Motin e82545_rx_enable(struct e82545_softc *sc)
15529e749f25SAlexander Motin {
15539e749f25SAlexander Motin 
15549e749f25SAlexander Motin 	sc->esc_rx_enabled = 1;
15559e749f25SAlexander Motin }
15569e749f25SAlexander Motin 
15579e749f25SAlexander Motin static void
e82545_rx_disable(struct e82545_softc * sc)15589e749f25SAlexander Motin e82545_rx_disable(struct e82545_softc *sc)
15599e749f25SAlexander Motin {
15609e749f25SAlexander Motin 
15619e749f25SAlexander Motin 	sc->esc_rx_enabled = 0;
15629e749f25SAlexander Motin 	while (sc->esc_rx_active)
15639e749f25SAlexander Motin 		pthread_cond_wait(&sc->esc_rx_cond, &sc->esc_mtx);
15649e749f25SAlexander Motin }
15659e749f25SAlexander Motin 
15669e749f25SAlexander Motin static void
e82545_write_ra(struct e82545_softc * sc,int reg,uint32_t wval)15679e749f25SAlexander Motin e82545_write_ra(struct e82545_softc *sc, int reg, uint32_t wval)
15689e749f25SAlexander Motin {
15699e749f25SAlexander Motin 	struct eth_uni *eu;
15709e749f25SAlexander Motin 	int idx;
15719e749f25SAlexander Motin 
15729e749f25SAlexander Motin 	idx = reg >> 1;
15739e749f25SAlexander Motin 	assert(idx < 15);
15749e749f25SAlexander Motin 
15759e749f25SAlexander Motin 	eu = &sc->esc_uni[idx];
15769e749f25SAlexander Motin 
15779e749f25SAlexander Motin 	if (reg & 0x1) {
15789e749f25SAlexander Motin 		/* RAH */
15799e749f25SAlexander Motin 		eu->eu_valid = ((wval & E1000_RAH_AV) == E1000_RAH_AV);
15809e749f25SAlexander Motin 		eu->eu_addrsel = (wval >> 16) & 0x3;
15819e749f25SAlexander Motin 		eu->eu_eth.octet[5] = wval >> 8;
15829e749f25SAlexander Motin 		eu->eu_eth.octet[4] = wval;
15839e749f25SAlexander Motin 	} else {
15849e749f25SAlexander Motin 		/* RAL */
15859e749f25SAlexander Motin 		eu->eu_eth.octet[3] = wval >> 24;
15869e749f25SAlexander Motin 		eu->eu_eth.octet[2] = wval >> 16;
15879e749f25SAlexander Motin 		eu->eu_eth.octet[1] = wval >> 8;
15889e749f25SAlexander Motin 		eu->eu_eth.octet[0] = wval;
15899e749f25SAlexander Motin 	}
15909e749f25SAlexander Motin }
15919e749f25SAlexander Motin 
15929e749f25SAlexander Motin static uint32_t
e82545_read_ra(struct e82545_softc * sc,int reg)15939e749f25SAlexander Motin e82545_read_ra(struct e82545_softc *sc, int reg)
15949e749f25SAlexander Motin {
15959e749f25SAlexander Motin 	struct eth_uni *eu;
15969e749f25SAlexander Motin 	uint32_t retval;
15979e749f25SAlexander Motin 	int idx;
15989e749f25SAlexander Motin 
15999e749f25SAlexander Motin 	idx = reg >> 1;
16009e749f25SAlexander Motin 	assert(idx < 15);
16019e749f25SAlexander Motin 
16029e749f25SAlexander Motin 	eu = &sc->esc_uni[idx];
16039e749f25SAlexander Motin 
16049e749f25SAlexander Motin 	if (reg & 0x1) {
16059e749f25SAlexander Motin 		/* RAH */
16069e749f25SAlexander Motin 		retval = (eu->eu_valid << 31) |
16079e749f25SAlexander Motin 			 (eu->eu_addrsel << 16) |
16089e749f25SAlexander Motin 			 (eu->eu_eth.octet[5] << 8) |
16099e749f25SAlexander Motin 			 eu->eu_eth.octet[4];
16109e749f25SAlexander Motin 	} else {
16119e749f25SAlexander Motin 		/* RAL */
16129e749f25SAlexander Motin 		retval = (eu->eu_eth.octet[3] << 24) |
16139e749f25SAlexander Motin 			 (eu->eu_eth.octet[2] << 16) |
16149e749f25SAlexander Motin 			 (eu->eu_eth.octet[1] << 8) |
16159e749f25SAlexander Motin 			 eu->eu_eth.octet[0];
16169e749f25SAlexander Motin 	}
16179e749f25SAlexander Motin 
16189e749f25SAlexander Motin 	return (retval);
16199e749f25SAlexander Motin }
16209e749f25SAlexander Motin 
16219e749f25SAlexander Motin static void
e82545_write_register(struct e82545_softc * sc,uint32_t offset,uint32_t value)16229e749f25SAlexander Motin e82545_write_register(struct e82545_softc *sc, uint32_t offset, uint32_t value)
16239e749f25SAlexander Motin {
16249e749f25SAlexander Motin 	int ridx;
16259e749f25SAlexander Motin 
16269e749f25SAlexander Motin 	if (offset & 0x3) {
1627332eff95SVincenzo Maffione 		DPRINTF("Unaligned register write offset:0x%x value:0x%x", offset, value);
16289e749f25SAlexander Motin 		return;
16299e749f25SAlexander Motin 	}
1630332eff95SVincenzo Maffione 	DPRINTF("Register write: 0x%x value: 0x%x", offset, value);
16319e749f25SAlexander Motin 
16329e749f25SAlexander Motin 	switch (offset) {
16339e749f25SAlexander Motin 	case E1000_CTRL:
16349e749f25SAlexander Motin 	case E1000_CTRL_DUP:
16359e749f25SAlexander Motin 		e82545_devctl(sc, value);
16369e749f25SAlexander Motin 		break;
16379e749f25SAlexander Motin 	case E1000_FCAL:
16389e749f25SAlexander Motin 		sc->esc_FCAL = value;
16399e749f25SAlexander Motin 		break;
16409e749f25SAlexander Motin 	case E1000_FCAH:
16419e749f25SAlexander Motin 		sc->esc_FCAH = value & ~0xFFFF0000;
16429e749f25SAlexander Motin 		break;
16439e749f25SAlexander Motin 	case E1000_FCT:
16449e749f25SAlexander Motin 		sc->esc_FCT = value & ~0xFFFF0000;
16459e749f25SAlexander Motin 		break;
16469e749f25SAlexander Motin 	case E1000_VET:
16479e749f25SAlexander Motin 		sc->esc_VET = value & ~0xFFFF0000;
16489e749f25SAlexander Motin 		break;
16499e749f25SAlexander Motin 	case E1000_FCTTV:
16509e749f25SAlexander Motin 		sc->esc_FCTTV = value & ~0xFFFF0000;
16519e749f25SAlexander Motin 		break;
16529e749f25SAlexander Motin 	case E1000_LEDCTL:
16539e749f25SAlexander Motin 		sc->esc_LEDCTL = value & ~0x30303000;
16549e749f25SAlexander Motin 		break;
16559e749f25SAlexander Motin 	case E1000_PBA:
16569e749f25SAlexander Motin 		sc->esc_PBA = value & 0x0000FF80;
16579e749f25SAlexander Motin 		break;
16589e749f25SAlexander Motin 	case E1000_ICR:
16599e749f25SAlexander Motin 	case E1000_ITR:
16609e749f25SAlexander Motin 	case E1000_ICS:
16619e749f25SAlexander Motin 	case E1000_IMS:
16629e749f25SAlexander Motin 	case E1000_IMC:
16639e749f25SAlexander Motin 		e82545_intr_write(sc, offset, value);
16649e749f25SAlexander Motin 		break;
16659e749f25SAlexander Motin 	case E1000_RCTL:
16669e749f25SAlexander Motin 		e82545_rx_ctl(sc, value);
16679e749f25SAlexander Motin 		break;
16689e749f25SAlexander Motin 	case E1000_FCRTL:
16699e749f25SAlexander Motin 		sc->esc_FCRTL = value & ~0xFFFF0007;
16709e749f25SAlexander Motin 		break;
16719e749f25SAlexander Motin 	case E1000_FCRTH:
16729e749f25SAlexander Motin 		sc->esc_FCRTH = value & ~0xFFFF0007;
16739e749f25SAlexander Motin 		break;
16749e749f25SAlexander Motin 	case E1000_RDBAL(0):
16759e749f25SAlexander Motin 		sc->esc_RDBAL = value & ~0xF;
16769e749f25SAlexander Motin 		if (sc->esc_rx_enabled) {
16779e749f25SAlexander Motin 			/* Apparently legal: update cached address */
16789e749f25SAlexander Motin 			e82545_rx_update_rdba(sc);
16799e749f25SAlexander Motin 		}
16809e749f25SAlexander Motin 		break;
16819e749f25SAlexander Motin 	case E1000_RDBAH(0):
16829e749f25SAlexander Motin 		assert(!sc->esc_rx_enabled);
16839e749f25SAlexander Motin 		sc->esc_RDBAH = value;
16849e749f25SAlexander Motin 		break;
16859e749f25SAlexander Motin 	case E1000_RDLEN(0):
16869e749f25SAlexander Motin 		assert(!sc->esc_rx_enabled);
16879e749f25SAlexander Motin 		sc->esc_RDLEN = value & ~0xFFF0007F;
16889e749f25SAlexander Motin 		break;
16899e749f25SAlexander Motin 	case E1000_RDH(0):
16909e749f25SAlexander Motin 		/* XXX should only ever be zero ? Range check ? */
16919e749f25SAlexander Motin 		sc->esc_RDH = value;
16929e749f25SAlexander Motin 		break;
16939e749f25SAlexander Motin 	case E1000_RDT(0):
16949e749f25SAlexander Motin 		/* XXX if this opens up the rx ring, do something ? */
16959e749f25SAlexander Motin 		sc->esc_RDT = value;
16969e749f25SAlexander Motin 		break;
16979e749f25SAlexander Motin 	case E1000_RDTR:
16989e749f25SAlexander Motin 		/* ignore FPD bit 31 */
16999e749f25SAlexander Motin 		sc->esc_RDTR = value & ~0xFFFF0000;
17009e749f25SAlexander Motin 		break;
17019e749f25SAlexander Motin 	case E1000_RXDCTL(0):
17029e749f25SAlexander Motin 		sc->esc_RXDCTL = value & ~0xFEC0C0C0;
17039e749f25SAlexander Motin 		break;
17049e749f25SAlexander Motin 	case E1000_RADV:
17059e749f25SAlexander Motin 		sc->esc_RADV = value & ~0xFFFF0000;
17069e749f25SAlexander Motin 		break;
17079e749f25SAlexander Motin 	case E1000_RSRPD:
17089e749f25SAlexander Motin 		sc->esc_RSRPD = value & ~0xFFFFF000;
17099e749f25SAlexander Motin 		break;
17109e749f25SAlexander Motin 	case E1000_RXCSUM:
17119e749f25SAlexander Motin 		sc->esc_RXCSUM = value & ~0xFFFFF800;
17129e749f25SAlexander Motin 		break;
17139e749f25SAlexander Motin 	case E1000_TXCW:
17149e749f25SAlexander Motin 		sc->esc_TXCW = value & ~0x3FFF0000;
17159e749f25SAlexander Motin 		break;
17169e749f25SAlexander Motin 	case E1000_TCTL:
17179e749f25SAlexander Motin 		e82545_tx_ctl(sc, value);
17189e749f25SAlexander Motin 		break;
17199e749f25SAlexander Motin 	case E1000_TIPG:
17209e749f25SAlexander Motin 		sc->esc_TIPG = value;
17219e749f25SAlexander Motin 		break;
17229e749f25SAlexander Motin 	case E1000_AIT:
17239e749f25SAlexander Motin 		sc->esc_AIT = value;
17249e749f25SAlexander Motin 		break;
17259e749f25SAlexander Motin 	case E1000_TDBAL(0):
17269e749f25SAlexander Motin 		sc->esc_TDBAL = value & ~0xF;
172760dc6beeSRyan Moeller 		if (sc->esc_tx_enabled)
17289e749f25SAlexander Motin 			e82545_tx_update_tdba(sc);
17299e749f25SAlexander Motin 		break;
17309e749f25SAlexander Motin 	case E1000_TDBAH(0):
17319e749f25SAlexander Motin 		sc->esc_TDBAH = value;
173260dc6beeSRyan Moeller 		if (sc->esc_tx_enabled)
173360dc6beeSRyan Moeller 			e82545_tx_update_tdba(sc);
17349e749f25SAlexander Motin 		break;
17359e749f25SAlexander Motin 	case E1000_TDLEN(0):
17369e749f25SAlexander Motin 		sc->esc_TDLEN = value & ~0xFFF0007F;
173760dc6beeSRyan Moeller 		if (sc->esc_tx_enabled)
173860dc6beeSRyan Moeller 			e82545_tx_update_tdba(sc);
17399e749f25SAlexander Motin 		break;
17409e749f25SAlexander Motin 	case E1000_TDH(0):
17417afe342dSJohn Baldwin 		if (sc->esc_tx_enabled) {
17427afe342dSJohn Baldwin 			WPRINTF("ignoring write to TDH while transmit enabled");
17437afe342dSJohn Baldwin 			break;
17447afe342dSJohn Baldwin 		}
17457afe342dSJohn Baldwin 		if (value != 0) {
17467afe342dSJohn Baldwin 			WPRINTF("ignoring non-zero value written to TDH");
17477afe342dSJohn Baldwin 			break;
17487afe342dSJohn Baldwin 		}
17499e749f25SAlexander Motin 		sc->esc_TDHr = sc->esc_TDH = value;
17509e749f25SAlexander Motin 		break;
17519e749f25SAlexander Motin 	case E1000_TDT(0):
17529e749f25SAlexander Motin 		sc->esc_TDT = value;
17539e749f25SAlexander Motin 		if (sc->esc_tx_enabled)
17549e749f25SAlexander Motin 			e82545_tx_start(sc);
17559e749f25SAlexander Motin 		break;
17569e749f25SAlexander Motin 	case E1000_TIDV:
17579e749f25SAlexander Motin 		sc->esc_TIDV = value & ~0xFFFF0000;
17589e749f25SAlexander Motin 		break;
17599e749f25SAlexander Motin 	case E1000_TXDCTL(0):
17609e749f25SAlexander Motin 		//assert(!sc->esc_tx_enabled);
17619e749f25SAlexander Motin 		sc->esc_TXDCTL = value & ~0xC0C0C0;
17629e749f25SAlexander Motin 		break;
17639e749f25SAlexander Motin 	case E1000_TADV:
17649e749f25SAlexander Motin 		sc->esc_TADV = value & ~0xFFFF0000;
17659e749f25SAlexander Motin 		break;
17669e749f25SAlexander Motin 	case E1000_RAL(0) ... E1000_RAH(15):
17679e749f25SAlexander Motin 		/* convert to u32 offset */
17689e749f25SAlexander Motin 		ridx = (offset - E1000_RAL(0)) >> 2;
17699e749f25SAlexander Motin 		e82545_write_ra(sc, ridx, value);
17709e749f25SAlexander Motin 		break;
17719e749f25SAlexander Motin 	case E1000_MTA ... (E1000_MTA + (127*4)):
17729e749f25SAlexander Motin 		sc->esc_fmcast[(offset - E1000_MTA) >> 2] = value;
17739e749f25SAlexander Motin 		break;
17749e749f25SAlexander Motin 	case E1000_VFTA ... (E1000_VFTA + (127*4)):
17759e749f25SAlexander Motin 		sc->esc_fvlan[(offset - E1000_VFTA) >> 2] = value;
17769e749f25SAlexander Motin 		break;
17779e749f25SAlexander Motin 	case E1000_EECD:
17789e749f25SAlexander Motin 	{
1779332eff95SVincenzo Maffione 		//DPRINTF("EECD write 0x%x -> 0x%x", sc->eeprom_control, value);
17809e749f25SAlexander Motin 		/* edge triggered low->high */
17819e749f25SAlexander Motin 		uint32_t eecd_strobe = ((sc->eeprom_control & E1000_EECD_SK) ?
17829e749f25SAlexander Motin 			0 : (value & E1000_EECD_SK));
17839e749f25SAlexander Motin 		uint32_t eecd_mask = (E1000_EECD_SK|E1000_EECD_CS|
17849e749f25SAlexander Motin 					E1000_EECD_DI|E1000_EECD_REQ);
17859e749f25SAlexander Motin 		sc->eeprom_control &= ~eecd_mask;
17869e749f25SAlexander Motin 		sc->eeprom_control |= (value & eecd_mask);
17879e749f25SAlexander Motin 		/* grant/revoke immediately */
17889e749f25SAlexander Motin 		if (value & E1000_EECD_REQ) {
17899e749f25SAlexander Motin 			sc->eeprom_control |= E1000_EECD_GNT;
17909e749f25SAlexander Motin 		} else {
17919e749f25SAlexander Motin                         sc->eeprom_control &= ~E1000_EECD_GNT;
17929e749f25SAlexander Motin 		}
17939e749f25SAlexander Motin 		if (eecd_strobe && (sc->eeprom_control & E1000_EECD_CS)) {
17949e749f25SAlexander Motin 			e82545_eecd_strobe(sc);
17959e749f25SAlexander Motin 		}
17969e749f25SAlexander Motin 		return;
17979e749f25SAlexander Motin 	}
17989e749f25SAlexander Motin 	case E1000_MDIC:
17999e749f25SAlexander Motin 	{
18009e749f25SAlexander Motin 		uint8_t reg_addr = (uint8_t)((value & E1000_MDIC_REG_MASK) >>
18019e749f25SAlexander Motin 						E1000_MDIC_REG_SHIFT);
18029e749f25SAlexander Motin 		uint8_t phy_addr = (uint8_t)((value & E1000_MDIC_PHY_MASK) >>
18039e749f25SAlexander Motin 						E1000_MDIC_PHY_SHIFT);
18049e749f25SAlexander Motin 		sc->mdi_control =
18059e749f25SAlexander Motin 			(value & ~(E1000_MDIC_ERROR|E1000_MDIC_DEST));
18069e749f25SAlexander Motin 		if ((value & E1000_MDIC_READY) != 0) {
1807332eff95SVincenzo Maffione 			DPRINTF("Incorrect MDIC ready bit: 0x%x", value);
18089e749f25SAlexander Motin 			return;
18099e749f25SAlexander Motin 		}
18109e749f25SAlexander Motin 		switch (value & E82545_MDIC_OP_MASK) {
18119e749f25SAlexander Motin 		case E1000_MDIC_OP_READ:
18129e749f25SAlexander Motin 			sc->mdi_control &= ~E82545_MDIC_DATA_MASK;
18139e749f25SAlexander Motin 			sc->mdi_control |= e82545_read_mdi(sc, reg_addr, phy_addr);
18149e749f25SAlexander Motin 			break;
18159e749f25SAlexander Motin 		case E1000_MDIC_OP_WRITE:
18169e749f25SAlexander Motin 			e82545_write_mdi(sc, reg_addr, phy_addr,
18179e749f25SAlexander Motin 				value & E82545_MDIC_DATA_MASK);
18189e749f25SAlexander Motin 			break;
18199e749f25SAlexander Motin 		default:
1820332eff95SVincenzo Maffione 			DPRINTF("Unknown MDIC op: 0x%x", value);
18219e749f25SAlexander Motin 			return;
18229e749f25SAlexander Motin 		}
18239e749f25SAlexander Motin 		/* TODO: barrier? */
18249e749f25SAlexander Motin 		sc->mdi_control |= E1000_MDIC_READY;
18259e749f25SAlexander Motin 		if (value & E82545_MDIC_IE) {
18269e749f25SAlexander Motin 			// TODO: generate interrupt
18279e749f25SAlexander Motin 		}
18289e749f25SAlexander Motin 		return;
18299e749f25SAlexander Motin 	}
18309e749f25SAlexander Motin 	case E1000_MANC:
18319e749f25SAlexander Motin 	case E1000_STATUS:
18329e749f25SAlexander Motin 		return;
18339e749f25SAlexander Motin 	default:
1834332eff95SVincenzo Maffione 		DPRINTF("Unknown write register: 0x%x value:%x", offset, value);
18359e749f25SAlexander Motin 		return;
18369e749f25SAlexander Motin 	}
18379e749f25SAlexander Motin }
18389e749f25SAlexander Motin 
18399e749f25SAlexander Motin static uint32_t
e82545_read_register(struct e82545_softc * sc,uint32_t offset)18409e749f25SAlexander Motin e82545_read_register(struct e82545_softc *sc, uint32_t offset)
18419e749f25SAlexander Motin {
18429e749f25SAlexander Motin 	uint32_t retval;
18439e749f25SAlexander Motin 	int ridx;
18449e749f25SAlexander Motin 
18459e749f25SAlexander Motin 	if (offset & 0x3) {
1846332eff95SVincenzo Maffione 		DPRINTF("Unaligned register read offset:0x%x", offset);
18479e749f25SAlexander Motin 		return 0;
18489e749f25SAlexander Motin 	}
18499e749f25SAlexander Motin 
1850332eff95SVincenzo Maffione 	DPRINTF("Register read: 0x%x", offset);
18519e749f25SAlexander Motin 
18529e749f25SAlexander Motin 	switch (offset) {
18539e749f25SAlexander Motin 	case E1000_CTRL:
18549e749f25SAlexander Motin 		retval = sc->esc_CTRL;
18559e749f25SAlexander Motin 		break;
18569e749f25SAlexander Motin 	case E1000_STATUS:
18579e749f25SAlexander Motin 		retval = E1000_STATUS_FD | E1000_STATUS_LU |
18589e749f25SAlexander Motin 		    E1000_STATUS_SPEED_1000;
18599e749f25SAlexander Motin 		break;
18609e749f25SAlexander Motin 	case E1000_FCAL:
18619e749f25SAlexander Motin 		retval = sc->esc_FCAL;
18629e749f25SAlexander Motin 		break;
18639e749f25SAlexander Motin 	case E1000_FCAH:
18649e749f25SAlexander Motin 		retval = sc->esc_FCAH;
18659e749f25SAlexander Motin 		break;
18669e749f25SAlexander Motin 	case E1000_FCT:
18679e749f25SAlexander Motin 		retval = sc->esc_FCT;
18689e749f25SAlexander Motin 		break;
18699e749f25SAlexander Motin 	case E1000_VET:
18709e749f25SAlexander Motin 		retval = sc->esc_VET;
18719e749f25SAlexander Motin 		break;
18729e749f25SAlexander Motin 	case E1000_FCTTV:
18739e749f25SAlexander Motin 		retval = sc->esc_FCTTV;
18749e749f25SAlexander Motin 		break;
18759e749f25SAlexander Motin 	case E1000_LEDCTL:
18769e749f25SAlexander Motin 		retval = sc->esc_LEDCTL;
18779e749f25SAlexander Motin 		break;
18789e749f25SAlexander Motin 	case E1000_PBA:
18799e749f25SAlexander Motin 		retval = sc->esc_PBA;
18809e749f25SAlexander Motin 		break;
18819e749f25SAlexander Motin 	case E1000_ICR:
18829e749f25SAlexander Motin 	case E1000_ITR:
18839e749f25SAlexander Motin 	case E1000_ICS:
18849e749f25SAlexander Motin 	case E1000_IMS:
18859e749f25SAlexander Motin 	case E1000_IMC:
18869e749f25SAlexander Motin 		retval = e82545_intr_read(sc, offset);
18879e749f25SAlexander Motin 		break;
18889e749f25SAlexander Motin 	case E1000_RCTL:
18899e749f25SAlexander Motin 		retval = sc->esc_RCTL;
18909e749f25SAlexander Motin 		break;
18919e749f25SAlexander Motin 	case E1000_FCRTL:
18929e749f25SAlexander Motin 		retval = sc->esc_FCRTL;
18939e749f25SAlexander Motin 		break;
18949e749f25SAlexander Motin 	case E1000_FCRTH:
18959e749f25SAlexander Motin 		retval = sc->esc_FCRTH;
18969e749f25SAlexander Motin 		break;
18979e749f25SAlexander Motin 	case E1000_RDBAL(0):
18989e749f25SAlexander Motin 		retval = sc->esc_RDBAL;
18999e749f25SAlexander Motin 		break;
19009e749f25SAlexander Motin 	case E1000_RDBAH(0):
19019e749f25SAlexander Motin 		retval = sc->esc_RDBAH;
19029e749f25SAlexander Motin 		break;
19039e749f25SAlexander Motin 	case E1000_RDLEN(0):
19049e749f25SAlexander Motin 		retval = sc->esc_RDLEN;
19059e749f25SAlexander Motin 		break;
19069e749f25SAlexander Motin 	case E1000_RDH(0):
19079e749f25SAlexander Motin 		retval = sc->esc_RDH;
19089e749f25SAlexander Motin 		break;
19099e749f25SAlexander Motin 	case E1000_RDT(0):
19109e749f25SAlexander Motin 		retval = sc->esc_RDT;
19119e749f25SAlexander Motin 		break;
19129e749f25SAlexander Motin 	case E1000_RDTR:
19139e749f25SAlexander Motin 		retval = sc->esc_RDTR;
19149e749f25SAlexander Motin 		break;
19159e749f25SAlexander Motin 	case E1000_RXDCTL(0):
19169e749f25SAlexander Motin 		retval = sc->esc_RXDCTL;
19179e749f25SAlexander Motin 		break;
19189e749f25SAlexander Motin 	case E1000_RADV:
19199e749f25SAlexander Motin 		retval = sc->esc_RADV;
19209e749f25SAlexander Motin 		break;
19219e749f25SAlexander Motin 	case E1000_RSRPD:
19229e749f25SAlexander Motin 		retval = sc->esc_RSRPD;
19239e749f25SAlexander Motin 		break;
19249e749f25SAlexander Motin 	case E1000_RXCSUM:
19259e749f25SAlexander Motin 		retval = sc->esc_RXCSUM;
19269e749f25SAlexander Motin 		break;
19279e749f25SAlexander Motin 	case E1000_TXCW:
19289e749f25SAlexander Motin 		retval = sc->esc_TXCW;
19299e749f25SAlexander Motin 		break;
19309e749f25SAlexander Motin 	case E1000_TCTL:
19319e749f25SAlexander Motin 		retval = sc->esc_TCTL;
19329e749f25SAlexander Motin 		break;
19339e749f25SAlexander Motin 	case E1000_TIPG:
19349e749f25SAlexander Motin 		retval = sc->esc_TIPG;
19359e749f25SAlexander Motin 		break;
19369e749f25SAlexander Motin 	case E1000_AIT:
19379e749f25SAlexander Motin 		retval = sc->esc_AIT;
19389e749f25SAlexander Motin 		break;
19399e749f25SAlexander Motin 	case E1000_TDBAL(0):
19409e749f25SAlexander Motin 		retval = sc->esc_TDBAL;
19419e749f25SAlexander Motin 		break;
19429e749f25SAlexander Motin 	case E1000_TDBAH(0):
19439e749f25SAlexander Motin 		retval = sc->esc_TDBAH;
19449e749f25SAlexander Motin 		break;
19459e749f25SAlexander Motin 	case E1000_TDLEN(0):
19469e749f25SAlexander Motin 		retval = sc->esc_TDLEN;
19479e749f25SAlexander Motin 		break;
19489e749f25SAlexander Motin 	case E1000_TDH(0):
19499e749f25SAlexander Motin 		retval = sc->esc_TDH;
19509e749f25SAlexander Motin 		break;
19519e749f25SAlexander Motin 	case E1000_TDT(0):
19529e749f25SAlexander Motin 		retval = sc->esc_TDT;
19539e749f25SAlexander Motin 		break;
19549e749f25SAlexander Motin 	case E1000_TIDV:
19559e749f25SAlexander Motin 		retval = sc->esc_TIDV;
19569e749f25SAlexander Motin 		break;
19579e749f25SAlexander Motin 	case E1000_TXDCTL(0):
19589e749f25SAlexander Motin 		retval = sc->esc_TXDCTL;
19599e749f25SAlexander Motin 		break;
19609e749f25SAlexander Motin 	case E1000_TADV:
19619e749f25SAlexander Motin 		retval = sc->esc_TADV;
19629e749f25SAlexander Motin 		break;
19639e749f25SAlexander Motin 	case E1000_RAL(0) ... E1000_RAH(15):
19649e749f25SAlexander Motin 		/* convert to u32 offset */
19659e749f25SAlexander Motin 		ridx = (offset - E1000_RAL(0)) >> 2;
19669e749f25SAlexander Motin 		retval = e82545_read_ra(sc, ridx);
19679e749f25SAlexander Motin 		break;
19689e749f25SAlexander Motin 	case E1000_MTA ... (E1000_MTA + (127*4)):
19699e749f25SAlexander Motin 		retval = sc->esc_fmcast[(offset - E1000_MTA) >> 2];
19709e749f25SAlexander Motin 		break;
19719e749f25SAlexander Motin 	case E1000_VFTA ... (E1000_VFTA + (127*4)):
19729e749f25SAlexander Motin 		retval = sc->esc_fvlan[(offset - E1000_VFTA) >> 2];
19739e749f25SAlexander Motin 		break;
19749e749f25SAlexander Motin 	case E1000_EECD:
1975332eff95SVincenzo Maffione 		//DPRINTF("EECD read %x", sc->eeprom_control);
19769e749f25SAlexander Motin 		retval = sc->eeprom_control;
19779e749f25SAlexander Motin 		break;
19789e749f25SAlexander Motin 	case E1000_MDIC:
19799e749f25SAlexander Motin 		retval = sc->mdi_control;
19809e749f25SAlexander Motin 		break;
19819e749f25SAlexander Motin 	case E1000_MANC:
19829e749f25SAlexander Motin 		retval = 0;
19839e749f25SAlexander Motin 		break;
19849e749f25SAlexander Motin 	/* stats that we emulate. */
19859e749f25SAlexander Motin 	case E1000_MPC:
19869e749f25SAlexander Motin 		retval = sc->missed_pkt_count;
19879e749f25SAlexander Motin 		break;
19889e749f25SAlexander Motin 	case E1000_PRC64:
19899e749f25SAlexander Motin 		retval = sc->pkt_rx_by_size[0];
19909e749f25SAlexander Motin 		break;
19919e749f25SAlexander Motin 	case E1000_PRC127:
19929e749f25SAlexander Motin 		retval = sc->pkt_rx_by_size[1];
19939e749f25SAlexander Motin 		break;
19949e749f25SAlexander Motin 	case E1000_PRC255:
19959e749f25SAlexander Motin 		retval = sc->pkt_rx_by_size[2];
19969e749f25SAlexander Motin 		break;
19979e749f25SAlexander Motin 	case E1000_PRC511:
19989e749f25SAlexander Motin 		retval = sc->pkt_rx_by_size[3];
19999e749f25SAlexander Motin 		break;
20009e749f25SAlexander Motin 	case E1000_PRC1023:
20019e749f25SAlexander Motin 		retval = sc->pkt_rx_by_size[4];
20029e749f25SAlexander Motin 		break;
20039e749f25SAlexander Motin 	case E1000_PRC1522:
20049e749f25SAlexander Motin 		retval = sc->pkt_rx_by_size[5];
20059e749f25SAlexander Motin 		break;
20069e749f25SAlexander Motin 	case E1000_GPRC:
20079e749f25SAlexander Motin 		retval = sc->good_pkt_rx_count;
20089e749f25SAlexander Motin 		break;
20099e749f25SAlexander Motin 	case E1000_BPRC:
20109e749f25SAlexander Motin 		retval = sc->bcast_pkt_rx_count;
20119e749f25SAlexander Motin 		break;
20129e749f25SAlexander Motin 	case E1000_MPRC:
20139e749f25SAlexander Motin 		retval = sc->mcast_pkt_rx_count;
20149e749f25SAlexander Motin 		break;
20159e749f25SAlexander Motin 	case E1000_GPTC:
20169e749f25SAlexander Motin 	case E1000_TPT:
20179e749f25SAlexander Motin 		retval = sc->good_pkt_tx_count;
20189e749f25SAlexander Motin 		break;
20199e749f25SAlexander Motin 	case E1000_GORCL:
20209e749f25SAlexander Motin 		retval = (uint32_t)sc->good_octets_rx;
20219e749f25SAlexander Motin 		break;
20229e749f25SAlexander Motin 	case E1000_GORCH:
20239e749f25SAlexander Motin 		retval = (uint32_t)(sc->good_octets_rx >> 32);
20249e749f25SAlexander Motin 		break;
20259e749f25SAlexander Motin 	case E1000_TOTL:
20269e749f25SAlexander Motin 	case E1000_GOTCL:
20279e749f25SAlexander Motin 		retval = (uint32_t)sc->good_octets_tx;
20289e749f25SAlexander Motin 		break;
20299e749f25SAlexander Motin 	case E1000_TOTH:
20309e749f25SAlexander Motin 	case E1000_GOTCH:
20319e749f25SAlexander Motin 		retval = (uint32_t)(sc->good_octets_tx >> 32);
20329e749f25SAlexander Motin 		break;
20339e749f25SAlexander Motin 	case E1000_ROC:
20349e749f25SAlexander Motin 		retval = sc->oversize_rx_count;
20359e749f25SAlexander Motin 		break;
20369e749f25SAlexander Motin 	case E1000_TORL:
20379e749f25SAlexander Motin 		retval = (uint32_t)(sc->good_octets_rx + sc->missed_octets);
20389e749f25SAlexander Motin 		break;
20399e749f25SAlexander Motin 	case E1000_TORH:
20409e749f25SAlexander Motin 		retval = (uint32_t)((sc->good_octets_rx +
20419e749f25SAlexander Motin 		    sc->missed_octets) >> 32);
20429e749f25SAlexander Motin 		break;
20439e749f25SAlexander Motin 	case E1000_TPR:
20449e749f25SAlexander Motin 		retval = sc->good_pkt_rx_count + sc->missed_pkt_count +
20459e749f25SAlexander Motin 		    sc->oversize_rx_count;
20469e749f25SAlexander Motin 		break;
20479e749f25SAlexander Motin 	case E1000_PTC64:
20489e749f25SAlexander Motin 		retval = sc->pkt_tx_by_size[0];
20499e749f25SAlexander Motin 		break;
20509e749f25SAlexander Motin 	case E1000_PTC127:
20519e749f25SAlexander Motin 		retval = sc->pkt_tx_by_size[1];
20529e749f25SAlexander Motin 		break;
20539e749f25SAlexander Motin 	case E1000_PTC255:
20549e749f25SAlexander Motin 		retval = sc->pkt_tx_by_size[2];
20559e749f25SAlexander Motin 		break;
20569e749f25SAlexander Motin 	case E1000_PTC511:
20579e749f25SAlexander Motin 		retval = sc->pkt_tx_by_size[3];
20589e749f25SAlexander Motin 		break;
20599e749f25SAlexander Motin 	case E1000_PTC1023:
20609e749f25SAlexander Motin 		retval = sc->pkt_tx_by_size[4];
20619e749f25SAlexander Motin 		break;
20629e749f25SAlexander Motin 	case E1000_PTC1522:
20639e749f25SAlexander Motin 		retval = sc->pkt_tx_by_size[5];
20649e749f25SAlexander Motin 		break;
20659e749f25SAlexander Motin 	case E1000_MPTC:
20669e749f25SAlexander Motin 		retval = sc->mcast_pkt_tx_count;
20679e749f25SAlexander Motin 		break;
20689e749f25SAlexander Motin 	case E1000_BPTC:
20699e749f25SAlexander Motin 		retval = sc->bcast_pkt_tx_count;
20709e749f25SAlexander Motin 		break;
20719e749f25SAlexander Motin 	case E1000_TSCTC:
20729e749f25SAlexander Motin 		retval = sc->tso_tx_count;
20739e749f25SAlexander Motin 		break;
20749e749f25SAlexander Motin 	/* stats that are always 0. */
20759e749f25SAlexander Motin 	case E1000_CRCERRS:
20769e749f25SAlexander Motin 	case E1000_ALGNERRC:
20779e749f25SAlexander Motin 	case E1000_SYMERRS:
20789e749f25SAlexander Motin 	case E1000_RXERRC:
20799e749f25SAlexander Motin 	case E1000_SCC:
20809e749f25SAlexander Motin 	case E1000_ECOL:
20819e749f25SAlexander Motin 	case E1000_MCC:
20829e749f25SAlexander Motin 	case E1000_LATECOL:
20839e749f25SAlexander Motin 	case E1000_COLC:
20849e749f25SAlexander Motin 	case E1000_DC:
20859e749f25SAlexander Motin 	case E1000_TNCRS:
20869e749f25SAlexander Motin 	case E1000_SEC:
20879e749f25SAlexander Motin 	case E1000_CEXTERR:
20889e749f25SAlexander Motin 	case E1000_RLEC:
20899e749f25SAlexander Motin 	case E1000_XONRXC:
20909e749f25SAlexander Motin 	case E1000_XONTXC:
20919e749f25SAlexander Motin 	case E1000_XOFFRXC:
20929e749f25SAlexander Motin 	case E1000_XOFFTXC:
20939e749f25SAlexander Motin 	case E1000_FCRUC:
20949e749f25SAlexander Motin 	case E1000_RNBC:
20959e749f25SAlexander Motin 	case E1000_RUC:
20969e749f25SAlexander Motin 	case E1000_RFC:
20979e749f25SAlexander Motin 	case E1000_RJC:
20989e749f25SAlexander Motin 	case E1000_MGTPRC:
20999e749f25SAlexander Motin 	case E1000_MGTPDC:
21009e749f25SAlexander Motin 	case E1000_MGTPTC:
21019e749f25SAlexander Motin 	case E1000_TSCTFC:
21029e749f25SAlexander Motin 		retval = 0;
21039e749f25SAlexander Motin 		break;
21049e749f25SAlexander Motin 	default:
2105332eff95SVincenzo Maffione 		DPRINTF("Unknown read register: 0x%x", offset);
2106e95b7573SAlexander Motin 		retval = 0;
21079e749f25SAlexander Motin 		break;
21089e749f25SAlexander Motin 	}
21099e749f25SAlexander Motin 
21109e749f25SAlexander Motin 	return (retval);
21119e749f25SAlexander Motin }
21129e749f25SAlexander Motin 
21139e749f25SAlexander Motin static void
e82545_write(struct pci_devinst * pi,int baridx,uint64_t offset,int size,uint64_t value)21146a284cacSJohn Baldwin e82545_write(struct pci_devinst *pi, int baridx, uint64_t offset, int size,
211598d920d9SMark Johnston     uint64_t value)
21169e749f25SAlexander Motin {
21179e749f25SAlexander Motin 	struct e82545_softc *sc;
21189e749f25SAlexander Motin 
2119332eff95SVincenzo Maffione 	//DPRINTF("Write bar:%d offset:0x%lx value:0x%lx size:%d", baridx, offset, value, size);
21209e749f25SAlexander Motin 
21219e749f25SAlexander Motin 	sc = pi->pi_arg;
21229e749f25SAlexander Motin 
21239e749f25SAlexander Motin 	pthread_mutex_lock(&sc->esc_mtx);
21249e749f25SAlexander Motin 
21259e749f25SAlexander Motin 	switch (baridx) {
21269e749f25SAlexander Motin 	case E82545_BAR_IO:
21279e749f25SAlexander Motin 		switch (offset) {
21289e749f25SAlexander Motin 		case E82545_IOADDR:
21299e749f25SAlexander Motin 			if (size != 4) {
2130332eff95SVincenzo Maffione 				DPRINTF("Wrong io addr write sz:%d value:0x%lx", size, value);
21319e749f25SAlexander Motin 			} else
21329e749f25SAlexander Motin 				sc->io_addr = (uint32_t)value;
21339e749f25SAlexander Motin 			break;
21349e749f25SAlexander Motin 		case E82545_IODATA:
21359e749f25SAlexander Motin 			if (size != 4) {
2136332eff95SVincenzo Maffione 				DPRINTF("Wrong io data write size:%d value:0x%lx", size, value);
21379e749f25SAlexander Motin 			} else if (sc->io_addr > E82545_IO_REGISTER_MAX) {
2138332eff95SVincenzo Maffione 				DPRINTF("Non-register io write addr:0x%x value:0x%lx", sc->io_addr, value);
21399e749f25SAlexander Motin 			} else
21409e749f25SAlexander Motin 				e82545_write_register(sc, sc->io_addr,
21419e749f25SAlexander Motin 						      (uint32_t)value);
21429e749f25SAlexander Motin 			break;
21439e749f25SAlexander Motin 		default:
2144332eff95SVincenzo Maffione 			DPRINTF("Unknown io bar write offset:0x%lx value:0x%lx size:%d", offset, value, size);
21459e749f25SAlexander Motin 			break;
21469e749f25SAlexander Motin 		}
2147a88b19f9SAlexander Motin 		break;
21489e749f25SAlexander Motin 	case E82545_BAR_REGISTER:
21499e749f25SAlexander Motin 		if (size != 4) {
2150332eff95SVincenzo Maffione 			DPRINTF("Wrong register write size:%d offset:0x%lx value:0x%lx", size, offset, value);
21519e749f25SAlexander Motin 		} else
21529e749f25SAlexander Motin 			e82545_write_register(sc, (uint32_t)offset,
21539e749f25SAlexander Motin 					      (uint32_t)value);
21549e749f25SAlexander Motin 		break;
21559e749f25SAlexander Motin 	default:
2156332eff95SVincenzo Maffione 		DPRINTF("Unknown write bar:%d off:0x%lx val:0x%lx size:%d",
21579e749f25SAlexander Motin 			baridx, offset, value, size);
21589e749f25SAlexander Motin 	}
21599e749f25SAlexander Motin 
21609e749f25SAlexander Motin 	pthread_mutex_unlock(&sc->esc_mtx);
21619e749f25SAlexander Motin }
21629e749f25SAlexander Motin 
21639e749f25SAlexander Motin static uint64_t
e82545_read(struct pci_devinst * pi,int baridx,uint64_t offset,int size)21646a284cacSJohn Baldwin e82545_read(struct pci_devinst *pi, int baridx, uint64_t offset, int size)
21659e749f25SAlexander Motin {
21669e749f25SAlexander Motin 	struct e82545_softc *sc;
21679e749f25SAlexander Motin 	uint64_t retval;
21689e749f25SAlexander Motin 
2169332eff95SVincenzo Maffione 	//DPRINTF("Read  bar:%d offset:0x%lx size:%d", baridx, offset, size);
21709e749f25SAlexander Motin 	sc = pi->pi_arg;
21719e749f25SAlexander Motin 	retval = 0;
21729e749f25SAlexander Motin 
21739e749f25SAlexander Motin 	pthread_mutex_lock(&sc->esc_mtx);
21749e749f25SAlexander Motin 
21759e749f25SAlexander Motin 	switch (baridx) {
21769e749f25SAlexander Motin 	case E82545_BAR_IO:
21779e749f25SAlexander Motin 		switch (offset) {
21789e749f25SAlexander Motin 		case E82545_IOADDR:
21799e749f25SAlexander Motin 			if (size != 4) {
2180332eff95SVincenzo Maffione 				DPRINTF("Wrong io addr read sz:%d", size);
21819e749f25SAlexander Motin 			} else
21829e749f25SAlexander Motin 				retval = sc->io_addr;
21839e749f25SAlexander Motin 			break;
21849e749f25SAlexander Motin 		case E82545_IODATA:
21859e749f25SAlexander Motin 			if (size != 4) {
2186332eff95SVincenzo Maffione 				DPRINTF("Wrong io data read sz:%d", size);
21879e749f25SAlexander Motin 			}
21889e749f25SAlexander Motin 			if (sc->io_addr > E82545_IO_REGISTER_MAX) {
2189332eff95SVincenzo Maffione 				DPRINTF("Non-register io read addr:0x%x",
21909e749f25SAlexander Motin 					sc->io_addr);
21919e749f25SAlexander Motin 			} else
21929e749f25SAlexander Motin 				retval = e82545_read_register(sc, sc->io_addr);
21939e749f25SAlexander Motin 			break;
21949e749f25SAlexander Motin 		default:
2195332eff95SVincenzo Maffione 			DPRINTF("Unknown io bar read offset:0x%lx size:%d",
21969e749f25SAlexander Motin 				offset, size);
21979e749f25SAlexander Motin 			break;
21989e749f25SAlexander Motin 		}
2199a88b19f9SAlexander Motin 		break;
22009e749f25SAlexander Motin 	case E82545_BAR_REGISTER:
22019e749f25SAlexander Motin 		if (size != 4) {
2202332eff95SVincenzo Maffione 			DPRINTF("Wrong register read size:%d offset:0x%lx",
22039e749f25SAlexander Motin 				size, offset);
22049e749f25SAlexander Motin 		} else
22059e749f25SAlexander Motin 			retval = e82545_read_register(sc, (uint32_t)offset);
22069e749f25SAlexander Motin 		break;
22079e749f25SAlexander Motin 	default:
2208332eff95SVincenzo Maffione 		DPRINTF("Unknown read bar:%d offset:0x%lx size:%d",
22099e749f25SAlexander Motin 			baridx, offset, size);
22109e749f25SAlexander Motin 		break;
22119e749f25SAlexander Motin 	}
22129e749f25SAlexander Motin 
22139e749f25SAlexander Motin 	pthread_mutex_unlock(&sc->esc_mtx);
22149e749f25SAlexander Motin 
22159e749f25SAlexander Motin 	return (retval);
22169e749f25SAlexander Motin }
22179e749f25SAlexander Motin 
22189e749f25SAlexander Motin static void
e82545_reset(struct e82545_softc * sc,int drvr)22199e749f25SAlexander Motin e82545_reset(struct e82545_softc *sc, int drvr)
22209e749f25SAlexander Motin {
22219e749f25SAlexander Motin 	int i;
22229e749f25SAlexander Motin 
22239e749f25SAlexander Motin 	e82545_rx_disable(sc);
22249e749f25SAlexander Motin 	e82545_tx_disable(sc);
22259e749f25SAlexander Motin 
22269e749f25SAlexander Motin 	/* clear outstanding interrupts */
22279e749f25SAlexander Motin 	if (sc->esc_irq_asserted)
22289e749f25SAlexander Motin 		pci_lintr_deassert(sc->esc_pi);
22299e749f25SAlexander Motin 
22309e749f25SAlexander Motin 	/* misc */
22319e749f25SAlexander Motin 	if (!drvr) {
22329e749f25SAlexander Motin 		sc->esc_FCAL = 0;
22339e749f25SAlexander Motin 		sc->esc_FCAH = 0;
22349e749f25SAlexander Motin 		sc->esc_FCT = 0;
22359e749f25SAlexander Motin 		sc->esc_VET = 0;
22369e749f25SAlexander Motin 		sc->esc_FCTTV = 0;
22379e749f25SAlexander Motin 	}
22389e749f25SAlexander Motin 	sc->esc_LEDCTL = 0x07061302;
22399e749f25SAlexander Motin 	sc->esc_PBA = 0x00100030;
22409e749f25SAlexander Motin 
22419e749f25SAlexander Motin 	/* start nvm in opcode mode. */
22429e749f25SAlexander Motin 	sc->nvm_opaddr = 0;
22439e749f25SAlexander Motin 	sc->nvm_mode = E82545_NVM_MODE_OPADDR;
22449e749f25SAlexander Motin 	sc->nvm_bits = E82545_NVM_OPADDR_BITS;
22459e749f25SAlexander Motin 	sc->eeprom_control = E1000_EECD_PRES | E82545_EECD_FWE_EN;
22469e749f25SAlexander Motin 	e82545_init_eeprom(sc);
22479e749f25SAlexander Motin 
22489e749f25SAlexander Motin 	/* interrupt */
22499e749f25SAlexander Motin 	sc->esc_ICR = 0;
22509e749f25SAlexander Motin 	sc->esc_ITR = 250;
22519e749f25SAlexander Motin 	sc->esc_ICS = 0;
22529e749f25SAlexander Motin 	sc->esc_IMS = 0;
22539e749f25SAlexander Motin 	sc->esc_IMC = 0;
22549e749f25SAlexander Motin 
22559e749f25SAlexander Motin 	/* L2 filters */
22569e749f25SAlexander Motin 	if (!drvr) {
22579e749f25SAlexander Motin 		memset(sc->esc_fvlan, 0, sizeof(sc->esc_fvlan));
22589e749f25SAlexander Motin 		memset(sc->esc_fmcast, 0, sizeof(sc->esc_fmcast));
22599e749f25SAlexander Motin 		memset(sc->esc_uni, 0, sizeof(sc->esc_uni));
22609e749f25SAlexander Motin 
22619e749f25SAlexander Motin 		/* XXX not necessary on 82545 ?? */
22629e749f25SAlexander Motin 		sc->esc_uni[0].eu_valid = 1;
22639e749f25SAlexander Motin 		memcpy(sc->esc_uni[0].eu_eth.octet, sc->esc_mac.octet,
22649e749f25SAlexander Motin 		    ETHER_ADDR_LEN);
22659e749f25SAlexander Motin 	} else {
22669e749f25SAlexander Motin 		/* Clear RAH valid bits */
22679e749f25SAlexander Motin 		for (i = 0; i < 16; i++)
22689e749f25SAlexander Motin 			sc->esc_uni[i].eu_valid = 0;
22699e749f25SAlexander Motin 	}
22709e749f25SAlexander Motin 
22719e749f25SAlexander Motin 	/* receive */
22729e749f25SAlexander Motin 	if (!drvr) {
22739e749f25SAlexander Motin 		sc->esc_RDBAL = 0;
22749e749f25SAlexander Motin 		sc->esc_RDBAH = 0;
22759e749f25SAlexander Motin 	}
22769e749f25SAlexander Motin 	sc->esc_RCTL = 0;
22779e749f25SAlexander Motin 	sc->esc_FCRTL = 0;
22789e749f25SAlexander Motin 	sc->esc_FCRTH = 0;
22799e749f25SAlexander Motin 	sc->esc_RDLEN = 0;
22809e749f25SAlexander Motin 	sc->esc_RDH = 0;
22819e749f25SAlexander Motin 	sc->esc_RDT = 0;
22829e749f25SAlexander Motin 	sc->esc_RDTR = 0;
22839e749f25SAlexander Motin 	sc->esc_RXDCTL = (1 << 24) | (1 << 16); /* default GRAN/WTHRESH */
22849e749f25SAlexander Motin 	sc->esc_RADV = 0;
22859e749f25SAlexander Motin 	sc->esc_RXCSUM = 0;
22869e749f25SAlexander Motin 
22879e749f25SAlexander Motin 	/* transmit */
22889e749f25SAlexander Motin 	if (!drvr) {
22899e749f25SAlexander Motin 		sc->esc_TDBAL = 0;
22909e749f25SAlexander Motin 		sc->esc_TDBAH = 0;
22919e749f25SAlexander Motin 		sc->esc_TIPG = 0;
22929e749f25SAlexander Motin 		sc->esc_AIT = 0;
22939e749f25SAlexander Motin 		sc->esc_TIDV = 0;
22949e749f25SAlexander Motin 		sc->esc_TADV = 0;
22959e749f25SAlexander Motin 	}
22969e749f25SAlexander Motin 	sc->esc_tdba = 0;
22979e749f25SAlexander Motin 	sc->esc_txdesc = NULL;
22989e749f25SAlexander Motin 	sc->esc_TXCW = 0;
22999e749f25SAlexander Motin 	sc->esc_TCTL = 0;
23009e749f25SAlexander Motin 	sc->esc_TDLEN = 0;
23019e749f25SAlexander Motin 	sc->esc_TDT = 0;
23029e749f25SAlexander Motin 	sc->esc_TDHr = sc->esc_TDH = 0;
23039e749f25SAlexander Motin 	sc->esc_TXDCTL = 0;
23049e749f25SAlexander Motin }
23059e749f25SAlexander Motin 
23069e749f25SAlexander Motin static int
e82545_init(struct pci_devinst * pi,nvlist_t * nvl)23076a284cacSJohn Baldwin e82545_init(struct pci_devinst *pi, nvlist_t *nvl)
23089e749f25SAlexander Motin {
23099e749f25SAlexander Motin 	char nstr[80];
23109e749f25SAlexander Motin 	struct e82545_softc *sc;
2311621b5090SJohn Baldwin 	const char *mac;
2312621b5090SJohn Baldwin 	int err;
23134f7c3b7bSVincenzo Maffione 
23149e749f25SAlexander Motin 	/* Setup our softc */
23159287c032SMarcelo Araujo 	sc = calloc(1, sizeof(*sc));
23169e749f25SAlexander Motin 
23179e749f25SAlexander Motin 	pi->pi_arg = sc;
23189e749f25SAlexander Motin 	sc->esc_pi = pi;
23196a284cacSJohn Baldwin 	sc->esc_ctx = pi->pi_vmctx;
23209e749f25SAlexander Motin 
23219e749f25SAlexander Motin 	pthread_mutex_init(&sc->esc_mtx, NULL);
23229e749f25SAlexander Motin 	pthread_cond_init(&sc->esc_rx_cond, NULL);
23239e749f25SAlexander Motin 	pthread_cond_init(&sc->esc_tx_cond, NULL);
23249e749f25SAlexander Motin 	pthread_create(&sc->esc_tx_tid, NULL, e82545_tx_thread, sc);
23259e749f25SAlexander Motin 	snprintf(nstr, sizeof(nstr), "e82545-%d:%d tx", pi->pi_slot,
23269e749f25SAlexander Motin 	    pi->pi_func);
23279e749f25SAlexander Motin         pthread_set_name_np(sc->esc_tx_tid, nstr);
23289e749f25SAlexander Motin 
23299e749f25SAlexander Motin 	pci_set_cfgdata16(pi, PCIR_DEVICE, E82545_DEV_ID_82545EM_COPPER);
23309e749f25SAlexander Motin 	pci_set_cfgdata16(pi, PCIR_VENDOR, E82545_VENDOR_ID_INTEL);
23319e749f25SAlexander Motin 	pci_set_cfgdata8(pi,  PCIR_CLASS, PCIC_NETWORK);
23329e749f25SAlexander Motin 	pci_set_cfgdata8(pi, PCIR_SUBCLASS, PCIS_NETWORK_ETHERNET);
23339e749f25SAlexander Motin 	pci_set_cfgdata16(pi, PCIR_SUBDEV_0, E82545_SUBDEV_ID);
23349e749f25SAlexander Motin 	pci_set_cfgdata16(pi, PCIR_SUBVEND_0, E82545_VENDOR_ID_INTEL);
23359e749f25SAlexander Motin 
23369e749f25SAlexander Motin 	pci_set_cfgdata8(pi,  PCIR_HDRTYPE, PCIM_HDRTYPE_NORMAL);
23379e749f25SAlexander Motin 	pci_set_cfgdata8(pi,  PCIR_INTPIN, 0x1);
23389e749f25SAlexander Motin 
23399e749f25SAlexander Motin 	/* TODO: this card also supports msi, but the freebsd driver for it
23409e749f25SAlexander Motin 	 * does not, so I have not implemented it. */
23419e749f25SAlexander Motin 	pci_lintr_request(pi);
23429e749f25SAlexander Motin 
23439e749f25SAlexander Motin 	pci_emul_alloc_bar(pi, E82545_BAR_REGISTER, PCIBAR_MEM32,
23449e749f25SAlexander Motin 		E82545_BAR_REGISTER_LEN);
23459e749f25SAlexander Motin 	pci_emul_alloc_bar(pi, E82545_BAR_FLASH, PCIBAR_MEM32,
23469e749f25SAlexander Motin 		E82545_BAR_FLASH_LEN);
23479e749f25SAlexander Motin 	pci_emul_alloc_bar(pi, E82545_BAR_IO, PCIBAR_IO,
23489e749f25SAlexander Motin 		E82545_BAR_IO_LEN);
23499e749f25SAlexander Motin 
2350621b5090SJohn Baldwin 	mac = get_config_value_node(nvl, "mac");
2351621b5090SJohn Baldwin 	if (mac != NULL) {
2352621b5090SJohn Baldwin 		err = net_parsemac(mac, sc->esc_mac.octet);
235366c662b0SVincenzo Maffione 		if (err) {
23545bebe923SAleksandr Fedorov 			free(sc);
23559e749f25SAlexander Motin 			return (err);
23569e749f25SAlexander Motin 		}
2357621b5090SJohn Baldwin 	} else
23584f7c3b7bSVincenzo Maffione 		net_genmac(pi, sc->esc_mac.octet);
2359621b5090SJohn Baldwin 
2360621b5090SJohn Baldwin 	err = netbe_init(&sc->esc_be, nvl, e82545_rx_callback, sc);
2361621b5090SJohn Baldwin 	if (err) {
2362621b5090SJohn Baldwin 		free(sc);
2363621b5090SJohn Baldwin 		return (err);
23649e749f25SAlexander Motin 	}
23659e749f25SAlexander Motin 
23663e11768eSVincenzo Maffione 	netbe_rx_enable(sc->esc_be);
23673e11768eSVincenzo Maffione 
23689e749f25SAlexander Motin 	/* H/w initiated reset */
23699e749f25SAlexander Motin 	e82545_reset(sc, 0);
23709e749f25SAlexander Motin 
23719e749f25SAlexander Motin 	return (0);
23729e749f25SAlexander Motin }
23739e749f25SAlexander Motin 
2374483d953aSJohn Baldwin #ifdef BHYVE_SNAPSHOT
2375483d953aSJohn Baldwin static int
e82545_snapshot(struct vm_snapshot_meta * meta)2376483d953aSJohn Baldwin e82545_snapshot(struct vm_snapshot_meta *meta)
2377483d953aSJohn Baldwin {
2378483d953aSJohn Baldwin 	int i;
2379483d953aSJohn Baldwin 	int ret;
2380483d953aSJohn Baldwin 	struct e82545_softc *sc;
2381483d953aSJohn Baldwin 	struct pci_devinst *pi;
2382483d953aSJohn Baldwin 	uint64_t bitmap_value;
2383483d953aSJohn Baldwin 
2384483d953aSJohn Baldwin 	pi = meta->dev_data;
2385483d953aSJohn Baldwin 	sc = pi->pi_arg;
2386483d953aSJohn Baldwin 
2387483d953aSJohn Baldwin 	/* esc_mevp and esc_mevpitr should be reinitiated at init. */
2388483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->esc_mac, meta, ret, done);
2389483d953aSJohn Baldwin 
2390483d953aSJohn Baldwin 	/* General */
2391483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->esc_CTRL, meta, ret, done);
2392483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->esc_FCAL, meta, ret, done);
2393483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->esc_FCAH, meta, ret, done);
2394483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->esc_FCT, meta, ret, done);
2395483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->esc_VET, meta, ret, done);
2396483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->esc_FCTTV, meta, ret, done);
2397483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->esc_LEDCTL, meta, ret, done);
2398483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->esc_PBA, meta, ret, done);
2399483d953aSJohn Baldwin 
2400483d953aSJohn Baldwin 	/* Interrupt control */
2401483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->esc_irq_asserted, meta, ret, done);
2402483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->esc_ICR, meta, ret, done);
2403483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->esc_ITR, meta, ret, done);
2404483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->esc_ICS, meta, ret, done);
2405483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->esc_IMS, meta, ret, done);
2406483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->esc_IMC, meta, ret, done);
2407483d953aSJohn Baldwin 
2408483d953aSJohn Baldwin 	/*
2409483d953aSJohn Baldwin 	 * Transmit
2410483d953aSJohn Baldwin 	 *
2411483d953aSJohn Baldwin 	 * The fields in the unions are in superposition to access certain
2412483d953aSJohn Baldwin 	 * bytes in the larger uint variables.
2413483d953aSJohn Baldwin 	 * e.g., ip_config = [ipcss|ipcso|ipcse0|ipcse1]
2414483d953aSJohn Baldwin 	 */
2415483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->esc_txctx.lower_setup.ip_config, meta, ret, done);
2416483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->esc_txctx.upper_setup.tcp_config, meta, ret, done);
2417483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->esc_txctx.cmd_and_length, meta, ret, done);
2418483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->esc_txctx.tcp_seg_setup.data, meta, ret, done);
2419483d953aSJohn Baldwin 
2420483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->esc_tx_enabled, meta, ret, done);
2421483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->esc_tx_active, meta, ret, done);
2422483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->esc_TXCW, meta, ret, done);
2423483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->esc_TCTL, meta, ret, done);
2424483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->esc_TIPG, meta, ret, done);
2425483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->esc_AIT, meta, ret, done);
2426483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->esc_tdba, meta, ret, done);
2427483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->esc_TDBAL, meta, ret, done);
2428483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->esc_TDBAH, meta, ret, done);
2429483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->esc_TDLEN, meta, ret, done);
2430483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->esc_TDH, meta, ret, done);
2431483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->esc_TDHr, meta, ret, done);
2432483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->esc_TDT, meta, ret, done);
2433483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->esc_TIDV, meta, ret, done);
2434483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->esc_TXDCTL, meta, ret, done);
2435483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->esc_TADV, meta, ret, done);
2436483d953aSJohn Baldwin 
2437483d953aSJohn Baldwin 	/* Has dependency on esc_TDLEN; reoreder of fields from struct. */
24380f735657SJohn Baldwin 	SNAPSHOT_GUEST2HOST_ADDR_OR_LEAVE(pi->pi_vmctx, sc->esc_txdesc,
24390f735657SJohn Baldwin 	    sc->esc_TDLEN, true, meta, ret, done);
2440483d953aSJohn Baldwin 
2441483d953aSJohn Baldwin 	/* L2 frame acceptance */
2442ed721684SMark Johnston 	for (i = 0; i < (int)nitems(sc->esc_uni); i++) {
2443483d953aSJohn Baldwin 		SNAPSHOT_VAR_OR_LEAVE(sc->esc_uni[i].eu_valid, meta, ret, done);
2444483d953aSJohn Baldwin 		SNAPSHOT_VAR_OR_LEAVE(sc->esc_uni[i].eu_addrsel, meta, ret, done);
2445483d953aSJohn Baldwin 		SNAPSHOT_VAR_OR_LEAVE(sc->esc_uni[i].eu_eth, meta, ret, done);
2446483d953aSJohn Baldwin 	}
2447483d953aSJohn Baldwin 
2448483d953aSJohn Baldwin 	SNAPSHOT_BUF_OR_LEAVE(sc->esc_fmcast, sizeof(sc->esc_fmcast),
2449483d953aSJohn Baldwin 			      meta, ret, done);
2450483d953aSJohn Baldwin 	SNAPSHOT_BUF_OR_LEAVE(sc->esc_fvlan, sizeof(sc->esc_fvlan),
2451483d953aSJohn Baldwin 			      meta, ret, done);
2452483d953aSJohn Baldwin 
2453483d953aSJohn Baldwin 	/* Receive */
2454483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->esc_rx_enabled, meta, ret, done);
2455483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->esc_rx_active, meta, ret, done);
2456483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->esc_rx_loopback, meta, ret, done);
2457483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->esc_RCTL, meta, ret, done);
2458483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->esc_FCRTL, meta, ret, done);
2459483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->esc_FCRTH, meta, ret, done);
2460483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->esc_rdba, meta, ret, done);
2461483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->esc_RDBAL, meta, ret, done);
2462483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->esc_RDBAH, meta, ret, done);
2463483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->esc_RDLEN, meta, ret, done);
2464483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->esc_RDH, meta, ret, done);
2465483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->esc_RDT, meta, ret, done);
2466483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->esc_RDTR, meta, ret, done);
2467483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->esc_RXDCTL, meta, ret, done);
2468483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->esc_RADV, meta, ret, done);
2469483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->esc_RSRPD, meta, ret, done);
2470483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->esc_RXCSUM, meta, ret, done);
2471483d953aSJohn Baldwin 
2472483d953aSJohn Baldwin 	/* Has dependency on esc_RDLEN; reoreder of fields from struct. */
24730f735657SJohn Baldwin 	SNAPSHOT_GUEST2HOST_ADDR_OR_LEAVE(pi->pi_vmctx, sc->esc_rxdesc,
24740f735657SJohn Baldwin 	    sc->esc_TDLEN, true, meta, ret, done);
2475483d953aSJohn Baldwin 
2476483d953aSJohn Baldwin 	/* IO Port register access */
2477483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->io_addr, meta, ret, done);
2478483d953aSJohn Baldwin 
2479483d953aSJohn Baldwin 	/* Shadow copy of MDIC */
2480483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->mdi_control, meta, ret, done);
2481483d953aSJohn Baldwin 
2482483d953aSJohn Baldwin 	/* Shadow copy of EECD */
2483483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->eeprom_control, meta, ret, done);
2484483d953aSJohn Baldwin 
2485483d953aSJohn Baldwin 	/* Latest NVM in/out */
2486483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->nvm_data, meta, ret, done);
2487483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->nvm_opaddr, meta, ret, done);
2488483d953aSJohn Baldwin 
2489483d953aSJohn Baldwin 	/* Stats */
2490483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->missed_pkt_count, meta, ret, done);
2491483d953aSJohn Baldwin 	SNAPSHOT_BUF_OR_LEAVE(sc->pkt_rx_by_size, sizeof(sc->pkt_rx_by_size),
2492483d953aSJohn Baldwin 			      meta, ret, done);
2493483d953aSJohn Baldwin 	SNAPSHOT_BUF_OR_LEAVE(sc->pkt_tx_by_size, sizeof(sc->pkt_tx_by_size),
2494483d953aSJohn Baldwin 			      meta, ret, done);
2495483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->good_pkt_rx_count, meta, ret, done);
2496483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->bcast_pkt_rx_count, meta, ret, done);
2497483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->mcast_pkt_rx_count, meta, ret, done);
2498483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->good_pkt_tx_count, meta, ret, done);
2499483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->bcast_pkt_tx_count, meta, ret, done);
2500483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->mcast_pkt_tx_count, meta, ret, done);
2501483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->oversize_rx_count, meta, ret, done);
2502483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->tso_tx_count, meta, ret, done);
2503483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->good_octets_rx, meta, ret, done);
2504483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->good_octets_tx, meta, ret, done);
2505483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->missed_octets, meta, ret, done);
2506483d953aSJohn Baldwin 
2507483d953aSJohn Baldwin 	if (meta->op == VM_SNAPSHOT_SAVE)
2508483d953aSJohn Baldwin 		bitmap_value = sc->nvm_bits;
2509483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(bitmap_value, meta, ret, done);
2510483d953aSJohn Baldwin 	if (meta->op == VM_SNAPSHOT_RESTORE)
2511483d953aSJohn Baldwin 		sc->nvm_bits = bitmap_value;
2512483d953aSJohn Baldwin 
2513483d953aSJohn Baldwin 	if (meta->op == VM_SNAPSHOT_SAVE)
2514483d953aSJohn Baldwin 		bitmap_value = sc->nvm_bits;
2515483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(bitmap_value, meta, ret, done);
2516483d953aSJohn Baldwin 	if (meta->op == VM_SNAPSHOT_RESTORE)
2517483d953aSJohn Baldwin 		sc->nvm_bits = bitmap_value;
2518483d953aSJohn Baldwin 
2519483d953aSJohn Baldwin 	/* EEPROM data */
2520483d953aSJohn Baldwin 	SNAPSHOT_BUF_OR_LEAVE(sc->eeprom_data, sizeof(sc->eeprom_data),
2521483d953aSJohn Baldwin 			      meta, ret, done);
2522483d953aSJohn Baldwin 
2523483d953aSJohn Baldwin done:
2524483d953aSJohn Baldwin 	return (ret);
2525483d953aSJohn Baldwin }
2526483d953aSJohn Baldwin #endif
2527483d953aSJohn Baldwin 
252837045dfaSMark Johnston static const struct pci_devemu pci_de_e82545 = {
25299e749f25SAlexander Motin 	.pe_emu = 	"e1000",
25309e749f25SAlexander Motin 	.pe_init =	e82545_init,
2531621b5090SJohn Baldwin 	.pe_legacy_config = netbe_legacy_config,
25329e749f25SAlexander Motin 	.pe_barwrite =	e82545_write,
2533483d953aSJohn Baldwin 	.pe_barread =	e82545_read,
2534483d953aSJohn Baldwin #ifdef BHYVE_SNAPSHOT
2535483d953aSJohn Baldwin 	.pe_snapshot =	e82545_snapshot,
2536483d953aSJohn Baldwin #endif
25379e749f25SAlexander Motin };
25389e749f25SAlexander Motin PCI_EMUL_SET(pci_de_e82545);
2539