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