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