1302504Smav/*
2302504Smav * Copyright (c) 2016 Alexander Motin <mav@FreeBSD.org>
3302504Smav * Copyright (c) 2015 Peter Grehan <grehan@freebsd.org>
4302504Smav * Copyright (c) 2013 Jeremiah Lott, Avere Systems
5302504Smav * All rights reserved.
6302504Smav *
7302504Smav * Redistribution and use in source and binary forms, with or without
8302504Smav * modification, are permitted provided that the following conditions
9302504Smav * are met:
10302504Smav * 1. Redistributions of source code must retain the above copyright
11302504Smav *    notice, this list of conditions and the following disclaimer
12302504Smav *    in this position and unchanged.
13302504Smav * 2. Redistributions in binary form must reproduce the above copyright
14302504Smav *    notice, this list of conditions and the following disclaimer in the
15302504Smav *    documentation and/or other materials provided with the distribution.
16302504Smav *
17302504Smav * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18302504Smav * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19302504Smav * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20302504Smav * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21302504Smav * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22302504Smav * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23302504Smav * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24302504Smav * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25302504Smav * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26302504Smav * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27302504Smav * SUCH DAMAGE.
28302504Smav */
29302504Smav
30302504Smav#include <sys/cdefs.h>
31302504Smav__FBSDID("$FreeBSD$");
32302504Smav
33302504Smav#include <sys/types.h>
34302504Smav#include <sys/limits.h>
35302504Smav#include <sys/ioctl.h>
36302504Smav#include <sys/uio.h>
37302504Smav#include <net/ethernet.h>
38302504Smav#include <netinet/in.h>
39302504Smav#include <netinet/tcp.h>
40302504Smav
41302504Smav#include <errno.h>
42302504Smav#include <fcntl.h>
43302504Smav#include <md5.h>
44302504Smav#include <stdio.h>
45302504Smav#include <stdlib.h>
46302504Smav#include <string.h>
47302504Smav#include <unistd.h>
48302504Smav#include <pthread.h>
49302504Smav#include <pthread_np.h>
50302504Smav
51302504Smav#include "e1000_regs.h"
52302504Smav#include "e1000_defines.h"
53302504Smav#include "mii.h"
54302504Smav
55302504Smav#include "bhyverun.h"
56302504Smav#include "pci_emul.h"
57302504Smav#include "mevent.h"
58302504Smav
59302504Smav/* Hardware/register definitions XXX: move some to common code. */
60302504Smav#define E82545_VENDOR_ID_INTEL			0x8086
61302504Smav#define E82545_DEV_ID_82545EM_COPPER		0x100F
62302504Smav#define E82545_SUBDEV_ID			0x1008
63302504Smav
64302504Smav#define E82545_REVISION_4			4
65302504Smav
66302504Smav#define E82545_MDIC_DATA_MASK			0x0000FFFF
67302504Smav#define E82545_MDIC_OP_MASK			0x0c000000
68302504Smav#define E82545_MDIC_IE				0x20000000
69302504Smav
70302504Smav#define E82545_EECD_FWE_DIS	0x00000010 /* Flash writes disabled */
71302504Smav#define E82545_EECD_FWE_EN	0x00000020 /* Flash writes enabled */
72302504Smav#define E82545_EECD_FWE_MASK	0x00000030 /* Flash writes mask */
73302504Smav
74302504Smav#define E82545_BAR_REGISTER			0
75302504Smav#define E82545_BAR_REGISTER_LEN			(128*1024)
76302504Smav#define E82545_BAR_FLASH			1
77302504Smav#define E82545_BAR_FLASH_LEN			(64*1024)
78302504Smav#define E82545_BAR_IO				2
79302504Smav#define E82545_BAR_IO_LEN			8
80302504Smav
81302504Smav#define E82545_IOADDR				0x00000000
82302504Smav#define E82545_IODATA				0x00000004
83302504Smav#define E82545_IO_REGISTER_MAX			0x0001FFFF
84302504Smav#define E82545_IO_FLASH_BASE			0x00080000
85302504Smav#define E82545_IO_FLASH_MAX			0x000FFFFF
86302504Smav
87302504Smav#define E82545_ARRAY_ENTRY(reg, offset)		(reg + (offset<<2))
88302504Smav#define E82545_RAR_MAX				15
89302504Smav#define E82545_MTA_MAX				127
90302504Smav#define E82545_VFTA_MAX				127
91302504Smav
92302504Smav/* Slightly modified from the driver versions, hardcoded for 3 opcode bits,
93302504Smav * followed by 6 address bits.
94302504Smav * TODO: make opcode bits and addr bits configurable?
95302504Smav * NVM Commands - Microwire */
96302504Smav#define E82545_NVM_OPCODE_BITS	3
97302504Smav#define E82545_NVM_ADDR_BITS	6
98302504Smav#define E82545_NVM_DATA_BITS	16
99302504Smav#define E82545_NVM_OPADDR_BITS	(E82545_NVM_OPCODE_BITS + E82545_NVM_ADDR_BITS)
100302504Smav#define E82545_NVM_ADDR_MASK	((1 << E82545_NVM_ADDR_BITS)-1)
101302504Smav#define E82545_NVM_OPCODE_MASK	\
102302504Smav    (((1 << E82545_NVM_OPCODE_BITS) - 1) << E82545_NVM_ADDR_BITS)
103302504Smav#define E82545_NVM_OPCODE_READ	(0x6 << E82545_NVM_ADDR_BITS)	/* read */
104302504Smav#define E82545_NVM_OPCODE_WRITE	(0x5 << E82545_NVM_ADDR_BITS)	/* write */
105302504Smav#define E82545_NVM_OPCODE_ERASE	(0x7 << E82545_NVM_ADDR_BITS)	/* erase */
106302504Smav#define	E82545_NVM_OPCODE_EWEN	(0x4 << E82545_NVM_ADDR_BITS)	/* wr-enable */
107302504Smav
108302504Smav#define	E82545_NVM_EEPROM_SIZE	64 /* 64 * 16-bit values == 128K */
109302504Smav
110302504Smav#define E1000_ICR_SRPD		0x00010000
111302504Smav
112304425Smav/* This is an arbitrary number.  There is no hard limit on the chip. */
113304425Smav#define I82545_MAX_TXSEGS	64
114302504Smav
115302504Smav/* Legacy receive descriptor */
116302504Smavstruct e1000_rx_desc {
117302504Smav	uint64_t buffer_addr;	/* Address of the descriptor's data buffer */
118302504Smav	uint16_t length;	/* Length of data DMAed into data buffer */
119302504Smav	uint16_t csum;		/* Packet checksum */
120302504Smav	uint8_t	 status;       	/* Descriptor status */
121302504Smav	uint8_t  errors;	/* Descriptor Errors */
122302504Smav	uint16_t special;
123302504Smav};
124302504Smav
125302504Smav/* Transmit descriptor types */
126302504Smav#define	E1000_TXD_MASK		(E1000_TXD_CMD_DEXT | 0x00F00000)
127302504Smav#define E1000_TXD_TYP_L		(0)
128302504Smav#define E1000_TXD_TYP_C		(E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_C)
129302504Smav#define E1000_TXD_TYP_D		(E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D)
130302504Smav
131302504Smav/* Legacy transmit descriptor */
132302504Smavstruct e1000_tx_desc {
133302504Smav	uint64_t buffer_addr;   /* Address of the descriptor's data buffer */
134302504Smav	union {
135302504Smav		uint32_t data;
136302504Smav		struct {
137302504Smav			uint16_t length;  /* Data buffer length */
138302504Smav			uint8_t  cso;  /* Checksum offset */
139302504Smav			uint8_t  cmd;  /* Descriptor control */
140302504Smav		} flags;
141302504Smav	} lower;
142302504Smav	union {
143302504Smav		uint32_t data;
144302504Smav		struct {
145302504Smav			uint8_t status; /* Descriptor status */
146302504Smav			uint8_t css;  /* Checksum start */
147302504Smav			uint16_t special;
148302504Smav		} fields;
149302504Smav	} upper;
150302504Smav};
151302504Smav
152302504Smav/* Context descriptor */
153302504Smavstruct e1000_context_desc {
154302504Smav	union {
155302504Smav		uint32_t ip_config;
156302504Smav		struct {
157302504Smav			uint8_t ipcss;  /* IP checksum start */
158302504Smav			uint8_t ipcso;  /* IP checksum offset */
159302504Smav			uint16_t ipcse;  /* IP checksum end */
160302504Smav		} ip_fields;
161302504Smav	} lower_setup;
162302504Smav	union {
163302504Smav		uint32_t tcp_config;
164302504Smav		struct {
165302504Smav			uint8_t tucss;  /* TCP checksum start */
166302504Smav			uint8_t tucso;  /* TCP checksum offset */
167302504Smav			uint16_t tucse;  /* TCP checksum end */
168302504Smav		} tcp_fields;
169302504Smav	} upper_setup;
170302504Smav	uint32_t cmd_and_length;
171302504Smav	union {
172302504Smav		uint32_t data;
173302504Smav		struct {
174302504Smav			uint8_t status;  /* Descriptor status */
175302504Smav			uint8_t hdr_len;  /* Header length */
176302504Smav			uint16_t mss;  /* Maximum segment size */
177302504Smav		} fields;
178302504Smav	} tcp_seg_setup;
179302504Smav};
180302504Smav
181302504Smav/* Data descriptor */
182302504Smavstruct e1000_data_desc {
183302504Smav	uint64_t buffer_addr;  /* Address of the descriptor's buffer address */
184302504Smav	union {
185302504Smav		uint32_t data;
186302504Smav		struct {
187302504Smav			uint16_t length;  /* Data buffer length */
188302504Smav			uint8_t typ_len_ext;
189302504Smav			uint8_t cmd;
190302504Smav		} flags;
191302504Smav	} lower;
192302504Smav	union {
193302504Smav		uint32_t data;
194302504Smav		struct {
195302504Smav			uint8_t status;  /* Descriptor status */
196302504Smav			uint8_t popts;  /* Packet Options */
197302504Smav			uint16_t special;
198302504Smav		} fields;
199302504Smav	} upper;
200302504Smav};
201302504Smav
202302504Smavunion e1000_tx_udesc {
203302504Smav	struct e1000_tx_desc td;
204302504Smav	struct e1000_context_desc cd;
205302504Smav	struct e1000_data_desc dd;
206302504Smav};
207302504Smav
208302504Smav/* Tx checksum info for a packet. */
209302504Smavstruct ck_info {
210302504Smav	int	ck_valid;	/* ck_info is valid */
211302504Smav	uint8_t	ck_start;	/* start byte of cksum calcuation */
212302504Smav	uint8_t	ck_off;		/* offset of cksum insertion */
213302504Smav	uint16_t ck_len;	/* length of cksum calc: 0 is to packet-end */
214302504Smav};
215302504Smav
216302504Smav/*
217302504Smav * Debug printf
218302504Smav */
219302504Smavstatic int e82545_debug = 0;
220302504Smav#define DPRINTF(msg,params...) if (e82545_debug) fprintf(stderr, "e82545: " msg, params)
221302504Smav#define WPRINTF(msg,params...) fprintf(stderr, "e82545: " msg, params)
222302504Smav
223302504Smav#define	MIN(a,b) (((a)<(b))?(a):(b))
224302504Smav#define	MAX(a,b) (((a)>(b))?(a):(b))
225302504Smav
226302504Smav/* s/w representation of the RAL/RAH regs */
227302504Smavstruct  eth_uni {
228302504Smav	int		eu_valid;
229302504Smav	int		eu_addrsel;
230302504Smav	struct ether_addr eu_eth;
231302504Smav};
232302504Smav
233302504Smav
234302504Smavstruct e82545_softc {
235302504Smav	struct pci_devinst *esc_pi;
236302504Smav	struct vmctx	*esc_ctx;
237302504Smav	struct mevent   *esc_mevp;
238302504Smav	struct mevent   *esc_mevpitr;
239302504Smav	pthread_mutex_t	esc_mtx;
240302504Smav	struct ether_addr esc_mac;
241302504Smav	int		esc_tapfd;
242302504Smav
243302504Smav	/* General */
244302504Smav	uint32_t	esc_CTRL;	/* x0000 device ctl */
245302504Smav	uint32_t	esc_FCAL;	/* x0028 flow ctl addr lo */
246302504Smav	uint32_t	esc_FCAH;	/* x002C flow ctl addr hi */
247302504Smav	uint32_t	esc_FCT;	/* x0030 flow ctl type */
248302504Smav	uint32_t	esc_VET;	/* x0038 VLAN eth type */
249302504Smav	uint32_t	esc_FCTTV;	/* x0170 flow ctl tx timer */
250302504Smav	uint32_t	esc_LEDCTL;	/* x0E00 LED control */
251302504Smav	uint32_t	esc_PBA;	/* x1000 pkt buffer allocation */
252302504Smav
253302504Smav	/* Interrupt control */
254302504Smav	int		esc_irq_asserted;
255302504Smav	uint32_t	esc_ICR;	/* x00C0 cause read/clear */
256302504Smav	uint32_t	esc_ITR;	/* x00C4 intr throttling */
257302504Smav	uint32_t	esc_ICS;	/* x00C8 cause set */
258302504Smav	uint32_t	esc_IMS;	/* x00D0 mask set/read */
259302504Smav	uint32_t	esc_IMC;	/* x00D8 mask clear */
260302504Smav
261302504Smav	/* Transmit */
262302504Smav	union e1000_tx_udesc *esc_txdesc;
263302504Smav	struct e1000_context_desc esc_txctx;
264302504Smav	pthread_t	esc_tx_tid;
265302504Smav	pthread_cond_t	esc_tx_cond;
266302504Smav	int		esc_tx_enabled;
267302504Smav	int		esc_tx_active;
268302504Smav	uint32_t	esc_TXCW;	/* x0178 transmit config */
269302504Smav	uint32_t	esc_TCTL;	/* x0400 transmit ctl */
270302504Smav	uint32_t	esc_TIPG;	/* x0410 inter-packet gap */
271302504Smav	uint16_t	esc_AIT;	/* x0458 Adaptive Interframe Throttle */
272302504Smav	uint64_t	esc_tdba;      	/* verified 64-bit desc table addr */
273302504Smav	uint32_t	esc_TDBAL;	/* x3800 desc table addr, low bits */
274302504Smav	uint32_t	esc_TDBAH;	/* x3804 desc table addr, hi 32-bits */
275302504Smav	uint32_t	esc_TDLEN;	/* x3808 # descriptors in bytes */
276302504Smav	uint16_t	esc_TDH;	/* x3810 desc table head idx */
277302504Smav	uint16_t	esc_TDHr;	/* internal read version of TDH */
278302504Smav	uint16_t	esc_TDT;	/* x3818 desc table tail idx */
279302504Smav	uint32_t	esc_TIDV;	/* x3820 intr delay */
280302504Smav	uint32_t	esc_TXDCTL;	/* x3828 desc control */
281302504Smav	uint32_t	esc_TADV;	/* x382C intr absolute delay */
282302504Smav
283302504Smav	/* L2 frame acceptance */
284302504Smav	struct eth_uni	esc_uni[16];	/* 16 x unicast MAC addresses */
285302504Smav	uint32_t	esc_fmcast[128]; /* Multicast filter bit-match */
286302504Smav	uint32_t	esc_fvlan[128]; /* VLAN 4096-bit filter */
287302504Smav
288302504Smav	/* Receive */
289302504Smav	struct e1000_rx_desc *esc_rxdesc;
290302504Smav	pthread_cond_t	esc_rx_cond;
291302504Smav	int		esc_rx_enabled;
292302504Smav	int		esc_rx_active;
293302504Smav	int		esc_rx_loopback;
294302504Smav	uint32_t	esc_RCTL;	/* x0100 receive ctl */
295302504Smav	uint32_t	esc_FCRTL;	/* x2160 flow cntl thresh, low */
296302504Smav	uint32_t	esc_FCRTH;	/* x2168 flow cntl thresh, hi */
297302504Smav	uint64_t	esc_rdba;	/* verified 64-bit desc table addr */
298302504Smav	uint32_t	esc_RDBAL;	/* x2800 desc table addr, low bits */
299302504Smav	uint32_t	esc_RDBAH;	/* x2804 desc table addr, hi 32-bits*/
300302504Smav	uint32_t	esc_RDLEN;	/* x2808 #descriptors */
301302504Smav	uint16_t	esc_RDH;	/* x2810 desc table head idx */
302302504Smav	uint16_t	esc_RDT;	/* x2818 desc table tail idx */
303302504Smav	uint32_t	esc_RDTR;	/* x2820 intr delay */
304302504Smav	uint32_t	esc_RXDCTL;	/* x2828 desc control */
305302504Smav	uint32_t	esc_RADV;	/* x282C intr absolute delay */
306302504Smav	uint32_t	esc_RSRPD;	/* x2C00 recv small packet detect */
307302504Smav	uint32_t	esc_RXCSUM;     /* x5000 receive cksum ctl */
308302504Smav
309302504Smav	/* IO Port register access */
310302504Smav	uint32_t io_addr;
311302504Smav
312302504Smav	/* Shadow copy of MDIC */
313302504Smav	uint32_t mdi_control;
314302504Smav	/* Shadow copy of EECD */
315302504Smav	uint32_t eeprom_control;
316302504Smav	/* Latest NVM in/out */
317302504Smav	uint16_t nvm_data;
318302504Smav	uint16_t nvm_opaddr;
319302504Smav	/* stats */
320302504Smav	uint32_t missed_pkt_count; /* dropped for no room in rx queue */
321302504Smav	uint32_t pkt_rx_by_size[6];
322302504Smav	uint32_t pkt_tx_by_size[6];
323302504Smav	uint32_t good_pkt_rx_count;
324302504Smav	uint32_t bcast_pkt_rx_count;
325302504Smav	uint32_t mcast_pkt_rx_count;
326302504Smav	uint32_t good_pkt_tx_count;
327302504Smav	uint32_t bcast_pkt_tx_count;
328302504Smav	uint32_t mcast_pkt_tx_count;
329302504Smav	uint32_t oversize_rx_count;
330302504Smav	uint32_t tso_tx_count;
331302504Smav	uint64_t good_octets_rx;
332302504Smav	uint64_t good_octets_tx;
333302504Smav	uint64_t missed_octets; /* counts missed and oversized */
334302504Smav
335302504Smav	uint8_t nvm_bits:6; /* number of bits remaining in/out */
336302504Smav	uint8_t nvm_mode:2;
337302504Smav#define E82545_NVM_MODE_OPADDR  0x0
338302504Smav#define E82545_NVM_MODE_DATAIN  0x1
339302504Smav#define E82545_NVM_MODE_DATAOUT 0x2
340302504Smav        /* EEPROM data */
341302504Smav        uint16_t eeprom_data[E82545_NVM_EEPROM_SIZE];
342302504Smav};
343302504Smav
344302504Smavstatic void e82545_reset(struct e82545_softc *sc, int dev);
345302504Smavstatic void e82545_rx_enable(struct e82545_softc *sc);
346302504Smavstatic void e82545_rx_disable(struct e82545_softc *sc);
347302504Smavstatic void e82545_tap_callback(int fd, enum ev_type type, void *param);
348302504Smavstatic void e82545_tx_start(struct e82545_softc *sc);
349302504Smavstatic void e82545_tx_enable(struct e82545_softc *sc);
350302504Smavstatic void e82545_tx_disable(struct e82545_softc *sc);
351302504Smav
352302504Smavstatic inline int
353302504Smave82545_size_stat_index(uint32_t size)
354302504Smav{
355302504Smav	if (size <= 64) {
356302504Smav		return 0;
357302504Smav	} else if (size >= 1024) {
358302504Smav		return 5;
359302504Smav	} else {
360302504Smav		/* should be 1-4 */
361302504Smav		return (ffs(size) - 6);
362302504Smav	}
363302504Smav}
364302504Smav
365302504Smavstatic void
366302504Smave82545_init_eeprom(struct e82545_softc *sc)
367302504Smav{
368302504Smav	uint16_t checksum, i;
369302504Smav
370302504Smav        /* mac addr */
371302504Smav	sc->eeprom_data[NVM_MAC_ADDR] = ((uint16_t)sc->esc_mac.octet[0]) |
372302504Smav		(((uint16_t)sc->esc_mac.octet[1]) << 8);
373302504Smav	sc->eeprom_data[NVM_MAC_ADDR+1] = ((uint16_t)sc->esc_mac.octet[2]) |
374302504Smav		(((uint16_t)sc->esc_mac.octet[3]) << 8);
375302504Smav	sc->eeprom_data[NVM_MAC_ADDR+2] = ((uint16_t)sc->esc_mac.octet[4]) |
376302504Smav		(((uint16_t)sc->esc_mac.octet[5]) << 8);
377302504Smav
378302504Smav	/* pci ids */
379302504Smav	sc->eeprom_data[NVM_SUB_DEV_ID] = E82545_SUBDEV_ID;
380302504Smav	sc->eeprom_data[NVM_SUB_VEN_ID] = E82545_VENDOR_ID_INTEL;
381302504Smav	sc->eeprom_data[NVM_DEV_ID] = E82545_DEV_ID_82545EM_COPPER;
382302504Smav	sc->eeprom_data[NVM_VEN_ID] = E82545_VENDOR_ID_INTEL;
383302504Smav
384302504Smav	/* fill in the checksum */
385302504Smav        checksum = 0;
386302504Smav	for (i = 0; i < NVM_CHECKSUM_REG; i++) {
387302504Smav		checksum += sc->eeprom_data[i];
388302504Smav	}
389302504Smav	checksum = NVM_SUM - checksum;
390302504Smav	sc->eeprom_data[NVM_CHECKSUM_REG] = checksum;
391302504Smav	DPRINTF("eeprom checksum: 0x%x\r\n", checksum);
392302504Smav}
393302504Smav
394302504Smavstatic void
395302504Smave82545_write_mdi(struct e82545_softc *sc, uint8_t reg_addr,
396302504Smav			uint8_t phy_addr, uint32_t data)
397302504Smav{
398302504Smav	DPRINTF("Write mdi reg:0x%x phy:0x%x data: 0x%x\r\n", reg_addr, phy_addr, data);
399302504Smav}
400302504Smav
401302504Smavstatic uint32_t
402302504Smave82545_read_mdi(struct e82545_softc *sc, uint8_t reg_addr,
403302504Smav			uint8_t phy_addr)
404302504Smav{
405302504Smav	//DPRINTF("Read mdi reg:0x%x phy:0x%x\r\n", reg_addr, phy_addr);
406302504Smav	switch (reg_addr) {
407302504Smav	case PHY_STATUS:
408302504Smav		return (MII_SR_LINK_STATUS | MII_SR_AUTONEG_CAPS |
409302504Smav			MII_SR_AUTONEG_COMPLETE);
410302504Smav	case PHY_AUTONEG_ADV:
411302504Smav		return NWAY_AR_SELECTOR_FIELD;
412302504Smav	case PHY_LP_ABILITY:
413302504Smav		return 0;
414302504Smav	case PHY_1000T_STATUS:
415302504Smav		return (SR_1000T_LP_FD_CAPS | SR_1000T_REMOTE_RX_STATUS |
416302504Smav			SR_1000T_LOCAL_RX_STATUS);
417302504Smav	case PHY_ID1:
418302504Smav		return (M88E1011_I_PHY_ID >> 16) & 0xFFFF;
419302504Smav	case PHY_ID2:
420302504Smav		return (M88E1011_I_PHY_ID | E82545_REVISION_4) & 0xFFFF;
421302504Smav	default:
422302504Smav		DPRINTF("Unknown mdi read reg:0x%x phy:0x%x\r\n", reg_addr, phy_addr);
423302504Smav		return 0;
424302504Smav	}
425302504Smav	/* not reached */
426302504Smav}
427302504Smav
428302504Smavstatic void
429302504Smave82545_eecd_strobe(struct e82545_softc *sc)
430302504Smav{
431302504Smav	/* Microwire state machine */
432302504Smav	/*
433302504Smav	DPRINTF("eeprom state machine srtobe "
434302504Smav		"0x%x 0x%x 0x%x 0x%x\r\n",
435302504Smav		sc->nvm_mode, sc->nvm_bits,
436302504Smav		sc->nvm_opaddr, sc->nvm_data);*/
437302504Smav
438302504Smav	if (sc->nvm_bits == 0) {
439302504Smav		DPRINTF("eeprom state machine not expecting data! "
440302504Smav			"0x%x 0x%x 0x%x 0x%x\r\n",
441302504Smav			sc->nvm_mode, sc->nvm_bits,
442302504Smav			sc->nvm_opaddr, sc->nvm_data);
443302504Smav		return;
444302504Smav	}
445302504Smav	sc->nvm_bits--;
446302504Smav	if (sc->nvm_mode == E82545_NVM_MODE_DATAOUT) {
447302504Smav		/* shifting out */
448302504Smav		if (sc->nvm_data & 0x8000) {
449302504Smav			sc->eeprom_control |= E1000_EECD_DO;
450302504Smav		} else {
451302504Smav			sc->eeprom_control &= ~E1000_EECD_DO;
452302504Smav		}
453302504Smav		sc->nvm_data <<= 1;
454302504Smav		if (sc->nvm_bits == 0) {
455302504Smav			/* read done, back to opcode mode. */
456302504Smav			sc->nvm_opaddr = 0;
457302504Smav			sc->nvm_mode = E82545_NVM_MODE_OPADDR;
458302504Smav			sc->nvm_bits = E82545_NVM_OPADDR_BITS;
459302504Smav		}
460302504Smav	} else if (sc->nvm_mode == E82545_NVM_MODE_DATAIN) {
461302504Smav		/* shifting in */
462302504Smav		sc->nvm_data <<= 1;
463302504Smav		if (sc->eeprom_control & E1000_EECD_DI) {
464302504Smav			sc->nvm_data |= 1;
465302504Smav		}
466302504Smav		if (sc->nvm_bits == 0) {
467302504Smav			/* eeprom write */
468302504Smav			uint16_t op = sc->nvm_opaddr & E82545_NVM_OPCODE_MASK;
469302504Smav			uint16_t addr = sc->nvm_opaddr & E82545_NVM_ADDR_MASK;
470302504Smav			if (op != E82545_NVM_OPCODE_WRITE) {
471302504Smav				DPRINTF("Illegal eeprom write op 0x%x\r\n",
472302504Smav					sc->nvm_opaddr);
473302504Smav			} else if (addr >= E82545_NVM_EEPROM_SIZE) {
474302504Smav				DPRINTF("Illegal eeprom write addr 0x%x\r\n",
475302504Smav					sc->nvm_opaddr);
476302504Smav			} else {
477302504Smav				DPRINTF("eeprom write eeprom[0x%x] = 0x%x\r\n",
478302504Smav				addr, sc->nvm_data);
479302504Smav				sc->eeprom_data[addr] = sc->nvm_data;
480302504Smav			}
481302504Smav			/* back to opcode mode */
482302504Smav			sc->nvm_opaddr = 0;
483302504Smav			sc->nvm_mode = E82545_NVM_MODE_OPADDR;
484302504Smav			sc->nvm_bits = E82545_NVM_OPADDR_BITS;
485302504Smav		}
486302504Smav	} else if (sc->nvm_mode == E82545_NVM_MODE_OPADDR) {
487302504Smav		sc->nvm_opaddr <<= 1;
488302504Smav		if (sc->eeprom_control & E1000_EECD_DI) {
489302504Smav			sc->nvm_opaddr |= 1;
490302504Smav		}
491302504Smav		if (sc->nvm_bits == 0) {
492302504Smav			uint16_t op = sc->nvm_opaddr & E82545_NVM_OPCODE_MASK;
493302504Smav			switch (op) {
494302504Smav			case E82545_NVM_OPCODE_EWEN:
495302504Smav				DPRINTF("eeprom write enable: 0x%x\r\n",
496302504Smav					sc->nvm_opaddr);
497302504Smav				/* back to opcode mode */
498302504Smav				sc->nvm_opaddr = 0;
499302504Smav				sc->nvm_mode = E82545_NVM_MODE_OPADDR;
500302504Smav				sc->nvm_bits = E82545_NVM_OPADDR_BITS;
501302504Smav				break;
502302504Smav			case E82545_NVM_OPCODE_READ:
503302504Smav			{
504302504Smav				uint16_t addr = sc->nvm_opaddr &
505302504Smav					E82545_NVM_ADDR_MASK;
506302504Smav				sc->nvm_mode = E82545_NVM_MODE_DATAOUT;
507302504Smav				sc->nvm_bits = E82545_NVM_DATA_BITS;
508302504Smav				if (addr < E82545_NVM_EEPROM_SIZE) {
509302504Smav					sc->nvm_data = sc->eeprom_data[addr];
510302504Smav					DPRINTF("eeprom read: eeprom[0x%x] = 0x%x\r\n",
511302504Smav						addr, sc->nvm_data);
512302504Smav				} else {
513302504Smav					DPRINTF("eeprom illegal read: 0x%x\r\n",
514302504Smav						sc->nvm_opaddr);
515302504Smav					sc->nvm_data = 0;
516302504Smav				}
517302504Smav				break;
518302504Smav			}
519302504Smav			case E82545_NVM_OPCODE_WRITE:
520302504Smav				sc->nvm_mode = E82545_NVM_MODE_DATAIN;
521302504Smav				sc->nvm_bits = E82545_NVM_DATA_BITS;
522302504Smav				sc->nvm_data = 0;
523302504Smav				break;
524302504Smav			default:
525302504Smav				DPRINTF("eeprom unknown op: 0x%x\r\r",
526302504Smav					sc->nvm_opaddr);
527302504Smav				/* back to opcode mode */
528302504Smav				sc->nvm_opaddr = 0;
529302504Smav				sc->nvm_mode = E82545_NVM_MODE_OPADDR;
530302504Smav				sc->nvm_bits = E82545_NVM_OPADDR_BITS;
531302504Smav			}
532302504Smav		}
533302504Smav	} else {
534302504Smav		DPRINTF("eeprom state machine wrong state! "
535302504Smav			"0x%x 0x%x 0x%x 0x%x\r\n",
536302504Smav			sc->nvm_mode, sc->nvm_bits,
537302504Smav			sc->nvm_opaddr, sc->nvm_data);
538302504Smav	}
539302504Smav}
540302504Smav
541302504Smavstatic void
542302504Smave82545_itr_callback(int fd, enum ev_type type, void *param)
543302504Smav{
544302504Smav	uint32_t new;
545302504Smav	struct e82545_softc *sc = param;
546302504Smav
547302504Smav	pthread_mutex_lock(&sc->esc_mtx);
548302504Smav	new = sc->esc_ICR & sc->esc_IMS;
549302504Smav	if (new && !sc->esc_irq_asserted) {
550302504Smav		DPRINTF("itr callback: lintr assert %x\r\n", new);
551302504Smav		sc->esc_irq_asserted = 1;
552302504Smav		pci_lintr_assert(sc->esc_pi);
553302504Smav	} else {
554302504Smav		mevent_delete(sc->esc_mevpitr);
555302504Smav		sc->esc_mevpitr = NULL;
556302504Smav	}
557302504Smav	pthread_mutex_unlock(&sc->esc_mtx);
558302504Smav}
559302504Smav
560302504Smavstatic void
561302504Smave82545_icr_assert(struct e82545_softc *sc, uint32_t bits)
562302504Smav{
563302504Smav	uint32_t new;
564302504Smav
565302504Smav	DPRINTF("icr assert: 0x%x\r\n", bits);
566302504Smav
567302504Smav	/*
568302504Smav	 * An interrupt is only generated if bits are set that
569302504Smav	 * aren't already in the ICR, these bits are unmasked,
570302504Smav	 * and there isn't an interrupt already pending.
571302504Smav	 */
572302504Smav	new = bits & ~sc->esc_ICR & sc->esc_IMS;
573302504Smav	sc->esc_ICR |= bits;
574302504Smav
575302504Smav	if (new == 0) {
576302504Smav		DPRINTF("icr assert: masked %x, ims %x\r\n", new, sc->esc_IMS);
577302504Smav	} else if (sc->esc_mevpitr != NULL) {
578302504Smav		DPRINTF("icr assert: throttled %x, ims %x\r\n", new, sc->esc_IMS);
579302504Smav	} else if (!sc->esc_irq_asserted) {
580302504Smav		DPRINTF("icr assert: lintr assert %x\r\n", new);
581302504Smav		sc->esc_irq_asserted = 1;
582302504Smav		pci_lintr_assert(sc->esc_pi);
583302504Smav		if (sc->esc_ITR != 0) {
584302504Smav			sc->esc_mevpitr = mevent_add(
585302504Smav			    (sc->esc_ITR + 3905) / 3906,  /* 256ns -> 1ms */
586302504Smav			    EVF_TIMER, e82545_itr_callback, sc);
587302504Smav		}
588302504Smav	}
589302504Smav}
590302504Smav
591302504Smavstatic void
592302504Smave82545_ims_change(struct e82545_softc *sc, uint32_t bits)
593302504Smav{
594302504Smav	uint32_t new;
595302504Smav
596302504Smav	/*
597302504Smav	 * Changing the mask may allow previously asserted
598302504Smav	 * but masked interrupt requests to generate an interrupt.
599302504Smav	 */
600302504Smav	new = bits & sc->esc_ICR & ~sc->esc_IMS;
601302504Smav	sc->esc_IMS |= bits;
602302504Smav
603302504Smav	if (new == 0) {
604302504Smav		DPRINTF("ims change: masked %x, ims %x\r\n", new, sc->esc_IMS);
605302504Smav	} else if (sc->esc_mevpitr != NULL) {
606302504Smav		DPRINTF("ims change: throttled %x, ims %x\r\n", new, sc->esc_IMS);
607302504Smav	} else if (!sc->esc_irq_asserted) {
608302504Smav		DPRINTF("ims change: lintr assert %x\n\r", new);
609302504Smav		sc->esc_irq_asserted = 1;
610302504Smav		pci_lintr_assert(sc->esc_pi);
611302504Smav		if (sc->esc_ITR != 0) {
612302504Smav			sc->esc_mevpitr = mevent_add(
613302504Smav			    (sc->esc_ITR + 3905) / 3906,  /* 256ns -> 1ms */
614302504Smav			    EVF_TIMER, e82545_itr_callback, sc);
615302504Smav		}
616302504Smav	}
617302504Smav}
618302504Smav
619302504Smavstatic void
620302504Smave82545_icr_deassert(struct e82545_softc *sc, uint32_t bits)
621302504Smav{
622302504Smav
623302504Smav	DPRINTF("icr deassert: 0x%x\r\n", bits);
624302504Smav	sc->esc_ICR &= ~bits;
625302504Smav
626302504Smav	/*
627302504Smav	 * If there are no longer any interrupt sources and there
628302504Smav	 * was an asserted interrupt, clear it
629302504Smav	 */
630302504Smav	if (sc->esc_irq_asserted && !(sc->esc_ICR & sc->esc_IMS)) {
631302504Smav		DPRINTF("icr deassert: lintr deassert %x\r\n", bits);
632302504Smav		pci_lintr_deassert(sc->esc_pi);
633302504Smav		sc->esc_irq_asserted = 0;
634302504Smav	}
635302504Smav}
636302504Smav
637302504Smavstatic void
638302504Smave82545_intr_write(struct e82545_softc *sc, uint32_t offset, uint32_t value)
639302504Smav{
640302504Smav
641302504Smav	DPRINTF("intr_write: off %x, val %x\n\r", offset, value);
642302504Smav
643302504Smav	switch (offset) {
644302504Smav	case E1000_ICR:
645302504Smav		e82545_icr_deassert(sc, value);
646302504Smav		break;
647302504Smav	case E1000_ITR:
648302504Smav		sc->esc_ITR = value;
649302504Smav		break;
650302504Smav	case E1000_ICS:
651302504Smav		sc->esc_ICS = value;	/* not used: store for debug */
652302504Smav		e82545_icr_assert(sc, value);
653302504Smav		break;
654302504Smav	case E1000_IMS:
655302504Smav		e82545_ims_change(sc, value);
656302504Smav		break;
657302504Smav	case E1000_IMC:
658302504Smav		sc->esc_IMC = value;	/* for debug */
659302504Smav		sc->esc_IMS &= ~value;
660302504Smav		// XXX clear interrupts if all ICR bits now masked
661302504Smav		// and interrupt was pending ?
662302504Smav		break;
663302504Smav	default:
664302504Smav		break;
665302504Smav	}
666302504Smav}
667302504Smav
668302504Smavstatic uint32_t
669302504Smave82545_intr_read(struct e82545_softc *sc, uint32_t offset)
670302504Smav{
671302504Smav	uint32_t retval;
672302504Smav
673302504Smav	retval = 0;
674302504Smav
675302504Smav	DPRINTF("intr_read: off %x\n\r", offset);
676302504Smav
677302504Smav	switch (offset) {
678302504Smav	case E1000_ICR:
679302504Smav		retval = sc->esc_ICR;
680302504Smav		sc->esc_ICR = 0;
681302504Smav		e82545_icr_deassert(sc, ~0);
682302504Smav		break;
683302504Smav	case E1000_ITR:
684302504Smav		retval = sc->esc_ITR;
685302504Smav		break;
686302504Smav	case E1000_ICS:
687302504Smav		/* write-only register */
688302504Smav		break;
689302504Smav	case E1000_IMS:
690302504Smav		retval = sc->esc_IMS;
691302504Smav		break;
692302504Smav	case E1000_IMC:
693302504Smav		/* write-only register */
694302504Smav		break;
695302504Smav	default:
696302504Smav		break;
697302504Smav	}
698302504Smav
699302504Smav	return (retval);
700302504Smav}
701302504Smav
702302504Smavstatic void
703302504Smave82545_devctl(struct e82545_softc *sc, uint32_t val)
704302504Smav{
705302504Smav
706302504Smav	sc->esc_CTRL = val & ~E1000_CTRL_RST;
707302504Smav
708302504Smav	if (val & E1000_CTRL_RST) {
709302504Smav		DPRINTF("e1k: s/w reset, ctl %x\n", val);
710302504Smav		e82545_reset(sc, 1);
711302504Smav	}
712302504Smav	/* XXX check for phy reset ? */
713302504Smav}
714302504Smav
715302504Smavstatic void
716302504Smave82545_rx_update_rdba(struct e82545_softc *sc)
717302504Smav{
718302504Smav
719302504Smav	/* XXX verify desc base/len within phys mem range */
720302504Smav	sc->esc_rdba = (uint64_t)sc->esc_RDBAH << 32 |
721302504Smav	    sc->esc_RDBAL;
722302504Smav
723302504Smav	/* Cache host mapping of guest descriptor array */
724302504Smav	sc->esc_rxdesc = paddr_guest2host(sc->esc_ctx,
725302504Smav	    sc->esc_rdba, sc->esc_RDLEN);
726302504Smav}
727302504Smav
728302504Smavstatic void
729302504Smave82545_rx_ctl(struct e82545_softc *sc, uint32_t val)
730302504Smav{
731302504Smav	int on;
732302504Smav
733302504Smav	on = ((val & E1000_RCTL_EN) == E1000_RCTL_EN);
734302504Smav
735302504Smav	/* Save RCTL after stripping reserved bits 31:27,24,21,14,11:10,0 */
736302504Smav	sc->esc_RCTL = val & ~0xF9204c01;
737302504Smav
738302504Smav	DPRINTF("rx_ctl - %s RCTL %x, val %x\n",
739302504Smav		on ? "on" : "off", sc->esc_RCTL, val);
740302504Smav
741302504Smav	/* state change requested */
742302504Smav	if (on != sc->esc_rx_enabled) {
743302504Smav		if (on) {
744302504Smav			/* Catch disallowed/unimplemented settings */
745302504Smav			//assert(!(val & E1000_RCTL_LBM_TCVR));
746302504Smav
747302504Smav			if (sc->esc_RCTL & E1000_RCTL_LBM_TCVR) {
748302504Smav				sc->esc_rx_loopback = 1;
749302504Smav			} else {
750302504Smav				sc->esc_rx_loopback = 0;
751302504Smav			}
752302504Smav
753302504Smav			e82545_rx_update_rdba(sc);
754302504Smav			e82545_rx_enable(sc);
755302504Smav		} else {
756302504Smav			e82545_rx_disable(sc);
757302504Smav			sc->esc_rx_loopback = 0;
758302504Smav			sc->esc_rdba = 0;
759302504Smav			sc->esc_rxdesc = NULL;
760302504Smav		}
761302504Smav	}
762302504Smav}
763302504Smav
764302504Smavstatic void
765302504Smave82545_tx_update_tdba(struct e82545_softc *sc)
766302504Smav{
767302504Smav
768302504Smav	/* XXX verify desc base/len within phys mem range */
769302504Smav	sc->esc_tdba = (uint64_t)sc->esc_TDBAH << 32 | sc->esc_TDBAL;
770302504Smav
771302504Smav	/* Cache host mapping of guest descriptor array */
772302504Smav	sc->esc_txdesc = paddr_guest2host(sc->esc_ctx, sc->esc_tdba,
773302504Smav            sc->esc_TDLEN);
774302504Smav}
775302504Smav
776302504Smavstatic void
777302504Smave82545_tx_ctl(struct e82545_softc *sc, uint32_t val)
778302504Smav{
779302504Smav	int on;
780302504Smav
781302504Smav	on = ((val & E1000_TCTL_EN) == E1000_TCTL_EN);
782302504Smav
783302504Smav	/* ignore TCTL_EN settings that don't change state */
784302504Smav	if (on == sc->esc_tx_enabled)
785302504Smav		return;
786302504Smav
787302504Smav	if (on) {
788302504Smav		e82545_tx_update_tdba(sc);
789302504Smav		e82545_tx_enable(sc);
790302504Smav	} else {
791302504Smav		e82545_tx_disable(sc);
792302504Smav		sc->esc_tdba = 0;
793302504Smav		sc->esc_txdesc = NULL;
794302504Smav	}
795302504Smav
796302504Smav	/* Save TCTL value after stripping reserved bits 31:25,23,2,0 */
797302504Smav	sc->esc_TCTL = val & ~0xFE800005;
798302504Smav}
799302504Smav
800302504Smavint
801302504Smave82545_bufsz(uint32_t rctl)
802302504Smav{
803302504Smav
804302504Smav	switch (rctl & (E1000_RCTL_BSEX | E1000_RCTL_SZ_256)) {
805302504Smav	case (E1000_RCTL_SZ_2048): return (2048);
806302504Smav	case (E1000_RCTL_SZ_1024): return (1024);
807302504Smav	case (E1000_RCTL_SZ_512): return (512);
808302504Smav	case (E1000_RCTL_SZ_256): return (256);
809302504Smav	case (E1000_RCTL_BSEX|E1000_RCTL_SZ_16384): return (16384);
810302504Smav	case (E1000_RCTL_BSEX|E1000_RCTL_SZ_8192): return (8192);
811302504Smav	case (E1000_RCTL_BSEX|E1000_RCTL_SZ_4096): return (4096);
812302504Smav	}
813302504Smav	return (256);	/* Forbidden value. */
814302504Smav}
815302504Smav
816302504Smavstatic uint8_t dummybuf[2048];
817302504Smav
818302504Smav/* XXX one packet at a time until this is debugged */
819302504Smavstatic void
820302504Smave82545_tap_callback(int fd, enum ev_type type, void *param)
821302504Smav{
822302504Smav	struct e82545_softc *sc = param;
823302504Smav	struct e1000_rx_desc *rxd;
824302504Smav	struct iovec vec[64];
825302504Smav	int left, len, lim, maxpktsz, maxpktdesc, bufsz, i, n, size;
826302504Smav	uint32_t cause = 0;
827302504Smav	uint16_t *tp, tag, head;
828302504Smav
829302504Smav	pthread_mutex_lock(&sc->esc_mtx);
830302504Smav	DPRINTF("rx_run: head %x, tail %x\r\n", sc->esc_RDH, sc->esc_RDT);
831302504Smav
832302504Smav	if (!sc->esc_rx_enabled || sc->esc_rx_loopback) {
833302504Smav		DPRINTF("rx disabled (!%d || %d) -- packet(s) dropped\r\n",
834302504Smav		    sc->esc_rx_enabled, sc->esc_rx_loopback);
835302504Smav		while (read(sc->esc_tapfd, dummybuf, sizeof(dummybuf)) > 0) {
836302504Smav		}
837302504Smav		goto done1;
838302504Smav	}
839302504Smav	bufsz = e82545_bufsz(sc->esc_RCTL);
840302504Smav	maxpktsz = (sc->esc_RCTL & E1000_RCTL_LPE) ? 16384 : 1522;
841302504Smav	maxpktdesc = (maxpktsz + bufsz - 1) / bufsz;
842302504Smav	size = sc->esc_RDLEN / 16;
843302504Smav	head = sc->esc_RDH;
844302504Smav	left = (size + sc->esc_RDT - head) % size;
845302504Smav	if (left < maxpktdesc) {
846302504Smav		DPRINTF("rx overflow (%d < %d) -- packet(s) dropped\r\n",
847302504Smav		    left, maxpktdesc);
848302504Smav		while (read(sc->esc_tapfd, dummybuf, sizeof(dummybuf)) > 0) {
849302504Smav		}
850302504Smav		goto done1;
851302504Smav	}
852302504Smav
853302504Smav	sc->esc_rx_active = 1;
854302504Smav	pthread_mutex_unlock(&sc->esc_mtx);
855302504Smav
856302504Smav	for (lim = size / 4; lim > 0 && left >= maxpktdesc; lim -= n) {
857302504Smav
858302504Smav		/* Grab rx descriptor pointed to by the head pointer */
859302504Smav		for (i = 0; i < maxpktdesc; i++) {
860302504Smav			rxd = &sc->esc_rxdesc[(head + i) % size];
861302504Smav			vec[i].iov_base = paddr_guest2host(sc->esc_ctx,
862302504Smav			    rxd->buffer_addr, bufsz);
863302504Smav			vec[i].iov_len = bufsz;
864302504Smav		}
865302504Smav		len = readv(sc->esc_tapfd, vec, maxpktdesc);
866302504Smav		if (len <= 0) {
867302504Smav			DPRINTF("tap: readv() returned %d\n", len);
868302504Smav			goto done;
869302504Smav		}
870302504Smav
871302504Smav		/*
872302504Smav		 * Adjust the packet length based on whether the CRC needs
873302504Smav		 * to be stripped or if the packet is less than the minimum
874302504Smav		 * eth packet size.
875302504Smav		 */
876302504Smav		if (len < ETHER_MIN_LEN - ETHER_CRC_LEN)
877302504Smav			len = ETHER_MIN_LEN - ETHER_CRC_LEN;
878302504Smav		if (!(sc->esc_RCTL & E1000_RCTL_SECRC))
879302504Smav			len += ETHER_CRC_LEN;
880302504Smav		n = (len + bufsz - 1) / bufsz;
881302504Smav
882302504Smav		DPRINTF("packet read %d bytes, %d segs, head %d\r\n",
883302504Smav		    len, n, head);
884302504Smav
885302504Smav		/* Apply VLAN filter. */
886302504Smav		tp = (uint16_t *)vec[0].iov_base + 6;
887302504Smav		if ((sc->esc_RCTL & E1000_RCTL_VFE) &&
888302504Smav		    (ntohs(tp[0]) == sc->esc_VET)) {
889302504Smav			tag = ntohs(tp[1]) & 0x0fff;
890302504Smav			if ((sc->esc_fvlan[tag >> 5] &
891302504Smav			    (1 << (tag & 0x1f))) != 0) {
892302504Smav				DPRINTF("known VLAN %d\r\n", tag);
893302504Smav			} else {
894302504Smav				DPRINTF("unknown VLAN %d\r\n", tag);
895302504Smav				n = 0;
896302504Smav				continue;
897302504Smav			}
898302504Smav		}
899302504Smav
900302504Smav		/* Update all consumed descriptors. */
901302504Smav		for (i = 0; i < n - 1; i++) {
902302504Smav			rxd = &sc->esc_rxdesc[(head + i) % size];
903302504Smav			rxd->length = bufsz;
904302504Smav			rxd->csum = 0;
905302504Smav			rxd->errors = 0;
906302504Smav			rxd->special = 0;
907302504Smav			rxd->status = E1000_RXD_STAT_DD;
908302504Smav		}
909302504Smav		rxd = &sc->esc_rxdesc[(head + i) % size];
910302504Smav		rxd->length = len % bufsz;
911302504Smav		rxd->csum = 0;
912302504Smav		rxd->errors = 0;
913302504Smav		rxd->special = 0;
914302504Smav		/* XXX signal no checksum for now */
915302504Smav		rxd->status = E1000_RXD_STAT_PIF | E1000_RXD_STAT_IXSM |
916302504Smav		    E1000_RXD_STAT_EOP | E1000_RXD_STAT_DD;
917302504Smav
918302504Smav		/* Schedule receive interrupts. */
919302504Smav		if (len <= sc->esc_RSRPD) {
920302504Smav			cause |= E1000_ICR_SRPD | E1000_ICR_RXT0;
921302504Smav		} else {
922302504Smav			/* XXX: RDRT and RADV timers should be here. */
923302504Smav			cause |= E1000_ICR_RXT0;
924302504Smav		}
925302504Smav
926302504Smav		head = (head + n) % size;
927302504Smav		left -= n;
928302504Smav	}
929302504Smav
930302504Smavdone:
931302504Smav	pthread_mutex_lock(&sc->esc_mtx);
932302504Smav	sc->esc_rx_active = 0;
933302504Smav	if (sc->esc_rx_enabled == 0)
934302504Smav		pthread_cond_signal(&sc->esc_rx_cond);
935302504Smav
936302504Smav	sc->esc_RDH = head;
937302504Smav	/* Respect E1000_RCTL_RDMTS */
938302504Smav	left = (size + sc->esc_RDT - head) % size;
939302504Smav	if (left < (size >> (((sc->esc_RCTL >> 8) & 3) + 1)))
940302504Smav		cause |= E1000_ICR_RXDMT0;
941302504Smav	/* Assert all accumulated interrupts. */
942302504Smav	if (cause != 0)
943302504Smav		e82545_icr_assert(sc, cause);
944302504Smavdone1:
945302504Smav	DPRINTF("rx_run done: head %x, tail %x\r\n", sc->esc_RDH, sc->esc_RDT);
946302504Smav	pthread_mutex_unlock(&sc->esc_mtx);
947302504Smav}
948302504Smav
949302504Smavstatic uint16_t
950302504Smave82545_carry(uint32_t sum)
951302504Smav{
952302504Smav
953302504Smav	sum = (sum & 0xFFFF) + (sum >> 16);
954302504Smav	if (sum > 0xFFFF)
955302504Smav		sum -= 0xFFFF;
956302504Smav	return (sum);
957302504Smav}
958302504Smav
959302504Smavstatic uint16_t
960302504Smave82545_buf_checksum(uint8_t *buf, int len)
961302504Smav{
962302504Smav	int i;
963302504Smav	uint32_t sum = 0;
964302504Smav
965302504Smav	/* Checksum all the pairs of bytes first... */
966302504Smav	for (i = 0; i < (len & ~1U); i += 2)
967302504Smav		sum += *((u_int16_t *)(buf + i));
968302504Smav
969302504Smav	/*
970302504Smav	 * If there's a single byte left over, checksum it, too.
971302504Smav	 * Network byte order is big-endian, so the remaining byte is
972302504Smav	 * the high byte.
973302504Smav	 */
974302504Smav	if (i < len)
975302504Smav		sum += htons(buf[i] << 8);
976302504Smav
977302504Smav	return (e82545_carry(sum));
978302504Smav}
979302504Smav
980302504Smavstatic uint16_t
981302504Smave82545_iov_checksum(struct iovec *iov, int iovcnt, int off, int len)
982302504Smav{
983302504Smav	int now, odd;
984302504Smav	uint32_t sum = 0, s;
985302504Smav
986302504Smav	/* Skip completely unneeded vectors. */
987302504Smav	while (iovcnt > 0 && iov->iov_len <= off && off > 0) {
988302504Smav		off -= iov->iov_len;
989302504Smav		iov++;
990302504Smav		iovcnt--;
991302504Smav	}
992302504Smav
993302504Smav	/* Calculate checksum of requested range. */
994302504Smav	odd = 0;
995302504Smav	while (len > 0 && iovcnt > 0) {
996302504Smav		now = MIN(len, iov->iov_len - off);
997302504Smav		s = e82545_buf_checksum(iov->iov_base + off, now);
998302504Smav		sum += odd ? (s << 8) : s;
999302504Smav		odd ^= (now & 1);
1000302504Smav		len -= now;
1001302504Smav		off = 0;
1002302504Smav		iov++;
1003302504Smav		iovcnt--;
1004302504Smav	}
1005302504Smav
1006302504Smav	return (e82545_carry(sum));
1007302504Smav}
1008302504Smav
1009302504Smav/*
1010302504Smav * Return the transmit descriptor type.
1011302504Smav */
1012302504Smavint
1013302504Smave82545_txdesc_type(uint32_t lower)
1014302504Smav{
1015302504Smav	int type;
1016302504Smav
1017302504Smav	type = 0;
1018302504Smav
1019302504Smav	if (lower & E1000_TXD_CMD_DEXT)
1020302504Smav		type = lower & E1000_TXD_MASK;
1021302504Smav
1022302504Smav	return (type);
1023302504Smav}
1024302504Smav
1025302504Smavstatic void
1026302504Smave82545_transmit_checksum(struct iovec *iov, int iovcnt, struct ck_info *ck)
1027302504Smav{
1028302504Smav	uint16_t cksum;
1029302504Smav	int cklen;
1030302504Smav
1031302504Smav	DPRINTF("tx cksum: iovcnt/s/off/len %d/%d/%d/%d\r\n",
1032302504Smav	    iovcnt, ck->ck_start, ck->ck_off, ck->ck_len);
1033302504Smav	cklen = ck->ck_len ? ck->ck_len - ck->ck_start + 1 : INT_MAX;
1034302504Smav	cksum = e82545_iov_checksum(iov, iovcnt, ck->ck_start, cklen);
1035302504Smav	*(uint16_t *)((uint8_t *)iov[0].iov_base + ck->ck_off) = ~cksum;
1036302504Smav}
1037302504Smav
1038302504Smavstatic void
1039302504Smave82545_transmit_backend(struct e82545_softc *sc, struct iovec *iov, int iovcnt)
1040302504Smav{
1041302504Smav
1042302504Smav	if (sc->esc_tapfd == -1)
1043302504Smav		return;
1044302504Smav
1045302504Smav	(void) writev(sc->esc_tapfd, iov, iovcnt);
1046302504Smav}
1047302504Smav
1048302504Smavstatic void
1049304425Smave82545_transmit_done(struct e82545_softc *sc, uint16_t head, uint16_t tail,
1050304425Smav    uint16_t dsize, int *tdwb)
1051302504Smav{
1052304425Smav	union e1000_tx_udesc *dsc;
1053302504Smav
1054304425Smav	for ( ; head != tail; head = (head + 1) % dsize) {
1055304425Smav		dsc = &sc->esc_txdesc[head];
1056304425Smav		if (dsc->td.lower.data & E1000_TXD_CMD_RS) {
1057304425Smav			dsc->td.upper.data |= E1000_TXD_STAT_DD;
1058304425Smav			*tdwb = 1;
1059304425Smav		}
1060304425Smav	}
1061302504Smav}
1062302504Smav
1063302504Smavstatic int
1064302504Smave82545_transmit(struct e82545_softc *sc, uint16_t head, uint16_t tail,
1065302504Smav    uint16_t dsize, uint16_t *rhead, int *tdwb)
1066302504Smav{
1067302504Smav	uint8_t *hdr, *hdrp;
1068302504Smav	struct iovec iovb[I82545_MAX_TXSEGS + 2];
1069302504Smav	struct iovec tiov[I82545_MAX_TXSEGS + 2];
1070302504Smav	struct e1000_context_desc *cd;
1071302504Smav	struct ck_info ckinfo[2];
1072302504Smav	struct iovec *iov;
1073302504Smav	union  e1000_tx_udesc *dsc;
1074304425Smav	int desc, dtype, len, ntype, iovcnt, tlen, hdrlen, vlen, tcp, tso;
1075302504Smav	int mss, paylen, seg, tiovcnt, left, now, nleft, nnow, pv, pvoff;
1076302504Smav	uint32_t tcpsum, tcpseq;
1077304425Smav	uint16_t ipcs, tcpcs, ipid, ohead;
1078302504Smav
1079302504Smav	ckinfo[0].ck_valid = ckinfo[1].ck_valid = 0;
1080302504Smav	iovcnt = 0;
1081302504Smav	tlen = 0;
1082302504Smav	ntype = 0;
1083302504Smav	tso = 0;
1084304425Smav	ohead = head;
1085302504Smav
1086302504Smav	/* iovb[0/1] may be used for writable copy of headers. */
1087302504Smav	iov = &iovb[2];
1088302504Smav
1089302504Smav	for (desc = 0; ; desc++, head = (head + 1) % dsize) {
1090302504Smav		if (head == tail) {
1091302504Smav			*rhead = head;
1092302504Smav			return (0);
1093302504Smav		}
1094302504Smav		dsc = &sc->esc_txdesc[head];
1095302504Smav		dtype = e82545_txdesc_type(dsc->td.lower.data);
1096302504Smav
1097302504Smav		if (desc == 0) {
1098302504Smav			switch (dtype) {
1099302504Smav			case E1000_TXD_TYP_C:
1100302504Smav				DPRINTF("tx ctxt desc idx %d: %016jx "
1101302504Smav				    "%08x%08x\r\n",
1102302504Smav				    head, dsc->td.buffer_addr,
1103302504Smav				    dsc->td.upper.data, dsc->td.lower.data);
1104302504Smav				/* Save context and return */
1105302504Smav				sc->esc_txctx = dsc->cd;
1106304425Smav				goto done;
1107302504Smav			case E1000_TXD_TYP_L:
1108302504Smav				DPRINTF("tx legacy desc idx %d: %08x%08x\r\n",
1109302504Smav				    head, dsc->td.upper.data, dsc->td.lower.data);
1110302504Smav				/*
1111302504Smav				 * legacy cksum start valid in first descriptor
1112302504Smav				 */
1113302504Smav				ntype = dtype;
1114302504Smav				ckinfo[0].ck_start = dsc->td.upper.fields.css;
1115302504Smav				break;
1116302504Smav			case E1000_TXD_TYP_D:
1117302504Smav				DPRINTF("tx data desc idx %d: %08x%08x\r\n",
1118302504Smav				    head, dsc->td.upper.data, dsc->td.lower.data);
1119302504Smav				ntype = dtype;
1120302504Smav				break;
1121302504Smav			default:
1122302504Smav				break;
1123302504Smav			}
1124302504Smav		} else {
1125302504Smav			/* Descriptor type must be consistent */
1126302504Smav			assert(dtype == ntype);
1127302504Smav			DPRINTF("tx next desc idx %d: %08x%08x\r\n",
1128302504Smav			    head, dsc->td.upper.data, dsc->td.lower.data);
1129302504Smav		}
1130302504Smav
1131302504Smav		len = (dtype == E1000_TXD_TYP_L) ? dsc->td.lower.flags.length :
1132302504Smav		    dsc->dd.lower.data & 0xFFFFF;
1133302504Smav
1134302504Smav		if (len > 0) {
1135302504Smav			/* Strip checksum supplied by guest. */
1136302504Smav			if ((dsc->td.lower.data & E1000_TXD_CMD_EOP) != 0 &&
1137302504Smav			    (dsc->td.lower.data & E1000_TXD_CMD_IFCS) == 0)
1138302504Smav				len -= 2;
1139302504Smav			tlen += len;
1140304425Smav			if (iovcnt < I82545_MAX_TXSEGS) {
1141304425Smav				iov[iovcnt].iov_base = paddr_guest2host(
1142304425Smav				    sc->esc_ctx, dsc->td.buffer_addr, len);
1143304425Smav				iov[iovcnt].iov_len = len;
1144304425Smav			}
1145302504Smav			iovcnt++;
1146302504Smav		}
1147302504Smav
1148302504Smav		/*
1149302504Smav		 * Pull out info that is valid in the final descriptor
1150302504Smav		 * and exit descriptor loop.
1151302504Smav		 */
1152302504Smav		if (dsc->td.lower.data & E1000_TXD_CMD_EOP) {
1153302504Smav			if (dtype == E1000_TXD_TYP_L) {
1154302504Smav				if (dsc->td.lower.data & E1000_TXD_CMD_IC) {
1155302504Smav					ckinfo[0].ck_valid = 1;
1156302504Smav					ckinfo[0].ck_off =
1157302504Smav					    dsc->td.lower.flags.cso;
1158302504Smav					ckinfo[0].ck_len = 0;
1159302504Smav				}
1160302504Smav			} else {
1161302504Smav				cd = &sc->esc_txctx;
1162302504Smav				if (dsc->dd.lower.data & E1000_TXD_CMD_TSE)
1163302504Smav					tso = 1;
1164302504Smav				if (dsc->dd.upper.fields.popts &
1165302504Smav				    E1000_TXD_POPTS_IXSM)
1166302504Smav					ckinfo[0].ck_valid = 1;
1167302504Smav				if (dsc->dd.upper.fields.popts &
1168302504Smav				    E1000_TXD_POPTS_IXSM || tso) {
1169302504Smav					ckinfo[0].ck_start =
1170302504Smav					    cd->lower_setup.ip_fields.ipcss;
1171302504Smav					ckinfo[0].ck_off =
1172302504Smav					    cd->lower_setup.ip_fields.ipcso;
1173302504Smav					ckinfo[0].ck_len =
1174302504Smav					    cd->lower_setup.ip_fields.ipcse;
1175302504Smav				}
1176302504Smav				if (dsc->dd.upper.fields.popts &
1177302504Smav				    E1000_TXD_POPTS_TXSM)
1178302504Smav					ckinfo[1].ck_valid = 1;
1179302504Smav				if (dsc->dd.upper.fields.popts &
1180302504Smav				    E1000_TXD_POPTS_TXSM || tso) {
1181302504Smav					ckinfo[1].ck_start =
1182302504Smav					    cd->upper_setup.tcp_fields.tucss;
1183302504Smav					ckinfo[1].ck_off =
1184302504Smav					    cd->upper_setup.tcp_fields.tucso;
1185302504Smav					ckinfo[1].ck_len =
1186302504Smav					    cd->upper_setup.tcp_fields.tucse;
1187302504Smav				}
1188302504Smav			}
1189302504Smav			break;
1190302504Smav		}
1191302504Smav	}
1192302504Smav
1193304425Smav	if (iovcnt > I82545_MAX_TXSEGS) {
1194304425Smav		WPRINTF("tx too many descriptors (%d > %d) -- dropped\r\n",
1195304425Smav		    iovcnt, I82545_MAX_TXSEGS);
1196304425Smav		goto done;
1197304425Smav	}
1198304425Smav
1199302504Smav	hdrlen = vlen = 0;
1200302504Smav	/* Estimate writable space for VLAN header insertion. */
1201302504Smav	if ((sc->esc_CTRL & E1000_CTRL_VME) &&
1202302504Smav	    (dsc->td.lower.data & E1000_TXD_CMD_VLE)) {
1203302504Smav		hdrlen = ETHER_ADDR_LEN*2;
1204302504Smav		vlen = ETHER_VLAN_ENCAP_LEN;
1205302504Smav	}
1206302504Smav	if (!tso) {
1207302504Smav		/* Estimate required writable space for checksums. */
1208302504Smav		if (ckinfo[0].ck_valid)
1209302504Smav			hdrlen = MAX(hdrlen, ckinfo[0].ck_off + 2);
1210302504Smav		if (ckinfo[1].ck_valid)
1211302504Smav			hdrlen = MAX(hdrlen, ckinfo[1].ck_off + 2);
1212302504Smav		/* Round up writable space to the first vector. */
1213302504Smav		if (hdrlen != 0 && iov[0].iov_len > hdrlen &&
1214302504Smav		    iov[0].iov_len < hdrlen + 100)
1215302504Smav			hdrlen = iov[0].iov_len;
1216302504Smav	} else {
1217302504Smav		/* In case of TSO header length provided by software. */
1218302504Smav		hdrlen = sc->esc_txctx.tcp_seg_setup.fields.hdr_len;
1219302504Smav	}
1220302504Smav
1221302504Smav	/* Allocate, fill and prepend writable header vector. */
1222302504Smav	if (hdrlen != 0) {
1223302504Smav		hdr = __builtin_alloca(hdrlen + vlen);
1224302504Smav		hdr += vlen;
1225302504Smav		for (left = hdrlen, hdrp = hdr; left > 0;
1226302504Smav		    left -= now, hdrp += now) {
1227302504Smav			now = MIN(left, iov->iov_len);
1228302504Smav			memcpy(hdrp, iov->iov_base, now);
1229302504Smav			iov->iov_base += now;
1230302504Smav			iov->iov_len -= now;
1231302504Smav			if (iov->iov_len == 0) {
1232302504Smav				iov++;
1233302504Smav				iovcnt--;
1234302504Smav			}
1235302504Smav		}
1236302504Smav		iov--;
1237302504Smav		iovcnt++;
1238302504Smav		iov->iov_base = hdr;
1239302504Smav		iov->iov_len = hdrlen;
1240302504Smav	}
1241302504Smav
1242302504Smav	/* Insert VLAN tag. */
1243302504Smav	if (vlen != 0) {
1244302504Smav		hdr -= ETHER_VLAN_ENCAP_LEN;
1245302504Smav		memmove(hdr, hdr + ETHER_VLAN_ENCAP_LEN, ETHER_ADDR_LEN*2);
1246302504Smav		hdrlen += ETHER_VLAN_ENCAP_LEN;
1247302504Smav		hdr[ETHER_ADDR_LEN*2 + 0] = sc->esc_VET >> 8;
1248302504Smav		hdr[ETHER_ADDR_LEN*2 + 1] = sc->esc_VET & 0xff;
1249302504Smav		hdr[ETHER_ADDR_LEN*2 + 2] = dsc->td.upper.fields.special >> 8;
1250302504Smav		hdr[ETHER_ADDR_LEN*2 + 3] = dsc->td.upper.fields.special & 0xff;
1251302504Smav		iov->iov_base = hdr;
1252302504Smav		iov->iov_len += ETHER_VLAN_ENCAP_LEN;
1253302504Smav		/* Correct checksum offsets after VLAN tag insertion. */
1254302504Smav		ckinfo[0].ck_start += ETHER_VLAN_ENCAP_LEN;
1255302504Smav		ckinfo[0].ck_off += ETHER_VLAN_ENCAP_LEN;
1256302504Smav		if (ckinfo[0].ck_len != 0)
1257302504Smav			ckinfo[0].ck_len += ETHER_VLAN_ENCAP_LEN;
1258302504Smav		ckinfo[1].ck_start += ETHER_VLAN_ENCAP_LEN;
1259302504Smav		ckinfo[1].ck_off += ETHER_VLAN_ENCAP_LEN;
1260302504Smav		if (ckinfo[1].ck_len != 0)
1261302504Smav			ckinfo[1].ck_len += ETHER_VLAN_ENCAP_LEN;
1262302504Smav	}
1263302504Smav
1264302504Smav	/* Simple non-TSO case. */
1265302504Smav	if (!tso) {
1266302504Smav		/* Calculate checksums and transmit. */
1267302504Smav		if (ckinfo[0].ck_valid)
1268302504Smav			e82545_transmit_checksum(iov, iovcnt, &ckinfo[0]);
1269302504Smav		if (ckinfo[1].ck_valid)
1270302504Smav			e82545_transmit_checksum(iov, iovcnt, &ckinfo[1]);
1271302504Smav		e82545_transmit_backend(sc, iov, iovcnt);
1272302504Smav		goto done;
1273302504Smav	}
1274302504Smav
1275302504Smav	/* Doing TSO. */
1276302504Smav	tcp = (sc->esc_txctx.cmd_and_length & E1000_TXD_CMD_TCP) != 0;
1277302504Smav	mss = sc->esc_txctx.tcp_seg_setup.fields.mss;
1278302504Smav	paylen = (sc->esc_txctx.cmd_and_length & 0x000fffff);
1279302504Smav	DPRINTF("tx %s segmentation offload %d+%d/%d bytes %d iovs\r\n",
1280302504Smav	    tcp ? "TCP" : "UDP", hdrlen, paylen, mss, iovcnt);
1281302504Smav	ipid = ntohs(*(uint16_t *)&hdr[ckinfo[0].ck_start + 4]);
1282302504Smav	tcpseq = ntohl(*(uint32_t *)&hdr[ckinfo[1].ck_start + 4]);
1283302504Smav	ipcs = *(uint16_t *)&hdr[ckinfo[0].ck_off];
1284302504Smav	tcpcs = 0;
1285302504Smav	if (ckinfo[1].ck_valid)	/* Save partial pseudo-header checksum. */
1286302504Smav		tcpcs = *(uint16_t *)&hdr[ckinfo[1].ck_off];
1287302504Smav	pv = 1;
1288302504Smav	pvoff = 0;
1289302504Smav	for (seg = 0, left = paylen; left > 0; seg++, left -= now) {
1290302504Smav		now = MIN(left, mss);
1291302504Smav
1292302504Smav		/* Construct IOVs for the segment. */
1293302504Smav		/* Include whole original header. */
1294302504Smav		tiov[0].iov_base = hdr;
1295302504Smav		tiov[0].iov_len = hdrlen;
1296302504Smav		tiovcnt = 1;
1297302504Smav		/* Include respective part of payload IOV. */
1298302504Smav		for (nleft = now; pv < iovcnt && nleft > 0; nleft -= nnow) {
1299302504Smav			nnow = MIN(nleft, iov[pv].iov_len - pvoff);
1300302504Smav			tiov[tiovcnt].iov_base = iov[pv].iov_base + pvoff;
1301302504Smav			tiov[tiovcnt++].iov_len = nnow;
1302302504Smav			if (pvoff + nnow == iov[pv].iov_len) {
1303302504Smav				pv++;
1304302504Smav				pvoff = 0;
1305302504Smav			} else
1306302504Smav				pvoff += nnow;
1307302504Smav		}
1308302504Smav		DPRINTF("tx segment %d %d+%d bytes %d iovs\r\n",
1309302504Smav		    seg, hdrlen, now, tiovcnt);
1310302504Smav
1311302504Smav		/* Update IP header. */
1312302504Smav		if (sc->esc_txctx.cmd_and_length & E1000_TXD_CMD_IP) {
1313302504Smav			/* IPv4 -- set length and ID */
1314302504Smav			*(uint16_t *)&hdr[ckinfo[0].ck_start + 2] =
1315302504Smav			    htons(hdrlen - ckinfo[0].ck_start + now);
1316302504Smav			*(uint16_t *)&hdr[ckinfo[0].ck_start + 4] =
1317302504Smav			    htons(ipid + seg);
1318302504Smav		} else {
1319302504Smav			/* IPv6 -- set length */
1320302504Smav			*(uint16_t *)&hdr[ckinfo[0].ck_start + 4] =
1321302504Smav			    htons(hdrlen - ckinfo[0].ck_start - 40 +
1322302504Smav				  now);
1323302504Smav		}
1324302504Smav
1325302504Smav		/* Update pseudo-header checksum. */
1326302504Smav		tcpsum = tcpcs;
1327302504Smav		tcpsum += htons(hdrlen - ckinfo[1].ck_start + now);
1328302504Smav
1329302504Smav		/* Update TCP/UDP headers. */
1330302504Smav		if (tcp) {
1331302504Smav			/* Update sequence number and FIN/PUSH flags. */
1332302504Smav			*(uint32_t *)&hdr[ckinfo[1].ck_start + 4] =
1333302504Smav			    htonl(tcpseq + paylen - left);
1334302504Smav			if (now < left) {
1335302504Smav				hdr[ckinfo[1].ck_start + 13] &=
1336302504Smav				    ~(TH_FIN | TH_PUSH);
1337302504Smav			}
1338302504Smav		} else {
1339302504Smav			/* Update payload length. */
1340302504Smav			*(uint32_t *)&hdr[ckinfo[1].ck_start + 4] =
1341302504Smav			    hdrlen - ckinfo[1].ck_start + now;
1342302504Smav		}
1343302504Smav
1344302504Smav		/* Calculate checksums and transmit. */
1345302504Smav		if (ckinfo[0].ck_valid) {
1346302504Smav			*(uint16_t *)&hdr[ckinfo[0].ck_off] = ipcs;
1347302504Smav			e82545_transmit_checksum(tiov, tiovcnt, &ckinfo[0]);
1348302504Smav		}
1349302504Smav		if (ckinfo[1].ck_valid) {
1350302504Smav			*(uint16_t *)&hdr[ckinfo[1].ck_off] =
1351302504Smav			    e82545_carry(tcpsum);
1352302504Smav			e82545_transmit_checksum(tiov, tiovcnt, &ckinfo[1]);
1353302504Smav		}
1354302504Smav		e82545_transmit_backend(sc, tiov, tiovcnt);
1355302504Smav	}
1356302504Smav
1357302504Smavdone:
1358304425Smav	head = (head + 1) % dsize;
1359304425Smav	e82545_transmit_done(sc, ohead, head, dsize, tdwb);
1360302504Smav
1361304425Smav	*rhead = head;
1362302504Smav	return (desc + 1);
1363302504Smav}
1364302504Smav
1365302504Smavstatic void
1366302504Smave82545_tx_run(struct e82545_softc *sc)
1367302504Smav{
1368302504Smav	uint32_t cause;
1369302504Smav	uint16_t head, rhead, tail, size;
1370302504Smav	int lim, tdwb, sent;
1371302504Smav
1372302504Smav	head = sc->esc_TDH;
1373302504Smav	tail = sc->esc_TDT;
1374302504Smav	size = sc->esc_TDLEN / 16;
1375302504Smav	DPRINTF("tx_run: head %x, rhead %x, tail %x\r\n",
1376302504Smav	    sc->esc_TDH, sc->esc_TDHr, sc->esc_TDT);
1377302504Smav
1378302504Smav	pthread_mutex_unlock(&sc->esc_mtx);
1379302504Smav	rhead = head;
1380302504Smav	tdwb = 0;
1381302504Smav	for (lim = size / 4; sc->esc_tx_enabled && lim > 0; lim -= sent) {
1382302504Smav		sent = e82545_transmit(sc, head, tail, size, &rhead, &tdwb);
1383302504Smav		if (sent == 0)
1384302504Smav			break;
1385302504Smav		head = rhead;
1386302504Smav	}
1387302504Smav	pthread_mutex_lock(&sc->esc_mtx);
1388302504Smav
1389302504Smav	sc->esc_TDH = head;
1390302504Smav	sc->esc_TDHr = rhead;
1391302504Smav	cause = 0;
1392302504Smav	if (tdwb)
1393302504Smav		cause |= E1000_ICR_TXDW;
1394302504Smav	if (lim != size / 4 && sc->esc_TDH == sc->esc_TDT)
1395302504Smav		cause |= E1000_ICR_TXQE;
1396302504Smav	if (cause)
1397302504Smav		e82545_icr_assert(sc, cause);
1398302504Smav
1399302504Smav	DPRINTF("tx_run done: head %x, rhead %x, tail %x\r\n",
1400302504Smav	    sc->esc_TDH, sc->esc_TDHr, sc->esc_TDT);
1401302504Smav}
1402302504Smav
1403302504Smavstatic void *
1404302504Smave82545_tx_thread(void *param)
1405302504Smav{
1406302504Smav	struct e82545_softc *sc = param;
1407302504Smav
1408302504Smav	pthread_mutex_lock(&sc->esc_mtx);
1409302504Smav	for (;;) {
1410302504Smav		while (!sc->esc_tx_enabled || sc->esc_TDHr == sc->esc_TDT) {
1411302504Smav			if (sc->esc_tx_enabled && sc->esc_TDHr != sc->esc_TDT)
1412302504Smav				break;
1413302504Smav			sc->esc_tx_active = 0;
1414302504Smav			if (sc->esc_tx_enabled == 0)
1415302504Smav				pthread_cond_signal(&sc->esc_tx_cond);
1416302504Smav			pthread_cond_wait(&sc->esc_tx_cond, &sc->esc_mtx);
1417302504Smav		}
1418302504Smav		sc->esc_tx_active = 1;
1419302504Smav
1420302504Smav		/* Process some tx descriptors.  Lock dropped inside. */
1421302504Smav		e82545_tx_run(sc);
1422302504Smav	}
1423302504Smav}
1424302504Smav
1425302504Smavstatic void
1426302504Smave82545_tx_start(struct e82545_softc *sc)
1427302504Smav{
1428302504Smav
1429302504Smav	if (sc->esc_tx_active == 0)
1430302504Smav		pthread_cond_signal(&sc->esc_tx_cond);
1431302504Smav}
1432302504Smav
1433302504Smavstatic void
1434302504Smave82545_tx_enable(struct e82545_softc *sc)
1435302504Smav{
1436302504Smav
1437302504Smav	sc->esc_tx_enabled = 1;
1438302504Smav}
1439302504Smav
1440302504Smavstatic void
1441302504Smave82545_tx_disable(struct e82545_softc *sc)
1442302504Smav{
1443302504Smav
1444302504Smav	sc->esc_tx_enabled = 0;
1445302504Smav	while (sc->esc_tx_active)
1446302504Smav		pthread_cond_wait(&sc->esc_tx_cond, &sc->esc_mtx);
1447302504Smav}
1448302504Smav
1449302504Smavstatic void
1450302504Smave82545_rx_enable(struct e82545_softc *sc)
1451302504Smav{
1452302504Smav
1453302504Smav	sc->esc_rx_enabled = 1;
1454302504Smav}
1455302504Smav
1456302504Smavstatic void
1457302504Smave82545_rx_disable(struct e82545_softc *sc)
1458302504Smav{
1459302504Smav
1460302504Smav	sc->esc_rx_enabled = 0;
1461302504Smav	while (sc->esc_rx_active)
1462302504Smav		pthread_cond_wait(&sc->esc_rx_cond, &sc->esc_mtx);
1463302504Smav}
1464302504Smav
1465302504Smavstatic void
1466302504Smave82545_write_ra(struct e82545_softc *sc, int reg, uint32_t wval)
1467302504Smav{
1468302504Smav        struct eth_uni *eu;
1469302504Smav	int idx;
1470302504Smav
1471302504Smav	idx = reg >> 1;
1472302504Smav	assert(idx < 15);
1473302504Smav
1474302504Smav	eu = &sc->esc_uni[idx];
1475302504Smav
1476302504Smav	if (reg & 0x1) {
1477302504Smav		/* RAH */
1478302504Smav		eu->eu_valid = ((wval & E1000_RAH_AV) == E1000_RAH_AV);
1479302504Smav		eu->eu_addrsel = (wval >> 16) & 0x3;
1480302504Smav		eu->eu_eth.octet[5] = wval >> 8;
1481302504Smav		eu->eu_eth.octet[4] = wval;
1482302504Smav	} else {
1483302504Smav		/* RAL */
1484302504Smav		eu->eu_eth.octet[3] = wval >> 24;
1485302504Smav		eu->eu_eth.octet[2] = wval >> 16;
1486302504Smav		eu->eu_eth.octet[1] = wval >> 8;
1487302504Smav		eu->eu_eth.octet[0] = wval;
1488302504Smav	}
1489302504Smav}
1490302504Smav
1491302504Smavstatic uint32_t
1492302504Smave82545_read_ra(struct e82545_softc *sc, int reg)
1493302504Smav{
1494302504Smav        struct eth_uni *eu;
1495302504Smav	uint32_t retval;
1496302504Smav	int idx;
1497302504Smav
1498302504Smav	idx = reg >> 1;
1499302504Smav	assert(idx < 15);
1500302504Smav
1501302504Smav	eu = &sc->esc_uni[idx];
1502302504Smav
1503302504Smav	if (reg & 0x1) {
1504302504Smav		/* RAH */
1505302504Smav		retval = (eu->eu_valid << 31) |
1506302504Smav			 (eu->eu_addrsel << 16) |
1507302504Smav			 (eu->eu_eth.octet[5] << 8) |
1508302504Smav			 eu->eu_eth.octet[4];
1509302504Smav	} else {
1510302504Smav		/* RAL */
1511302504Smav		retval = (eu->eu_eth.octet[3] << 24) |
1512302504Smav			 (eu->eu_eth.octet[2] << 16) |
1513302504Smav			 (eu->eu_eth.octet[1] << 8) |
1514302504Smav			 eu->eu_eth.octet[0];
1515302504Smav	}
1516302504Smav
1517302504Smav	return (retval);
1518302504Smav}
1519302504Smav
1520302504Smavstatic void
1521302504Smave82545_write_register(struct e82545_softc *sc, uint32_t offset, uint32_t value)
1522302504Smav{
1523302504Smav	int ridx;
1524302504Smav
1525302504Smav	if (offset & 0x3) {
1526302504Smav		DPRINTF("Unaligned register write offset:0x%x value:0x%x\r\n", offset, value);
1527302504Smav		return;
1528302504Smav	}
1529302504Smav	DPRINTF("Register write: 0x%x value: 0x%x\r\n", offset, value);
1530302504Smav
1531302504Smav	switch (offset) {
1532302504Smav	case E1000_CTRL:
1533302504Smav	case E1000_CTRL_DUP:
1534302504Smav		e82545_devctl(sc, value);
1535302504Smav		break;
1536302504Smav	case E1000_FCAL:
1537302504Smav		sc->esc_FCAL = value;
1538302504Smav		break;
1539302504Smav	case E1000_FCAH:
1540302504Smav		sc->esc_FCAH = value & ~0xFFFF0000;
1541302504Smav		break;
1542302504Smav	case E1000_FCT:
1543302504Smav		sc->esc_FCT = value & ~0xFFFF0000;
1544302504Smav		break;
1545302504Smav	case E1000_VET:
1546302504Smav		sc->esc_VET = value & ~0xFFFF0000;
1547302504Smav		break;
1548302504Smav	case E1000_FCTTV:
1549302504Smav		sc->esc_FCTTV = value & ~0xFFFF0000;
1550302504Smav		break;
1551302504Smav	case E1000_LEDCTL:
1552302504Smav		sc->esc_LEDCTL = value & ~0x30303000;
1553302504Smav		break;
1554302504Smav	case E1000_PBA:
1555302504Smav		sc->esc_PBA = value & 0x0000FF80;
1556302504Smav		break;
1557302504Smav	case E1000_ICR:
1558302504Smav	case E1000_ITR:
1559302504Smav	case E1000_ICS:
1560302504Smav	case E1000_IMS:
1561302504Smav	case E1000_IMC:
1562302504Smav		e82545_intr_write(sc, offset, value);
1563302504Smav		break;
1564302504Smav	case E1000_RCTL:
1565302504Smav		e82545_rx_ctl(sc, value);
1566302504Smav		break;
1567302504Smav	case E1000_FCRTL:
1568302504Smav		sc->esc_FCRTL = value & ~0xFFFF0007;
1569302504Smav		break;
1570302504Smav	case E1000_FCRTH:
1571302504Smav		sc->esc_FCRTH = value & ~0xFFFF0007;
1572302504Smav		break;
1573302504Smav	case E1000_RDBAL(0):
1574302504Smav		sc->esc_RDBAL = value & ~0xF;
1575302504Smav		if (sc->esc_rx_enabled) {
1576302504Smav			/* Apparently legal: update cached address */
1577302504Smav			e82545_rx_update_rdba(sc);
1578302504Smav		}
1579302504Smav		break;
1580302504Smav	case E1000_RDBAH(0):
1581302504Smav		assert(!sc->esc_rx_enabled);
1582302504Smav		sc->esc_RDBAH = value;
1583302504Smav		break;
1584302504Smav	case E1000_RDLEN(0):
1585302504Smav		assert(!sc->esc_rx_enabled);
1586302504Smav		sc->esc_RDLEN = value & ~0xFFF0007F;
1587302504Smav		break;
1588302504Smav	case E1000_RDH(0):
1589302504Smav		/* XXX should only ever be zero ? Range check ? */
1590302504Smav		sc->esc_RDH = value;
1591302504Smav		break;
1592302504Smav	case E1000_RDT(0):
1593302504Smav		/* XXX if this opens up the rx ring, do something ? */
1594302504Smav		sc->esc_RDT = value;
1595302504Smav		break;
1596302504Smav	case E1000_RDTR:
1597302504Smav		/* ignore FPD bit 31 */
1598302504Smav		sc->esc_RDTR = value & ~0xFFFF0000;
1599302504Smav		break;
1600302504Smav	case E1000_RXDCTL(0):
1601302504Smav		sc->esc_RXDCTL = value & ~0xFEC0C0C0;
1602302504Smav		break;
1603302504Smav	case E1000_RADV:
1604302504Smav		sc->esc_RADV = value & ~0xFFFF0000;
1605302504Smav		break;
1606302504Smav	case E1000_RSRPD:
1607302504Smav		sc->esc_RSRPD = value & ~0xFFFFF000;
1608302504Smav		break;
1609302504Smav	case E1000_RXCSUM:
1610302504Smav		sc->esc_RXCSUM = value & ~0xFFFFF800;
1611302504Smav		break;
1612302504Smav	case E1000_TXCW:
1613302504Smav		sc->esc_TXCW = value & ~0x3FFF0000;
1614302504Smav		break;
1615302504Smav	case E1000_TCTL:
1616302504Smav		e82545_tx_ctl(sc, value);
1617302504Smav		break;
1618302504Smav	case E1000_TIPG:
1619302504Smav		sc->esc_TIPG = value;
1620302504Smav		break;
1621302504Smav	case E1000_AIT:
1622302504Smav		sc->esc_AIT = value;
1623302504Smav		break;
1624302504Smav	case E1000_TDBAL(0):
1625302504Smav		sc->esc_TDBAL = value & ~0xF;
1626302504Smav		if (sc->esc_tx_enabled) {
1627302504Smav			/* Apparently legal */
1628302504Smav			e82545_tx_update_tdba(sc);
1629302504Smav		}
1630302504Smav		break;
1631302504Smav	case E1000_TDBAH(0):
1632302504Smav		//assert(!sc->esc_tx_enabled);
1633302504Smav		sc->esc_TDBAH = value;
1634302504Smav		break;
1635302504Smav	case E1000_TDLEN(0):
1636302504Smav		//assert(!sc->esc_tx_enabled);
1637302504Smav		sc->esc_TDLEN = value & ~0xFFF0007F;
1638302504Smav		break;
1639302504Smav	case E1000_TDH(0):
1640302504Smav		//assert(!sc->esc_tx_enabled);
1641302504Smav		/* XXX should only ever be zero ? Range check ? */
1642302504Smav		sc->esc_TDHr = sc->esc_TDH = value;
1643302504Smav		break;
1644302504Smav	case E1000_TDT(0):
1645302504Smav		/* XXX range check ? */
1646302504Smav		sc->esc_TDT = value;
1647302504Smav		if (sc->esc_tx_enabled)
1648302504Smav			e82545_tx_start(sc);
1649302504Smav		break;
1650302504Smav	case E1000_TIDV:
1651302504Smav		sc->esc_TIDV = value & ~0xFFFF0000;
1652302504Smav		break;
1653302504Smav	case E1000_TXDCTL(0):
1654302504Smav		//assert(!sc->esc_tx_enabled);
1655302504Smav		sc->esc_TXDCTL = value & ~0xC0C0C0;
1656302504Smav		break;
1657302504Smav	case E1000_TADV:
1658302504Smav		sc->esc_TADV = value & ~0xFFFF0000;
1659302504Smav		break;
1660302504Smav	case E1000_RAL(0) ... E1000_RAH(15):
1661302504Smav		/* convert to u32 offset */
1662302504Smav		ridx = (offset - E1000_RAL(0)) >> 2;
1663302504Smav		e82545_write_ra(sc, ridx, value);
1664302504Smav		break;
1665302504Smav	case E1000_MTA ... (E1000_MTA + (127*4)):
1666302504Smav		sc->esc_fmcast[(offset - E1000_MTA) >> 2] = value;
1667302504Smav		break;
1668302504Smav	case E1000_VFTA ... (E1000_VFTA + (127*4)):
1669302504Smav		sc->esc_fvlan[(offset - E1000_VFTA) >> 2] = value;
1670302504Smav		break;
1671302504Smav	case E1000_EECD:
1672302504Smav	{
1673302504Smav		//DPRINTF("EECD write 0x%x -> 0x%x\r\n", sc->eeprom_control, value);
1674302504Smav		/* edge triggered low->high */
1675302504Smav		uint32_t eecd_strobe = ((sc->eeprom_control & E1000_EECD_SK) ?
1676302504Smav			0 : (value & E1000_EECD_SK));
1677302504Smav		uint32_t eecd_mask = (E1000_EECD_SK|E1000_EECD_CS|
1678302504Smav					E1000_EECD_DI|E1000_EECD_REQ);
1679302504Smav		sc->eeprom_control &= ~eecd_mask;
1680302504Smav		sc->eeprom_control |= (value & eecd_mask);
1681302504Smav		/* grant/revoke immediately */
1682302504Smav		if (value & E1000_EECD_REQ) {
1683302504Smav			sc->eeprom_control |= E1000_EECD_GNT;
1684302504Smav		} else {
1685302504Smav                        sc->eeprom_control &= ~E1000_EECD_GNT;
1686302504Smav		}
1687302504Smav		if (eecd_strobe && (sc->eeprom_control & E1000_EECD_CS)) {
1688302504Smav			e82545_eecd_strobe(sc);
1689302504Smav		}
1690302504Smav		return;
1691302504Smav	}
1692302504Smav	case E1000_MDIC:
1693302504Smav	{
1694302504Smav		uint8_t reg_addr = (uint8_t)((value & E1000_MDIC_REG_MASK) >>
1695302504Smav						E1000_MDIC_REG_SHIFT);
1696302504Smav		uint8_t phy_addr = (uint8_t)((value & E1000_MDIC_PHY_MASK) >>
1697302504Smav						E1000_MDIC_PHY_SHIFT);
1698302504Smav		sc->mdi_control =
1699302504Smav			(value & ~(E1000_MDIC_ERROR|E1000_MDIC_DEST));
1700302504Smav		if ((value & E1000_MDIC_READY) != 0) {
1701302504Smav			DPRINTF("Incorrect MDIC ready bit: 0x%x\r\n", value);
1702302504Smav			return;
1703302504Smav		}
1704302504Smav		switch (value & E82545_MDIC_OP_MASK) {
1705302504Smav		case E1000_MDIC_OP_READ:
1706302504Smav			sc->mdi_control &= ~E82545_MDIC_DATA_MASK;
1707302504Smav			sc->mdi_control |= e82545_read_mdi(sc, reg_addr, phy_addr);
1708302504Smav			break;
1709302504Smav		case E1000_MDIC_OP_WRITE:
1710302504Smav			e82545_write_mdi(sc, reg_addr, phy_addr,
1711302504Smav				value & E82545_MDIC_DATA_MASK);
1712302504Smav			break;
1713302504Smav		default:
1714302504Smav			DPRINTF("Unknown MDIC op: 0x%x\r\n", value);
1715302504Smav			return;
1716302504Smav		}
1717302504Smav		/* TODO: barrier? */
1718302504Smav		sc->mdi_control |= E1000_MDIC_READY;
1719302504Smav		if (value & E82545_MDIC_IE) {
1720302504Smav			// TODO: generate interrupt
1721302504Smav		}
1722302504Smav		return;
1723302504Smav	}
1724302504Smav	case E1000_MANC:
1725302504Smav	case E1000_STATUS:
1726302504Smav		return;
1727302504Smav	default:
1728302504Smav		DPRINTF("Unknown write register: 0x%x value:%x\r\n", offset, value);
1729302504Smav		return;
1730302504Smav	}
1731302504Smav}
1732302504Smav
1733302504Smavstatic uint32_t
1734302504Smave82545_read_register(struct e82545_softc *sc, uint32_t offset)
1735302504Smav{
1736302504Smav	uint32_t retval;
1737302504Smav	int ridx;
1738302504Smav
1739302504Smav	if (offset & 0x3) {
1740302504Smav		DPRINTF("Unaligned register read offset:0x%x\r\n", offset);
1741302504Smav		return 0;
1742302504Smav	}
1743302504Smav
1744302504Smav	DPRINTF("Register read: 0x%x\r\n", offset);
1745302504Smav
1746302504Smav	switch (offset) {
1747302504Smav	case E1000_CTRL:
1748302504Smav		retval = sc->esc_CTRL;
1749302504Smav		break;
1750302504Smav	case E1000_STATUS:
1751302504Smav		retval = E1000_STATUS_FD | E1000_STATUS_LU |
1752302504Smav		    E1000_STATUS_SPEED_1000;
1753302504Smav		break;
1754302504Smav	case E1000_FCAL:
1755302504Smav		retval = sc->esc_FCAL;
1756302504Smav		break;
1757302504Smav	case E1000_FCAH:
1758302504Smav		retval = sc->esc_FCAH;
1759302504Smav		break;
1760302504Smav	case E1000_FCT:
1761302504Smav		retval = sc->esc_FCT;
1762302504Smav		break;
1763302504Smav	case E1000_VET:
1764302504Smav		retval = sc->esc_VET;
1765302504Smav		break;
1766302504Smav	case E1000_FCTTV:
1767302504Smav		retval = sc->esc_FCTTV;
1768302504Smav		break;
1769302504Smav	case E1000_LEDCTL:
1770302504Smav		retval = sc->esc_LEDCTL;
1771302504Smav		break;
1772302504Smav	case E1000_PBA:
1773302504Smav		retval = sc->esc_PBA;
1774302504Smav		break;
1775302504Smav	case E1000_ICR:
1776302504Smav	case E1000_ITR:
1777302504Smav	case E1000_ICS:
1778302504Smav	case E1000_IMS:
1779302504Smav	case E1000_IMC:
1780302504Smav		retval = e82545_intr_read(sc, offset);
1781302504Smav		break;
1782302504Smav	case E1000_RCTL:
1783302504Smav		retval = sc->esc_RCTL;
1784302504Smav		break;
1785302504Smav	case E1000_FCRTL:
1786302504Smav		retval = sc->esc_FCRTL;
1787302504Smav		break;
1788302504Smav	case E1000_FCRTH:
1789302504Smav		retval = sc->esc_FCRTH;
1790302504Smav		break;
1791302504Smav	case E1000_RDBAL(0):
1792302504Smav		retval = sc->esc_RDBAL;
1793302504Smav		break;
1794302504Smav	case E1000_RDBAH(0):
1795302504Smav		retval = sc->esc_RDBAH;
1796302504Smav		break;
1797302504Smav	case E1000_RDLEN(0):
1798302504Smav		retval = sc->esc_RDLEN;
1799302504Smav		break;
1800302504Smav	case E1000_RDH(0):
1801302504Smav		retval = sc->esc_RDH;
1802302504Smav		break;
1803302504Smav	case E1000_RDT(0):
1804302504Smav		retval = sc->esc_RDT;
1805302504Smav		break;
1806302504Smav	case E1000_RDTR:
1807302504Smav		retval = sc->esc_RDTR;
1808302504Smav		break;
1809302504Smav	case E1000_RXDCTL(0):
1810302504Smav		retval = sc->esc_RXDCTL;
1811302504Smav		break;
1812302504Smav	case E1000_RADV:
1813302504Smav		retval = sc->esc_RADV;
1814302504Smav		break;
1815302504Smav	case E1000_RSRPD:
1816302504Smav		retval = sc->esc_RSRPD;
1817302504Smav		break;
1818302504Smav	case E1000_RXCSUM:
1819302504Smav		retval = sc->esc_RXCSUM;
1820302504Smav		break;
1821302504Smav	case E1000_TXCW:
1822302504Smav		retval = sc->esc_TXCW;
1823302504Smav		break;
1824302504Smav	case E1000_TCTL:
1825302504Smav		retval = sc->esc_TCTL;
1826302504Smav		break;
1827302504Smav	case E1000_TIPG:
1828302504Smav		retval = sc->esc_TIPG;
1829302504Smav		break;
1830302504Smav	case E1000_AIT:
1831302504Smav		retval = sc->esc_AIT;
1832302504Smav		break;
1833302504Smav	case E1000_TDBAL(0):
1834302504Smav		retval = sc->esc_TDBAL;
1835302504Smav		break;
1836302504Smav	case E1000_TDBAH(0):
1837302504Smav		retval = sc->esc_TDBAH;
1838302504Smav		break;
1839302504Smav	case E1000_TDLEN(0):
1840302504Smav		retval = sc->esc_TDLEN;
1841302504Smav		break;
1842302504Smav	case E1000_TDH(0):
1843302504Smav		retval = sc->esc_TDH;
1844302504Smav		break;
1845302504Smav	case E1000_TDT(0):
1846302504Smav		retval = sc->esc_TDT;
1847302504Smav		break;
1848302504Smav	case E1000_TIDV:
1849302504Smav		retval = sc->esc_TIDV;
1850302504Smav		break;
1851302504Smav	case E1000_TXDCTL(0):
1852302504Smav		retval = sc->esc_TXDCTL;
1853302504Smav		break;
1854302504Smav	case E1000_TADV:
1855302504Smav		retval = sc->esc_TADV;
1856302504Smav		break;
1857302504Smav	case E1000_RAL(0) ... E1000_RAH(15):
1858302504Smav		/* convert to u32 offset */
1859302504Smav		ridx = (offset - E1000_RAL(0)) >> 2;
1860302504Smav		retval = e82545_read_ra(sc, ridx);
1861302504Smav		break;
1862302504Smav	case E1000_MTA ... (E1000_MTA + (127*4)):
1863302504Smav		retval = sc->esc_fmcast[(offset - E1000_MTA) >> 2];
1864302504Smav		break;
1865302504Smav	case E1000_VFTA ... (E1000_VFTA + (127*4)):
1866302504Smav		retval = sc->esc_fvlan[(offset - E1000_VFTA) >> 2];
1867302504Smav		break;
1868302504Smav	case E1000_EECD:
1869302504Smav		//DPRINTF("EECD read %x\r\n", sc->eeprom_control);
1870302504Smav		retval = sc->eeprom_control;
1871302504Smav		break;
1872302504Smav	case E1000_MDIC:
1873302504Smav		retval = sc->mdi_control;
1874302504Smav		break;
1875302504Smav	case E1000_MANC:
1876302504Smav		retval = 0;
1877302504Smav		break;
1878302504Smav	/* stats that we emulate. */
1879302504Smav	case E1000_MPC:
1880302504Smav		retval = sc->missed_pkt_count;
1881302504Smav		break;
1882302504Smav	case E1000_PRC64:
1883302504Smav		retval = sc->pkt_rx_by_size[0];
1884302504Smav		break;
1885302504Smav	case E1000_PRC127:
1886302504Smav		retval = sc->pkt_rx_by_size[1];
1887302504Smav		break;
1888302504Smav	case E1000_PRC255:
1889302504Smav		retval = sc->pkt_rx_by_size[2];
1890302504Smav		break;
1891302504Smav	case E1000_PRC511:
1892302504Smav		retval = sc->pkt_rx_by_size[3];
1893302504Smav		break;
1894302504Smav	case E1000_PRC1023:
1895302504Smav		retval = sc->pkt_rx_by_size[4];
1896302504Smav		break;
1897302504Smav	case E1000_PRC1522:
1898302504Smav		retval = sc->pkt_rx_by_size[5];
1899302504Smav		break;
1900302504Smav	case E1000_GPRC:
1901302504Smav		retval = sc->good_pkt_rx_count;
1902302504Smav		break;
1903302504Smav	case E1000_BPRC:
1904302504Smav		retval = sc->bcast_pkt_rx_count;
1905302504Smav		break;
1906302504Smav	case E1000_MPRC:
1907302504Smav		retval = sc->mcast_pkt_rx_count;
1908302504Smav		break;
1909302504Smav	case E1000_GPTC:
1910302504Smav	case E1000_TPT:
1911302504Smav		retval = sc->good_pkt_tx_count;
1912302504Smav		break;
1913302504Smav	case E1000_GORCL:
1914302504Smav		retval = (uint32_t)sc->good_octets_rx;
1915302504Smav		break;
1916302504Smav	case E1000_GORCH:
1917302504Smav		retval = (uint32_t)(sc->good_octets_rx >> 32);
1918302504Smav		break;
1919302504Smav	case E1000_TOTL:
1920302504Smav	case E1000_GOTCL:
1921302504Smav		retval = (uint32_t)sc->good_octets_tx;
1922302504Smav		break;
1923302504Smav	case E1000_TOTH:
1924302504Smav	case E1000_GOTCH:
1925302504Smav		retval = (uint32_t)(sc->good_octets_tx >> 32);
1926302504Smav		break;
1927302504Smav	case E1000_ROC:
1928302504Smav		retval = sc->oversize_rx_count;
1929302504Smav		break;
1930302504Smav	case E1000_TORL:
1931302504Smav		retval = (uint32_t)(sc->good_octets_rx + sc->missed_octets);
1932302504Smav		break;
1933302504Smav	case E1000_TORH:
1934302504Smav		retval = (uint32_t)((sc->good_octets_rx +
1935302504Smav		    sc->missed_octets) >> 32);
1936302504Smav		break;
1937302504Smav	case E1000_TPR:
1938302504Smav		retval = sc->good_pkt_rx_count + sc->missed_pkt_count +
1939302504Smav		    sc->oversize_rx_count;
1940302504Smav		break;
1941302504Smav	case E1000_PTC64:
1942302504Smav		retval = sc->pkt_tx_by_size[0];
1943302504Smav		break;
1944302504Smav	case E1000_PTC127:
1945302504Smav		retval = sc->pkt_tx_by_size[1];
1946302504Smav		break;
1947302504Smav	case E1000_PTC255:
1948302504Smav		retval = sc->pkt_tx_by_size[2];
1949302504Smav		break;
1950302504Smav	case E1000_PTC511:
1951302504Smav		retval = sc->pkt_tx_by_size[3];
1952302504Smav		break;
1953302504Smav	case E1000_PTC1023:
1954302504Smav		retval = sc->pkt_tx_by_size[4];
1955302504Smav		break;
1956302504Smav	case E1000_PTC1522:
1957302504Smav		retval = sc->pkt_tx_by_size[5];
1958302504Smav		break;
1959302504Smav	case E1000_MPTC:
1960302504Smav		retval = sc->mcast_pkt_tx_count;
1961302504Smav		break;
1962302504Smav	case E1000_BPTC:
1963302504Smav		retval = sc->bcast_pkt_tx_count;
1964302504Smav		break;
1965302504Smav	case E1000_TSCTC:
1966302504Smav		retval = sc->tso_tx_count;
1967302504Smav		break;
1968302504Smav	/* stats that are always 0. */
1969302504Smav	case E1000_CRCERRS:
1970302504Smav	case E1000_ALGNERRC:
1971302504Smav	case E1000_SYMERRS:
1972302504Smav	case E1000_RXERRC:
1973302504Smav	case E1000_SCC:
1974302504Smav	case E1000_ECOL:
1975302504Smav	case E1000_MCC:
1976302504Smav	case E1000_LATECOL:
1977302504Smav	case E1000_COLC:
1978302504Smav	case E1000_DC:
1979302504Smav	case E1000_TNCRS:
1980302504Smav	case E1000_SEC:
1981302504Smav	case E1000_CEXTERR:
1982302504Smav	case E1000_RLEC:
1983302504Smav	case E1000_XONRXC:
1984302504Smav	case E1000_XONTXC:
1985302504Smav	case E1000_XOFFRXC:
1986302504Smav	case E1000_XOFFTXC:
1987302504Smav	case E1000_FCRUC:
1988302504Smav	case E1000_RNBC:
1989302504Smav	case E1000_RUC:
1990302504Smav	case E1000_RFC:
1991302504Smav	case E1000_RJC:
1992302504Smav	case E1000_MGTPRC:
1993302504Smav	case E1000_MGTPDC:
1994302504Smav	case E1000_MGTPTC:
1995302504Smav	case E1000_TSCTFC:
1996302504Smav		retval = 0;
1997302504Smav		break;
1998302504Smav	default:
1999302504Smav		DPRINTF("Unknown read register: 0x%x\r\n", offset);
2000304425Smav		retval = 0;
2001302504Smav		break;
2002302504Smav	}
2003302504Smav
2004302504Smav	return (retval);
2005302504Smav}
2006302504Smav
2007302504Smavstatic void
2008302504Smave82545_write(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, int baridx,
2009302504Smav	     uint64_t offset, int size, uint64_t value)
2010302504Smav{
2011302504Smav	struct e82545_softc *sc;
2012302504Smav
2013302504Smav	//DPRINTF("Write bar:%d offset:0x%lx value:0x%lx size:%d\r\n", baridx, offset, value, size);
2014302504Smav
2015302504Smav	sc = pi->pi_arg;
2016302504Smav
2017302504Smav	pthread_mutex_lock(&sc->esc_mtx);
2018302504Smav
2019302504Smav	switch (baridx) {
2020302504Smav	case E82545_BAR_IO:
2021302504Smav		switch (offset) {
2022302504Smav		case E82545_IOADDR:
2023302504Smav			if (size != 4) {
2024302504Smav				DPRINTF("Wrong io addr write sz:%d value:0x%lx\r\n", size, value);
2025302504Smav			} else
2026302504Smav				sc->io_addr = (uint32_t)value;
2027302504Smav			break;
2028302504Smav		case E82545_IODATA:
2029302504Smav			if (size != 4) {
2030302504Smav				DPRINTF("Wrong io data write size:%d value:0x%lx\r\n", size, value);
2031302504Smav			} else if (sc->io_addr > E82545_IO_REGISTER_MAX) {
2032302504Smav				DPRINTF("Non-register io write addr:0x%x value:0x%lx\r\n", sc->io_addr, value);
2033302504Smav			} else
2034302504Smav				e82545_write_register(sc, sc->io_addr,
2035302504Smav						      (uint32_t)value);
2036302504Smav			break;
2037302504Smav		default:
2038302504Smav			DPRINTF("Unknown io bar write offset:0x%lx value:0x%lx size:%d\r\n", offset, value, size);
2039302504Smav			break;
2040302504Smav		}
2041304425Smav		break;
2042302504Smav	case E82545_BAR_REGISTER:
2043302504Smav		if (size != 4) {
2044302504Smav			DPRINTF("Wrong register write size:%d offset:0x%lx value:0x%lx\r\n", size, offset, value);
2045302504Smav		} else
2046302504Smav			e82545_write_register(sc, (uint32_t)offset,
2047302504Smav					      (uint32_t)value);
2048302504Smav		break;
2049302504Smav	default:
2050302504Smav		DPRINTF("Unknown write bar:%d off:0x%lx val:0x%lx size:%d\r\n",
2051302504Smav			baridx, offset, value, size);
2052302504Smav	}
2053302504Smav
2054302504Smav	pthread_mutex_unlock(&sc->esc_mtx);
2055302504Smav}
2056302504Smav
2057302504Smavstatic uint64_t
2058302504Smave82545_read(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, int baridx,
2059302504Smav	    uint64_t offset, int size)
2060302504Smav{
2061302504Smav	struct e82545_softc *sc;
2062302504Smav	uint64_t retval;
2063302504Smav
2064302504Smav	//DPRINTF("Read  bar:%d offset:0x%lx size:%d\r\n", baridx, offset, size);
2065302504Smav	sc = pi->pi_arg;
2066302504Smav	retval = 0;
2067302504Smav
2068302504Smav	pthread_mutex_lock(&sc->esc_mtx);
2069302504Smav
2070302504Smav	switch (baridx) {
2071302504Smav	case E82545_BAR_IO:
2072302504Smav		switch (offset) {
2073302504Smav		case E82545_IOADDR:
2074302504Smav			if (size != 4) {
2075302504Smav				DPRINTF("Wrong io addr read sz:%d\r\n", size);
2076302504Smav			} else
2077302504Smav				retval = sc->io_addr;
2078302504Smav			break;
2079302504Smav		case E82545_IODATA:
2080302504Smav			if (size != 4) {
2081302504Smav				DPRINTF("Wrong io data read sz:%d\r\n", size);
2082302504Smav			}
2083302504Smav			if (sc->io_addr > E82545_IO_REGISTER_MAX) {
2084302504Smav				DPRINTF("Non-register io read addr:0x%x\r\n",
2085302504Smav					sc->io_addr);
2086302504Smav			} else
2087302504Smav				retval = e82545_read_register(sc, sc->io_addr);
2088302504Smav			break;
2089302504Smav		default:
2090302504Smav			DPRINTF("Unknown io bar read offset:0x%lx size:%d\r\n",
2091302504Smav				offset, size);
2092302504Smav			break;
2093302504Smav		}
2094304425Smav		break;
2095302504Smav	case E82545_BAR_REGISTER:
2096302504Smav		if (size != 4) {
2097302504Smav			DPRINTF("Wrong register read size:%d offset:0x%lx\r\n",
2098302504Smav				size, offset);
2099302504Smav		} else
2100302504Smav			retval = e82545_read_register(sc, (uint32_t)offset);
2101302504Smav		break;
2102302504Smav	default:
2103302504Smav		DPRINTF("Unknown read bar:%d offset:0x%lx size:%d\r\n",
2104302504Smav			baridx, offset, size);
2105302504Smav		break;
2106302504Smav	}
2107302504Smav
2108302504Smav	pthread_mutex_unlock(&sc->esc_mtx);
2109302504Smav
2110302504Smav	return (retval);
2111302504Smav}
2112302504Smav
2113302504Smavstatic void
2114302504Smave82545_reset(struct e82545_softc *sc, int drvr)
2115302504Smav{
2116302504Smav	int i;
2117302504Smav
2118302504Smav	e82545_rx_disable(sc);
2119302504Smav	e82545_tx_disable(sc);
2120302504Smav
2121302504Smav	/* clear outstanding interrupts */
2122302504Smav	if (sc->esc_irq_asserted)
2123302504Smav		pci_lintr_deassert(sc->esc_pi);
2124302504Smav
2125302504Smav	/* misc */
2126302504Smav	if (!drvr) {
2127302504Smav		sc->esc_FCAL = 0;
2128302504Smav		sc->esc_FCAH = 0;
2129302504Smav		sc->esc_FCT = 0;
2130302504Smav		sc->esc_VET = 0;
2131302504Smav		sc->esc_FCTTV = 0;
2132302504Smav	}
2133302504Smav	sc->esc_LEDCTL = 0x07061302;
2134302504Smav	sc->esc_PBA = 0x00100030;
2135302504Smav
2136302504Smav	/* start nvm in opcode mode. */
2137302504Smav	sc->nvm_opaddr = 0;
2138302504Smav	sc->nvm_mode = E82545_NVM_MODE_OPADDR;
2139302504Smav	sc->nvm_bits = E82545_NVM_OPADDR_BITS;
2140302504Smav	sc->eeprom_control = E1000_EECD_PRES | E82545_EECD_FWE_EN;
2141302504Smav	e82545_init_eeprom(sc);
2142302504Smav
2143302504Smav	/* interrupt */
2144302504Smav	sc->esc_ICR = 0;
2145302504Smav	sc->esc_ITR = 250;
2146302504Smav	sc->esc_ICS = 0;
2147302504Smav	sc->esc_IMS = 0;
2148302504Smav	sc->esc_IMC = 0;
2149302504Smav
2150302504Smav	/* L2 filters */
2151302504Smav	if (!drvr) {
2152302504Smav		memset(sc->esc_fvlan, 0, sizeof(sc->esc_fvlan));
2153302504Smav		memset(sc->esc_fmcast, 0, sizeof(sc->esc_fmcast));
2154302504Smav		memset(sc->esc_uni, 0, sizeof(sc->esc_uni));
2155302504Smav
2156302504Smav		/* XXX not necessary on 82545 ?? */
2157302504Smav		sc->esc_uni[0].eu_valid = 1;
2158302504Smav		memcpy(sc->esc_uni[0].eu_eth.octet, sc->esc_mac.octet,
2159302504Smav		    ETHER_ADDR_LEN);
2160302504Smav	} else {
2161302504Smav		/* Clear RAH valid bits */
2162302504Smav		for (i = 0; i < 16; i++)
2163302504Smav			sc->esc_uni[i].eu_valid = 0;
2164302504Smav	}
2165302504Smav
2166302504Smav	/* receive */
2167302504Smav	if (!drvr) {
2168302504Smav		sc->esc_RDBAL = 0;
2169302504Smav		sc->esc_RDBAH = 0;
2170302504Smav	}
2171302504Smav	sc->esc_RCTL = 0;
2172302504Smav	sc->esc_FCRTL = 0;
2173302504Smav	sc->esc_FCRTH = 0;
2174302504Smav	sc->esc_RDLEN = 0;
2175302504Smav	sc->esc_RDH = 0;
2176302504Smav	sc->esc_RDT = 0;
2177302504Smav	sc->esc_RDTR = 0;
2178302504Smav	sc->esc_RXDCTL = (1 << 24) | (1 << 16); /* default GRAN/WTHRESH */
2179302504Smav	sc->esc_RADV = 0;
2180302504Smav	sc->esc_RXCSUM = 0;
2181302504Smav
2182302504Smav	/* transmit */
2183302504Smav	if (!drvr) {
2184302504Smav		sc->esc_TDBAL = 0;
2185302504Smav		sc->esc_TDBAH = 0;
2186302504Smav		sc->esc_TIPG = 0;
2187302504Smav		sc->esc_AIT = 0;
2188302504Smav		sc->esc_TIDV = 0;
2189302504Smav		sc->esc_TADV = 0;
2190302504Smav	}
2191302504Smav	sc->esc_tdba = 0;
2192302504Smav	sc->esc_txdesc = NULL;
2193302504Smav	sc->esc_TXCW = 0;
2194302504Smav	sc->esc_TCTL = 0;
2195302504Smav	sc->esc_TDLEN = 0;
2196302504Smav	sc->esc_TDT = 0;
2197302504Smav	sc->esc_TDHr = sc->esc_TDH = 0;
2198302504Smav	sc->esc_TXDCTL = 0;
2199302504Smav}
2200302504Smav
2201302504Smavstatic void
2202302504Smave82545_open_tap(struct e82545_softc *sc, char *opts)
2203302504Smav{
2204302504Smav	char tbuf[80];
2205302504Smav
2206302504Smav	if (opts == NULL) {
2207302504Smav		sc->esc_tapfd = -1;
2208302504Smav		return;
2209302504Smav	}
2210302504Smav
2211302504Smav	strcpy(tbuf, "/dev/");
2212302504Smav	strlcat(tbuf, opts, sizeof(tbuf));
2213302504Smav
2214302504Smav	sc->esc_tapfd = open(tbuf, O_RDWR);
2215302504Smav	if (sc->esc_tapfd == -1) {
2216302504Smav		DPRINTF("unable to open tap device %s\n", opts);
2217302504Smav		exit(1);
2218302504Smav	}
2219302504Smav
2220302504Smav	/*
2221302504Smav	 * Set non-blocking and register for read
2222302504Smav	 * notifications with the event loop
2223302504Smav	 */
2224302504Smav	int opt = 1;
2225302504Smav	if (ioctl(sc->esc_tapfd, FIONBIO, &opt) < 0) {
2226302504Smav		WPRINTF("tap device O_NONBLOCK failed: %d\n", errno);
2227302504Smav		close(sc->esc_tapfd);
2228302504Smav		sc->esc_tapfd = -1;
2229302504Smav	}
2230302504Smav
2231302504Smav	sc->esc_mevp = mevent_add(sc->esc_tapfd,
2232302504Smav				  EVF_READ,
2233302504Smav				  e82545_tap_callback,
2234302504Smav				  sc);
2235302504Smav	if (sc->esc_mevp == NULL) {
2236302504Smav		DPRINTF("Could not register mevent %d\n", EVF_READ);
2237302504Smav		close(sc->esc_tapfd);
2238302504Smav		sc->esc_tapfd = -1;
2239302504Smav	}
2240302504Smav}
2241302504Smav
2242302504Smavstatic int
2243302504Smave82545_parsemac(char *mac_str, uint8_t *mac_addr)
2244302504Smav{
2245302504Smav	struct ether_addr *ea;
2246302504Smav	char *tmpstr;
2247302504Smav	char zero_addr[ETHER_ADDR_LEN] = { 0, 0, 0, 0, 0, 0 };
2248302504Smav
2249302504Smav	tmpstr = strsep(&mac_str,"=");
2250302504Smav	if ((mac_str != NULL) && (!strcmp(tmpstr,"mac"))) {
2251302504Smav		ea = ether_aton(mac_str);
2252302504Smav		if (ea == NULL || ETHER_IS_MULTICAST(ea->octet) ||
2253302504Smav		    memcmp(ea->octet, zero_addr, ETHER_ADDR_LEN) == 0) {
2254302504Smav			fprintf(stderr, "Invalid MAC %s\n", mac_str);
2255302504Smav			return (1);
2256302504Smav		} else
2257302504Smav			memcpy(mac_addr, ea->octet, ETHER_ADDR_LEN);
2258302504Smav	}
2259302504Smav	return (0);
2260302504Smav}
2261302504Smav
2262302504Smavstatic int
2263302504Smave82545_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts)
2264302504Smav{
2265302504Smav	DPRINTF("Loading with options: %s\r\n", opts);
2266302504Smav
2267302504Smav	MD5_CTX mdctx;
2268302504Smav	unsigned char digest[16];
2269302504Smav	char nstr[80];
2270302504Smav	struct e82545_softc *sc;
2271302504Smav	char *devname;
2272302504Smav	char *vtopts;
2273302504Smav	int mac_provided;
2274302504Smav
2275302504Smav	/* Setup our softc */
2276302504Smav	sc = calloc(sizeof(*sc), 1);
2277302504Smav
2278302504Smav	pi->pi_arg = sc;
2279302504Smav	sc->esc_pi = pi;
2280302504Smav	sc->esc_ctx = ctx;
2281302504Smav
2282302504Smav	pthread_mutex_init(&sc->esc_mtx, NULL);
2283302504Smav	pthread_cond_init(&sc->esc_rx_cond, NULL);
2284302504Smav	pthread_cond_init(&sc->esc_tx_cond, NULL);
2285302504Smav	pthread_create(&sc->esc_tx_tid, NULL, e82545_tx_thread, sc);
2286302504Smav	snprintf(nstr, sizeof(nstr), "e82545-%d:%d tx", pi->pi_slot,
2287302504Smav	    pi->pi_func);
2288302504Smav        pthread_set_name_np(sc->esc_tx_tid, nstr);
2289302504Smav
2290302504Smav	pci_set_cfgdata16(pi, PCIR_DEVICE, E82545_DEV_ID_82545EM_COPPER);
2291302504Smav	pci_set_cfgdata16(pi, PCIR_VENDOR, E82545_VENDOR_ID_INTEL);
2292302504Smav	pci_set_cfgdata8(pi,  PCIR_CLASS, PCIC_NETWORK);
2293302504Smav	pci_set_cfgdata8(pi, PCIR_SUBCLASS, PCIS_NETWORK_ETHERNET);
2294302504Smav	pci_set_cfgdata16(pi, PCIR_SUBDEV_0, E82545_SUBDEV_ID);
2295302504Smav	pci_set_cfgdata16(pi, PCIR_SUBVEND_0, E82545_VENDOR_ID_INTEL);
2296302504Smav
2297302504Smav	pci_set_cfgdata8(pi,  PCIR_HDRTYPE, PCIM_HDRTYPE_NORMAL);
2298302504Smav	pci_set_cfgdata8(pi,  PCIR_INTPIN, 0x1);
2299302504Smav
2300302504Smav	/* TODO: this card also supports msi, but the freebsd driver for it
2301302504Smav	 * does not, so I have not implemented it. */
2302302504Smav	pci_lintr_request(pi);
2303302504Smav
2304302504Smav	pci_emul_alloc_bar(pi, E82545_BAR_REGISTER, PCIBAR_MEM32,
2305302504Smav		E82545_BAR_REGISTER_LEN);
2306302504Smav	pci_emul_alloc_bar(pi, E82545_BAR_FLASH, PCIBAR_MEM32,
2307302504Smav		E82545_BAR_FLASH_LEN);
2308302504Smav	pci_emul_alloc_bar(pi, E82545_BAR_IO, PCIBAR_IO,
2309302504Smav		E82545_BAR_IO_LEN);
2310302504Smav
2311302504Smav	/*
2312302504Smav	 * Attempt to open the tap device and read the MAC address
2313302504Smav	 * if specified.  Copied from virtio-net, slightly modified.
2314302504Smav	 */
2315302504Smav	mac_provided = 0;
2316302504Smav	sc->esc_tapfd = -1;
2317302504Smav	if (opts != NULL) {
2318302504Smav		int err;
2319302504Smav
2320302504Smav		devname = vtopts = strdup(opts);
2321302504Smav		(void) strsep(&vtopts, ",");
2322302504Smav
2323302504Smav		if (vtopts != NULL) {
2324302504Smav			err = e82545_parsemac(vtopts, sc->esc_mac.octet);
2325302504Smav			if (err != 0) {
2326302504Smav				free(devname);
2327302504Smav				return (err);
2328302504Smav			}
2329302504Smav			mac_provided = 1;
2330302504Smav		}
2331302504Smav
2332302504Smav		if (strncmp(devname, "tap", 3) == 0 ||
2333302504Smav		    strncmp(devname, "vmnet", 5) == 0)
2334302504Smav			e82545_open_tap(sc, devname);
2335302504Smav
2336302504Smav		free(devname);
2337302504Smav	}
2338302504Smav
2339302504Smav	/*
2340302504Smav	 * The default MAC address is the standard NetApp OUI of 00-a0-98,
2341302504Smav	 * followed by an MD5 of the PCI slot/func number and dev name
2342302504Smav	 */
2343302504Smav	if (!mac_provided) {
2344302504Smav		snprintf(nstr, sizeof(nstr), "%d-%d-%s", pi->pi_slot,
2345302504Smav		    pi->pi_func, vmname);
2346302504Smav
2347302504Smav		MD5Init(&mdctx);
2348302504Smav		MD5Update(&mdctx, nstr, strlen(nstr));
2349302504Smav		MD5Final(digest, &mdctx);
2350302504Smav
2351302504Smav		sc->esc_mac.octet[0] = 0x00;
2352302504Smav		sc->esc_mac.octet[1] = 0xa0;
2353302504Smav		sc->esc_mac.octet[2] = 0x98;
2354302504Smav		sc->esc_mac.octet[3] = digest[0];
2355302504Smav		sc->esc_mac.octet[4] = digest[1];
2356302504Smav		sc->esc_mac.octet[5] = digest[2];
2357302504Smav	}
2358302504Smav
2359302504Smav	/* H/w initiated reset */
2360302504Smav	e82545_reset(sc, 0);
2361302504Smav
2362302504Smav	return (0);
2363302504Smav}
2364302504Smav
2365302504Smavstruct pci_devemu pci_de_e82545 = {
2366302504Smav	.pe_emu = 	"e1000",
2367302504Smav	.pe_init =	e82545_init,
2368302504Smav	.pe_barwrite =	e82545_write,
2369302504Smav	.pe_barread =	e82545_read
2370302504Smav};
2371302504SmavPCI_EMUL_SET(pci_de_e82545);
2372302504Smav
2373