VirtualBox

source: vbox/trunk/src/VBox/Devices/Network/DevE1000.cpp@ 48166

Last change on this file since 48166 was 47580, checked in by vboxsync, 11 years ago

Devices/E1000: Fixed debug output for IPv4 addresses.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 315.6 KB
Line 
1/* $Id: DevE1000.cpp 47580 2013-08-07 10:36:00Z vboxsync $ */
2/** @file
3 * DevE1000 - Intel 82540EM Ethernet Controller Emulation.
4 *
5 * Implemented in accordance with the specification:
6 *
7 * PCI/PCI-X Family of Gigabit Ethernet Controllers Software Developer's Manual
8 * 82540EP/EM, 82541xx, 82544GC/EI, 82545GM/EM, 82546GB/EB, and 82547xx
9 *
10 * 317453-002 Revision 3.5
11 *
12 * @todo IPv6 checksum offloading support
13 * @todo Flexible Filter / Wakeup (optional?)
14 */
15
16/*
17 * Copyright (C) 2007-2013 Oracle Corporation
18 *
19 * This file is part of VirtualBox Open Source Edition (OSE), as
20 * available from http://www.virtualbox.org. This file is free software;
21 * you can redistribute it and/or modify it under the terms of the GNU
22 * General Public License (GPL) as published by the Free Software
23 * Foundation, in version 2 as it comes in the "COPYING" file of the
24 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
25 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
26 */
27
28/*******************************************************************************
29* Header Files *
30*******************************************************************************/
31#define LOG_GROUP LOG_GROUP_DEV_E1000
32#include <iprt/crc.h>
33#include <iprt/ctype.h>
34#include <iprt/net.h>
35#include <iprt/semaphore.h>
36#include <iprt/string.h>
37#include <iprt/time.h>
38#include <iprt/uuid.h>
39#include <VBox/vmm/pdmdev.h>
40#include <VBox/vmm/pdmnetifs.h>
41#include <VBox/vmm/pdmnetinline.h>
42#include <VBox/param.h>
43#include "VBoxDD.h"
44
45#include "DevEEPROM.h"
46#include "DevE1000Phy.h"
47
48
49/* Options *******************************************************************/
50/** @def E1K_INIT_RA0
51 * E1K_INIT_RA0 forces E1000 to set the first entry in Receive Address filter
52 * table to MAC address obtained from CFGM. Most guests read MAC address from
53 * EEPROM and write it to RA[0] explicitly, but Mac OS X seems to depend on it
54 * being already set (see @bugref{4657}).
55 */
56#define E1K_INIT_RA0
57/** @def E1K_LSC_ON_SLU
58 * E1K_LSC_ON_SLU causes E1000 to generate Link Status Change interrupt when
59 * the guest driver brings up the link via STATUS.LU bit. Again the only guest
60 * that requires it is Mac OS X (see @bugref{4657}).
61 */
62#define E1K_LSC_ON_SLU
63/** @def E1K_ITR_ENABLED
64 * E1K_ITR_ENABLED reduces the number of interrupts generated by E1000 if a
65 * guest driver requested it by writing non-zero value to the Interrupt
66 * Throttling Register (see section 13.4.18 in "8254x Family of Gigabit
67 * Ethernet Controllers Software Developer’s Manual").
68 */
69//#define E1K_ITR_ENABLED
70/** @def E1K_TX_DELAY
71 * E1K_TX_DELAY aims to improve guest-host transfer rate for TCP streams by
72 * preventing packets to be sent immediately. It allows to send several
73 * packets in a batch reducing the number of acknowledgments. Note that it
74 * effectively disables R0 TX path, forcing sending in R3.
75 */
76//#define E1K_TX_DELAY 150
77/** @def E1K_USE_TX_TIMERS
78 * E1K_USE_TX_TIMERS aims to reduce the number of generated TX interrupts if a
79 * guest driver set the delays via the Transmit Interrupt Delay Value (TIDV)
80 * register. Enabling it showed no positive effects on existing guests so it
81 * stays disabled. See sections 3.2.7.1 and 3.4.3.1 in "8254x Family of Gigabit
82 * Ethernet Controllers Software Developer’s Manual" for more detailed
83 * explanation.
84 */
85//#define E1K_USE_TX_TIMERS
86/** @def E1K_NO_TAD
87 * E1K_NO_TAD disables one of two timers enabled by E1K_USE_TX_TIMERS, the
88 * Transmit Absolute Delay time. This timer sets the maximum time interval
89 * during which TX interrupts can be postponed (delayed). It has no effect
90 * if E1K_USE_TX_TIMERS is not defined.
91 */
92//#define E1K_NO_TAD
93/** @def E1K_REL_DEBUG
94 * E1K_REL_DEBUG enables debug logging of l1, l2, l3 in release build.
95 */
96//#define E1K_REL_DEBUG
97/** @def E1K_INT_STATS
98 * E1K_INT_STATS enables collection of internal statistics used for
99 * debugging of delayed interrupts, etc.
100 */
101//#define E1K_INT_STATS
102/** @def E1K_WITH_MSI
103 * E1K_WITH_MSI enables rudimentary MSI support. Not implemented.
104 */
105//#define E1K_WITH_MSI
106/** @def E1K_WITH_TX_CS
107 * E1K_WITH_TX_CS protects e1kXmitPending with a critical section.
108 */
109#define E1K_WITH_TX_CS
110/** @def E1K_WITH_TXD_CACHE
111 * E1K_WITH_TXD_CACHE causes E1000 to fetch multiple TX descriptors in a
112 * single physical memory read (or two if it wraps around the end of TX
113 * descriptor ring). It is required for proper functioning of bandwidth
114 * resource control as it allows to compute exact sizes of packets prior
115 * to allocating their buffers (see @bugref{5582}).
116 */
117#define E1K_WITH_TXD_CACHE
118/** @def E1K_WITH_RXD_CACHE
119 * E1K_WITH_RXD_CACHE causes E1000 to fetch multiple RX descriptors in a
120 * single physical memory read (or two if it wraps around the end of RX
121 * descriptor ring). Intel's packet driver for DOS needs this option in
122 * order to work properly (see @bugref{6217}).
123 */
124#define E1K_WITH_RXD_CACHE
125/* End of Options ************************************************************/
126
127#ifdef E1K_WITH_TXD_CACHE
128/**
129 * E1K_TXD_CACHE_SIZE specifies the maximum number of TX descriptors stored
130 * in the state structure. It limits the amount of descriptors loaded in one
131 * batch read. For example, Linux guest may use up to 20 descriptors per
132 * TSE packet. The largest TSE packet seen (Windows guest) was 45 descriptors.
133 */
134# define E1K_TXD_CACHE_SIZE 64u
135#endif /* E1K_WITH_TXD_CACHE */
136
137#ifdef E1K_WITH_RXD_CACHE
138/**
139 * E1K_RXD_CACHE_SIZE specifies the maximum number of RX descriptors stored
140 * in the state structure. It limits the amount of descriptors loaded in one
141 * batch read. For example, XP guest adds 15 RX descriptors at a time.
142 */
143# define E1K_RXD_CACHE_SIZE 16u
144#endif /* E1K_WITH_RXD_CACHE */
145
146
147/* Little helpers ************************************************************/
148#undef htons
149#undef ntohs
150#undef htonl
151#undef ntohl
152#define htons(x) ((((x) & 0xff00) >> 8) | (((x) & 0x00ff) << 8))
153#define ntohs(x) htons(x)
154#define htonl(x) ASMByteSwapU32(x)
155#define ntohl(x) htonl(x)
156
157#ifndef DEBUG
158# ifdef E1K_REL_DEBUG
159# define DEBUG
160# define E1kLog(a) LogRel(a)
161# define E1kLog2(a) LogRel(a)
162# define E1kLog3(a) LogRel(a)
163# define E1kLogX(x, a) LogRel(a)
164//# define E1kLog3(a) do {} while (0)
165# else
166# define E1kLog(a) do {} while (0)
167# define E1kLog2(a) do {} while (0)
168# define E1kLog3(a) do {} while (0)
169# define E1kLogX(x, a) do {} while (0)
170# endif
171#else
172# define E1kLog(a) Log(a)
173# define E1kLog2(a) Log2(a)
174# define E1kLog3(a) Log3(a)
175# define E1kLogX(x, a) LogIt(LOG_INSTANCE, x, LOG_GROUP, a)
176//# define E1kLog(a) do {} while (0)
177//# define E1kLog2(a) do {} while (0)
178//# define E1kLog3(a) do {} while (0)
179#endif
180
181#if 0
182# define E1kLogRel(a) LogRel(a)
183#else
184# define E1kLogRel(a) do { } while (0)
185#endif
186
187//#undef DEBUG
188
189#define STATE_TO_DEVINS(pThis) (((PE1KSTATE )pThis)->CTX_SUFF(pDevIns))
190#define E1K_RELOCATE(p, o) *(RTHCUINTPTR *)&p += o
191
192#define E1K_INC_CNT32(cnt) \
193do { \
194 if (cnt < UINT32_MAX) \
195 cnt++; \
196} while (0)
197
198#define E1K_ADD_CNT64(cntLo, cntHi, val) \
199do { \
200 uint64_t u64Cnt = RT_MAKE_U64(cntLo, cntHi); \
201 uint64_t tmp = u64Cnt; \
202 u64Cnt += val; \
203 if (tmp > u64Cnt ) \
204 u64Cnt = UINT64_MAX; \
205 cntLo = (uint32_t)u64Cnt; \
206 cntHi = (uint32_t)(u64Cnt >> 32); \
207} while (0)
208
209#ifdef E1K_INT_STATS
210# define E1K_INC_ISTAT_CNT(cnt) do { ++cnt; } while (0)
211#else /* E1K_INT_STATS */
212# define E1K_INC_ISTAT_CNT(cnt) do { } while (0)
213#endif /* E1K_INT_STATS */
214
215
216/*****************************************************************************/
217
218typedef uint32_t E1KCHIP;
219#define E1K_CHIP_82540EM 0
220#define E1K_CHIP_82543GC 1
221#define E1K_CHIP_82545EM 2
222
223/** Different E1000 chips. */
224static const struct E1kChips
225{
226 uint16_t uPCIVendorId;
227 uint16_t uPCIDeviceId;
228 uint16_t uPCISubsystemVendorId;
229 uint16_t uPCISubsystemId;
230 const char *pcszName;
231} g_Chips[] =
232{
233 /* Vendor Device SSVendor SubSys Name */
234 { 0x8086,
235 /* Temporary code, as MSI-aware driver dislike 0x100E. How to do that right? */
236#ifdef E1K_WITH_MSI
237 0x105E,
238#else
239 0x100E,
240#endif
241 0x8086, 0x001E, "82540EM" }, /* Intel 82540EM-A in Intel PRO/1000 MT Desktop */
242 { 0x8086, 0x1004, 0x8086, 0x1004, "82543GC" }, /* Intel 82543GC in Intel PRO/1000 T Server */
243 { 0x8086, 0x100F, 0x15AD, 0x0750, "82545EM" } /* Intel 82545EM-A in VMWare Network Adapter */
244};
245
246
247/* The size of register area mapped to I/O space */
248#define E1K_IOPORT_SIZE 0x8
249/* The size of memory-mapped register area */
250#define E1K_MM_SIZE 0x20000
251
252#define E1K_MAX_TX_PKT_SIZE 16288
253#define E1K_MAX_RX_PKT_SIZE 16384
254
255/*****************************************************************************/
256
257/** Gets the specfieid bits from the register. */
258#define GET_BITS(reg, bits) ((reg & reg##_##bits##_MASK) >> reg##_##bits##_SHIFT)
259#define GET_BITS_V(val, reg, bits) ((val & reg##_##bits##_MASK) >> reg##_##bits##_SHIFT)
260#define BITS(reg, bits, bitval) (bitval << reg##_##bits##_SHIFT)
261#define SET_BITS(reg, bits, bitval) do { reg = (reg & ~reg##_##bits##_MASK) | (bitval << reg##_##bits##_SHIFT); } while (0)
262#define SET_BITS_V(val, reg, bits, bitval) do { val = (val & ~reg##_##bits##_MASK) | (bitval << reg##_##bits##_SHIFT); } while (0)
263
264#define CTRL_SLU UINT32_C(0x00000040)
265#define CTRL_MDIO UINT32_C(0x00100000)
266#define CTRL_MDC UINT32_C(0x00200000)
267#define CTRL_MDIO_DIR UINT32_C(0x01000000)
268#define CTRL_MDC_DIR UINT32_C(0x02000000)
269#define CTRL_RESET UINT32_C(0x04000000)
270#define CTRL_VME UINT32_C(0x40000000)
271
272#define STATUS_LU UINT32_C(0x00000002)
273#define STATUS_TXOFF UINT32_C(0x00000010)
274
275#define EECD_EE_WIRES UINT32_C(0x0F)
276#define EECD_EE_REQ UINT32_C(0x40)
277#define EECD_EE_GNT UINT32_C(0x80)
278
279#define EERD_START UINT32_C(0x00000001)
280#define EERD_DONE UINT32_C(0x00000010)
281#define EERD_DATA_MASK UINT32_C(0xFFFF0000)
282#define EERD_DATA_SHIFT 16
283#define EERD_ADDR_MASK UINT32_C(0x0000FF00)
284#define EERD_ADDR_SHIFT 8
285
286#define MDIC_DATA_MASK UINT32_C(0x0000FFFF)
287#define MDIC_DATA_SHIFT 0
288#define MDIC_REG_MASK UINT32_C(0x001F0000)
289#define MDIC_REG_SHIFT 16
290#define MDIC_PHY_MASK UINT32_C(0x03E00000)
291#define MDIC_PHY_SHIFT 21
292#define MDIC_OP_WRITE UINT32_C(0x04000000)
293#define MDIC_OP_READ UINT32_C(0x08000000)
294#define MDIC_READY UINT32_C(0x10000000)
295#define MDIC_INT_EN UINT32_C(0x20000000)
296#define MDIC_ERROR UINT32_C(0x40000000)
297
298#define TCTL_EN UINT32_C(0x00000002)
299#define TCTL_PSP UINT32_C(0x00000008)
300
301#define RCTL_EN UINT32_C(0x00000002)
302#define RCTL_UPE UINT32_C(0x00000008)
303#define RCTL_MPE UINT32_C(0x00000010)
304#define RCTL_LPE UINT32_C(0x00000020)
305#define RCTL_LBM_MASK UINT32_C(0x000000C0)
306#define RCTL_LBM_SHIFT 6
307#define RCTL_RDMTS_MASK UINT32_C(0x00000300)
308#define RCTL_RDMTS_SHIFT 8
309#define RCTL_LBM_TCVR UINT32_C(3) /**< PHY or external SerDes loopback. */
310#define RCTL_MO_MASK UINT32_C(0x00003000)
311#define RCTL_MO_SHIFT 12
312#define RCTL_BAM UINT32_C(0x00008000)
313#define RCTL_BSIZE_MASK UINT32_C(0x00030000)
314#define RCTL_BSIZE_SHIFT 16
315#define RCTL_VFE UINT32_C(0x00040000)
316#define RCTL_CFIEN UINT32_C(0x00080000)
317#define RCTL_CFI UINT32_C(0x00100000)
318#define RCTL_BSEX UINT32_C(0x02000000)
319#define RCTL_SECRC UINT32_C(0x04000000)
320
321#define ICR_TXDW UINT32_C(0x00000001)
322#define ICR_TXQE UINT32_C(0x00000002)
323#define ICR_LSC UINT32_C(0x00000004)
324#define ICR_RXDMT0 UINT32_C(0x00000010)
325#define ICR_RXT0 UINT32_C(0x00000080)
326#define ICR_TXD_LOW UINT32_C(0x00008000)
327#define RDTR_FPD UINT32_C(0x80000000)
328
329#define PBA_st ((PBAST*)(pThis->auRegs + PBA_IDX))
330typedef struct
331{
332 unsigned rxa : 7;
333 unsigned rxa_r : 9;
334 unsigned txa : 16;
335} PBAST;
336AssertCompileSize(PBAST, 4);
337
338#define TXDCTL_WTHRESH_MASK 0x003F0000
339#define TXDCTL_WTHRESH_SHIFT 16
340#define TXDCTL_LWTHRESH_MASK 0xFE000000
341#define TXDCTL_LWTHRESH_SHIFT 25
342
343#define RXCSUM_PCSS_MASK UINT32_C(0x000000FF)
344#define RXCSUM_PCSS_SHIFT 0
345
346/** @name Register access macros
347 * @remarks These ASSUME alocal variable @a pThis of type PE1KSTATE.
348 * @{ */
349#define CTRL pThis->auRegs[CTRL_IDX]
350#define STATUS pThis->auRegs[STATUS_IDX]
351#define EECD pThis->auRegs[EECD_IDX]
352#define EERD pThis->auRegs[EERD_IDX]
353#define CTRL_EXT pThis->auRegs[CTRL_EXT_IDX]
354#define FLA pThis->auRegs[FLA_IDX]
355#define MDIC pThis->auRegs[MDIC_IDX]
356#define FCAL pThis->auRegs[FCAL_IDX]
357#define FCAH pThis->auRegs[FCAH_IDX]
358#define FCT pThis->auRegs[FCT_IDX]
359#define VET pThis->auRegs[VET_IDX]
360#define ICR pThis->auRegs[ICR_IDX]
361#define ITR pThis->auRegs[ITR_IDX]
362#define ICS pThis->auRegs[ICS_IDX]
363#define IMS pThis->auRegs[IMS_IDX]
364#define IMC pThis->auRegs[IMC_IDX]
365#define RCTL pThis->auRegs[RCTL_IDX]
366#define FCTTV pThis->auRegs[FCTTV_IDX]
367#define TXCW pThis->auRegs[TXCW_IDX]
368#define RXCW pThis->auRegs[RXCW_IDX]
369#define TCTL pThis->auRegs[TCTL_IDX]
370#define TIPG pThis->auRegs[TIPG_IDX]
371#define AIFS pThis->auRegs[AIFS_IDX]
372#define LEDCTL pThis->auRegs[LEDCTL_IDX]
373#define PBA pThis->auRegs[PBA_IDX]
374#define FCRTL pThis->auRegs[FCRTL_IDX]
375#define FCRTH pThis->auRegs[FCRTH_IDX]
376#define RDFH pThis->auRegs[RDFH_IDX]
377#define RDFT pThis->auRegs[RDFT_IDX]
378#define RDFHS pThis->auRegs[RDFHS_IDX]
379#define RDFTS pThis->auRegs[RDFTS_IDX]
380#define RDFPC pThis->auRegs[RDFPC_IDX]
381#define RDBAL pThis->auRegs[RDBAL_IDX]
382#define RDBAH pThis->auRegs[RDBAH_IDX]
383#define RDLEN pThis->auRegs[RDLEN_IDX]
384#define RDH pThis->auRegs[RDH_IDX]
385#define RDT pThis->auRegs[RDT_IDX]
386#define RDTR pThis->auRegs[RDTR_IDX]
387#define RXDCTL pThis->auRegs[RXDCTL_IDX]
388#define RADV pThis->auRegs[RADV_IDX]
389#define RSRPD pThis->auRegs[RSRPD_IDX]
390#define TXDMAC pThis->auRegs[TXDMAC_IDX]
391#define TDFH pThis->auRegs[TDFH_IDX]
392#define TDFT pThis->auRegs[TDFT_IDX]
393#define TDFHS pThis->auRegs[TDFHS_IDX]
394#define TDFTS pThis->auRegs[TDFTS_IDX]
395#define TDFPC pThis->auRegs[TDFPC_IDX]
396#define TDBAL pThis->auRegs[TDBAL_IDX]
397#define TDBAH pThis->auRegs[TDBAH_IDX]
398#define TDLEN pThis->auRegs[TDLEN_IDX]
399#define TDH pThis->auRegs[TDH_IDX]
400#define TDT pThis->auRegs[TDT_IDX]
401#define TIDV pThis->auRegs[TIDV_IDX]
402#define TXDCTL pThis->auRegs[TXDCTL_IDX]
403#define TADV pThis->auRegs[TADV_IDX]
404#define TSPMT pThis->auRegs[TSPMT_IDX]
405#define CRCERRS pThis->auRegs[CRCERRS_IDX]
406#define ALGNERRC pThis->auRegs[ALGNERRC_IDX]
407#define SYMERRS pThis->auRegs[SYMERRS_IDX]
408#define RXERRC pThis->auRegs[RXERRC_IDX]
409#define MPC pThis->auRegs[MPC_IDX]
410#define SCC pThis->auRegs[SCC_IDX]
411#define ECOL pThis->auRegs[ECOL_IDX]
412#define MCC pThis->auRegs[MCC_IDX]
413#define LATECOL pThis->auRegs[LATECOL_IDX]
414#define COLC pThis->auRegs[COLC_IDX]
415#define DC pThis->auRegs[DC_IDX]
416#define TNCRS pThis->auRegs[TNCRS_IDX]
417/* #define SEC pThis->auRegs[SEC_IDX] Conflict with sys/time.h */
418#define CEXTERR pThis->auRegs[CEXTERR_IDX]
419#define RLEC pThis->auRegs[RLEC_IDX]
420#define XONRXC pThis->auRegs[XONRXC_IDX]
421#define XONTXC pThis->auRegs[XONTXC_IDX]
422#define XOFFRXC pThis->auRegs[XOFFRXC_IDX]
423#define XOFFTXC pThis->auRegs[XOFFTXC_IDX]
424#define FCRUC pThis->auRegs[FCRUC_IDX]
425#define PRC64 pThis->auRegs[PRC64_IDX]
426#define PRC127 pThis->auRegs[PRC127_IDX]
427#define PRC255 pThis->auRegs[PRC255_IDX]
428#define PRC511 pThis->auRegs[PRC511_IDX]
429#define PRC1023 pThis->auRegs[PRC1023_IDX]
430#define PRC1522 pThis->auRegs[PRC1522_IDX]
431#define GPRC pThis->auRegs[GPRC_IDX]
432#define BPRC pThis->auRegs[BPRC_IDX]
433#define MPRC pThis->auRegs[MPRC_IDX]
434#define GPTC pThis->auRegs[GPTC_IDX]
435#define GORCL pThis->auRegs[GORCL_IDX]
436#define GORCH pThis->auRegs[GORCH_IDX]
437#define GOTCL pThis->auRegs[GOTCL_IDX]
438#define GOTCH pThis->auRegs[GOTCH_IDX]
439#define RNBC pThis->auRegs[RNBC_IDX]
440#define RUC pThis->auRegs[RUC_IDX]
441#define RFC pThis->auRegs[RFC_IDX]
442#define ROC pThis->auRegs[ROC_IDX]
443#define RJC pThis->auRegs[RJC_IDX]
444#define MGTPRC pThis->auRegs[MGTPRC_IDX]
445#define MGTPDC pThis->auRegs[MGTPDC_IDX]
446#define MGTPTC pThis->auRegs[MGTPTC_IDX]
447#define TORL pThis->auRegs[TORL_IDX]
448#define TORH pThis->auRegs[TORH_IDX]
449#define TOTL pThis->auRegs[TOTL_IDX]
450#define TOTH pThis->auRegs[TOTH_IDX]
451#define TPR pThis->auRegs[TPR_IDX]
452#define TPT pThis->auRegs[TPT_IDX]
453#define PTC64 pThis->auRegs[PTC64_IDX]
454#define PTC127 pThis->auRegs[PTC127_IDX]
455#define PTC255 pThis->auRegs[PTC255_IDX]
456#define PTC511 pThis->auRegs[PTC511_IDX]
457#define PTC1023 pThis->auRegs[PTC1023_IDX]
458#define PTC1522 pThis->auRegs[PTC1522_IDX]
459#define MPTC pThis->auRegs[MPTC_IDX]
460#define BPTC pThis->auRegs[BPTC_IDX]
461#define TSCTC pThis->auRegs[TSCTC_IDX]
462#define TSCTFC pThis->auRegs[TSCTFC_IDX]
463#define RXCSUM pThis->auRegs[RXCSUM_IDX]
464#define WUC pThis->auRegs[WUC_IDX]
465#define WUFC pThis->auRegs[WUFC_IDX]
466#define WUS pThis->auRegs[WUS_IDX]
467#define MANC pThis->auRegs[MANC_IDX]
468#define IPAV pThis->auRegs[IPAV_IDX]
469#define WUPL pThis->auRegs[WUPL_IDX]
470/** @} */
471
472/**
473 * Indices of memory-mapped registers in register table.
474 */
475typedef enum
476{
477 CTRL_IDX,
478 STATUS_IDX,
479 EECD_IDX,
480 EERD_IDX,
481 CTRL_EXT_IDX,
482 FLA_IDX,
483 MDIC_IDX,
484 FCAL_IDX,
485 FCAH_IDX,
486 FCT_IDX,
487 VET_IDX,
488 ICR_IDX,
489 ITR_IDX,
490 ICS_IDX,
491 IMS_IDX,
492 IMC_IDX,
493 RCTL_IDX,
494 FCTTV_IDX,
495 TXCW_IDX,
496 RXCW_IDX,
497 TCTL_IDX,
498 TIPG_IDX,
499 AIFS_IDX,
500 LEDCTL_IDX,
501 PBA_IDX,
502 FCRTL_IDX,
503 FCRTH_IDX,
504 RDFH_IDX,
505 RDFT_IDX,
506 RDFHS_IDX,
507 RDFTS_IDX,
508 RDFPC_IDX,
509 RDBAL_IDX,
510 RDBAH_IDX,
511 RDLEN_IDX,
512 RDH_IDX,
513 RDT_IDX,
514 RDTR_IDX,
515 RXDCTL_IDX,
516 RADV_IDX,
517 RSRPD_IDX,
518 TXDMAC_IDX,
519 TDFH_IDX,
520 TDFT_IDX,
521 TDFHS_IDX,
522 TDFTS_IDX,
523 TDFPC_IDX,
524 TDBAL_IDX,
525 TDBAH_IDX,
526 TDLEN_IDX,
527 TDH_IDX,
528 TDT_IDX,
529 TIDV_IDX,
530 TXDCTL_IDX,
531 TADV_IDX,
532 TSPMT_IDX,
533 CRCERRS_IDX,
534 ALGNERRC_IDX,
535 SYMERRS_IDX,
536 RXERRC_IDX,
537 MPC_IDX,
538 SCC_IDX,
539 ECOL_IDX,
540 MCC_IDX,
541 LATECOL_IDX,
542 COLC_IDX,
543 DC_IDX,
544 TNCRS_IDX,
545 SEC_IDX,
546 CEXTERR_IDX,
547 RLEC_IDX,
548 XONRXC_IDX,
549 XONTXC_IDX,
550 XOFFRXC_IDX,
551 XOFFTXC_IDX,
552 FCRUC_IDX,
553 PRC64_IDX,
554 PRC127_IDX,
555 PRC255_IDX,
556 PRC511_IDX,
557 PRC1023_IDX,
558 PRC1522_IDX,
559 GPRC_IDX,
560 BPRC_IDX,
561 MPRC_IDX,
562 GPTC_IDX,
563 GORCL_IDX,
564 GORCH_IDX,
565 GOTCL_IDX,
566 GOTCH_IDX,
567 RNBC_IDX,
568 RUC_IDX,
569 RFC_IDX,
570 ROC_IDX,
571 RJC_IDX,
572 MGTPRC_IDX,
573 MGTPDC_IDX,
574 MGTPTC_IDX,
575 TORL_IDX,
576 TORH_IDX,
577 TOTL_IDX,
578 TOTH_IDX,
579 TPR_IDX,
580 TPT_IDX,
581 PTC64_IDX,
582 PTC127_IDX,
583 PTC255_IDX,
584 PTC511_IDX,
585 PTC1023_IDX,
586 PTC1522_IDX,
587 MPTC_IDX,
588 BPTC_IDX,
589 TSCTC_IDX,
590 TSCTFC_IDX,
591 RXCSUM_IDX,
592 WUC_IDX,
593 WUFC_IDX,
594 WUS_IDX,
595 MANC_IDX,
596 IPAV_IDX,
597 WUPL_IDX,
598 MTA_IDX,
599 RA_IDX,
600 VFTA_IDX,
601 IP4AT_IDX,
602 IP6AT_IDX,
603 WUPM_IDX,
604 FFLT_IDX,
605 FFMT_IDX,
606 FFVT_IDX,
607 PBM_IDX,
608 RA_82542_IDX,
609 MTA_82542_IDX,
610 VFTA_82542_IDX,
611 E1K_NUM_OF_REGS
612} E1kRegIndex;
613
614#define E1K_NUM_OF_32BIT_REGS MTA_IDX
615/** The number of registers with strictly increasing offset. */
616#define E1K_NUM_OF_BINARY_SEARCHABLE (WUPL_IDX + 1)
617
618
619/**
620 * Define E1000-specific EEPROM layout.
621 */
622struct E1kEEPROM
623{
624 public:
625 EEPROM93C46 eeprom;
626
627#ifdef IN_RING3
628 /**
629 * Initialize EEPROM content.
630 *
631 * @param macAddr MAC address of E1000.
632 */
633 void init(RTMAC &macAddr)
634 {
635 eeprom.init();
636 memcpy(eeprom.m_au16Data, macAddr.au16, sizeof(macAddr.au16));
637 eeprom.m_au16Data[0x04] = 0xFFFF;
638 /*
639 * bit 3 - full support for power management
640 * bit 10 - full duplex
641 */
642 eeprom.m_au16Data[0x0A] = 0x4408;
643 eeprom.m_au16Data[0x0B] = 0x001E;
644 eeprom.m_au16Data[0x0C] = 0x8086;
645 eeprom.m_au16Data[0x0D] = 0x100E;
646 eeprom.m_au16Data[0x0E] = 0x8086;
647 eeprom.m_au16Data[0x0F] = 0x3040;
648 eeprom.m_au16Data[0x21] = 0x7061;
649 eeprom.m_au16Data[0x22] = 0x280C;
650 eeprom.m_au16Data[0x23] = 0x00C8;
651 eeprom.m_au16Data[0x24] = 0x00C8;
652 eeprom.m_au16Data[0x2F] = 0x0602;
653 updateChecksum();
654 };
655
656 /**
657 * Compute the checksum as required by E1000 and store it
658 * in the last word.
659 */
660 void updateChecksum()
661 {
662 uint16_t u16Checksum = 0;
663
664 for (int i = 0; i < eeprom.SIZE-1; i++)
665 u16Checksum += eeprom.m_au16Data[i];
666 eeprom.m_au16Data[eeprom.SIZE-1] = 0xBABA - u16Checksum;
667 };
668
669 /**
670 * First 6 bytes of EEPROM contain MAC address.
671 *
672 * @returns MAC address of E1000.
673 */
674 void getMac(PRTMAC pMac)
675 {
676 memcpy(pMac->au16, eeprom.m_au16Data, sizeof(pMac->au16));
677 };
678
679 uint32_t read()
680 {
681 return eeprom.read();
682 }
683
684 void write(uint32_t u32Wires)
685 {
686 eeprom.write(u32Wires);
687 }
688
689 bool readWord(uint32_t u32Addr, uint16_t *pu16Value)
690 {
691 return eeprom.readWord(u32Addr, pu16Value);
692 }
693
694 int load(PSSMHANDLE pSSM)
695 {
696 return eeprom.load(pSSM);
697 }
698
699 void save(PSSMHANDLE pSSM)
700 {
701 eeprom.save(pSSM);
702 }
703#endif /* IN_RING3 */
704};
705
706
707#define E1K_SPEC_VLAN(s) (s & 0xFFF)
708#define E1K_SPEC_CFI(s) (!!((s>>12) & 0x1))
709#define E1K_SPEC_PRI(s) ((s>>13) & 0x7)
710
711struct E1kRxDStatus
712{
713 /** @name Descriptor Status field (3.2.3.1)
714 * @{ */
715 unsigned fDD : 1; /**< Descriptor Done. */
716 unsigned fEOP : 1; /**< End of packet. */
717 unsigned fIXSM : 1; /**< Ignore checksum indication. */
718 unsigned fVP : 1; /**< VLAN, matches VET. */
719 unsigned : 1;
720 unsigned fTCPCS : 1; /**< RCP Checksum calculated on the packet. */
721 unsigned fIPCS : 1; /**< IP Checksum calculated on the packet. */
722 unsigned fPIF : 1; /**< Passed in-exact filter */
723 /** @} */
724 /** @name Descriptor Errors field (3.2.3.2)
725 * (Only valid when fEOP and fDD are set.)
726 * @{ */
727 unsigned fCE : 1; /**< CRC or alignment error. */
728 unsigned : 4; /**< Reserved, varies with different models... */
729 unsigned fTCPE : 1; /**< TCP/UDP checksum error. */
730 unsigned fIPE : 1; /**< IP Checksum error. */
731 unsigned fRXE : 1; /**< RX Data error. */
732 /** @} */
733 /** @name Descriptor Special field (3.2.3.3)
734 * @{ */
735 unsigned u16Special : 16; /**< VLAN: Id, Canonical form, Priority. */
736 /** @} */
737};
738typedef struct E1kRxDStatus E1KRXDST;
739
740struct E1kRxDesc_st
741{
742 uint64_t u64BufAddr; /**< Address of data buffer */
743 uint16_t u16Length; /**< Length of data in buffer */
744 uint16_t u16Checksum; /**< Packet checksum */
745 E1KRXDST status;
746};
747typedef struct E1kRxDesc_st E1KRXDESC;
748AssertCompileSize(E1KRXDESC, 16);
749
750#define E1K_DTYP_LEGACY -1
751#define E1K_DTYP_CONTEXT 0
752#define E1K_DTYP_DATA 1
753
754struct E1kTDLegacy
755{
756 uint64_t u64BufAddr; /**< Address of data buffer */
757 struct TDLCmd_st
758 {
759 unsigned u16Length : 16;
760 unsigned u8CSO : 8;
761 /* CMD field : 8 */
762 unsigned fEOP : 1;
763 unsigned fIFCS : 1;
764 unsigned fIC : 1;
765 unsigned fRS : 1;
766 unsigned fRPS : 1;
767 unsigned fDEXT : 1;
768 unsigned fVLE : 1;
769 unsigned fIDE : 1;
770 } cmd;
771 struct TDLDw3_st
772 {
773 /* STA field */
774 unsigned fDD : 1;
775 unsigned fEC : 1;
776 unsigned fLC : 1;
777 unsigned fTURSV : 1;
778 /* RSV field */
779 unsigned u4RSV : 4;
780 /* CSS field */
781 unsigned u8CSS : 8;
782 /* Special field*/
783 unsigned u16Special: 16;
784 } dw3;
785};
786
787/**
788 * TCP/IP Context Transmit Descriptor, section 3.3.6.
789 */
790struct E1kTDContext
791{
792 struct CheckSum_st
793 {
794 /** TSE: Header start. !TSE: Checksum start. */
795 unsigned u8CSS : 8;
796 /** Checksum offset - where to store it. */
797 unsigned u8CSO : 8;
798 /** Checksum ending (inclusive) offset, 0 = end of packet. */
799 unsigned u16CSE : 16;
800 } ip;
801 struct CheckSum_st tu;
802 struct TDCDw2_st
803 {
804 /** TSE: The total number of payload bytes for this context. Sans header. */
805 unsigned u20PAYLEN : 20;
806 /** The descriptor type - E1K_DTYP_CONTEXT (0). */
807 unsigned u4DTYP : 4;
808 /** TUCMD field, 8 bits
809 * @{ */
810 /** TSE: TCP (set) or UDP (clear). */
811 unsigned fTCP : 1;
812 /** TSE: IPv4 (set) or IPv6 (clear) - for finding the payload length field in
813 * the IP header. Does not affect the checksumming.
814 * @remarks 82544GC/EI interprets a cleared field differently. */
815 unsigned fIP : 1;
816 /** TSE: TCP segmentation enable. When clear the context describes */
817 unsigned fTSE : 1;
818 /** Report status (only applies to dw3.fDD for here). */
819 unsigned fRS : 1;
820 /** Reserved, MBZ. */
821 unsigned fRSV1 : 1;
822 /** Descriptor extension, must be set for this descriptor type. */
823 unsigned fDEXT : 1;
824 /** Reserved, MBZ. */
825 unsigned fRSV2 : 1;
826 /** Interrupt delay enable. */
827 unsigned fIDE : 1;
828 /** @} */
829 } dw2;
830 struct TDCDw3_st
831 {
832 /** Descriptor Done. */
833 unsigned fDD : 1;
834 /** Reserved, MBZ. */
835 unsigned u7RSV : 7;
836 /** TSO: The header (prototype) length (Ethernet[, VLAN tag], IP, TCP/UDP. */
837 unsigned u8HDRLEN : 8;
838 /** TSO: Maximum segment size. */
839 unsigned u16MSS : 16;
840 } dw3;
841};
842typedef struct E1kTDContext E1KTXCTX;
843
844/**
845 * TCP/IP Data Transmit Descriptor, section 3.3.7.
846 */
847struct E1kTDData
848{
849 uint64_t u64BufAddr; /**< Address of data buffer */
850 struct TDDCmd_st
851 {
852 /** The total length of data pointed to by this descriptor. */
853 unsigned u20DTALEN : 20;
854 /** The descriptor type - E1K_DTYP_DATA (1). */
855 unsigned u4DTYP : 4;
856 /** @name DCMD field, 8 bits (3.3.7.1).
857 * @{ */
858 /** End of packet. Note TSCTFC update. */
859 unsigned fEOP : 1;
860 /** Insert Ethernet FCS/CRC (requires fEOP to be set). */
861 unsigned fIFCS : 1;
862 /** Use the TSE context when set and the normal when clear. */
863 unsigned fTSE : 1;
864 /** Report status (dw3.STA). */
865 unsigned fRS : 1;
866 /** Reserved. 82544GC/EI defines this report packet set (RPS). */
867 unsigned fRPS : 1;
868 /** Descriptor extension, must be set for this descriptor type. */
869 unsigned fDEXT : 1;
870 /** VLAN enable, requires CTRL.VME, auto enables FCS/CRC.
871 * Insert dw3.SPECIAL after ethernet header. */
872 unsigned fVLE : 1;
873 /** Interrupt delay enable. */
874 unsigned fIDE : 1;
875 /** @} */
876 } cmd;
877 struct TDDDw3_st
878 {
879 /** @name STA field (3.3.7.2)
880 * @{ */
881 unsigned fDD : 1; /**< Descriptor done. */
882 unsigned fEC : 1; /**< Excess collision. */
883 unsigned fLC : 1; /**< Late collision. */
884 /** Reserved, except for the usual oddball (82544GC/EI) where it's called TU. */
885 unsigned fTURSV : 1;
886 /** @} */
887 unsigned u4RSV : 4; /**< Reserved field, MBZ. */
888 /** @name POPTS (Packet Option) field (3.3.7.3)
889 * @{ */
890 unsigned fIXSM : 1; /**< Insert IP checksum. */
891 unsigned fTXSM : 1; /**< Insert TCP/UDP checksum. */
892 unsigned u6RSV : 6; /**< Reserved, MBZ. */
893 /** @} */
894 /** @name SPECIAL field - VLAN tag to be inserted after ethernet header.
895 * Requires fEOP, fVLE and CTRL.VME to be set.
896 * @{ */
897 unsigned u16Special: 16; /**< VLAN: Id, Canonical form, Priority. */
898 /** @} */
899 } dw3;
900};
901typedef struct E1kTDData E1KTXDAT;
902
903union E1kTxDesc
904{
905 struct E1kTDLegacy legacy;
906 struct E1kTDContext context;
907 struct E1kTDData data;
908};
909typedef union E1kTxDesc E1KTXDESC;
910AssertCompileSize(E1KTXDESC, 16);
911
912#define RA_CTL_AS 0x0003
913#define RA_CTL_AV 0x8000
914
915union E1kRecAddr
916{
917 uint32_t au32[32];
918 struct RAArray
919 {
920 uint8_t addr[6];
921 uint16_t ctl;
922 } array[16];
923};
924typedef struct E1kRecAddr::RAArray E1KRAELEM;
925typedef union E1kRecAddr E1KRA;
926AssertCompileSize(E1KRA, 8*16);
927
928#define E1K_IP_RF UINT16_C(0x8000) /**< reserved fragment flag */
929#define E1K_IP_DF UINT16_C(0x4000) /**< dont fragment flag */
930#define E1K_IP_MF UINT16_C(0x2000) /**< more fragments flag */
931#define E1K_IP_OFFMASK UINT16_C(0x1fff) /**< mask for fragmenting bits */
932
933/** @todo use+extend RTNETIPV4 */
934struct E1kIpHeader
935{
936 /* type of service / version / header length */
937 uint16_t tos_ver_hl;
938 /* total length */
939 uint16_t total_len;
940 /* identification */
941 uint16_t ident;
942 /* fragment offset field */
943 uint16_t offset;
944 /* time to live / protocol*/
945 uint16_t ttl_proto;
946 /* checksum */
947 uint16_t chksum;
948 /* source IP address */
949 uint32_t src;
950 /* destination IP address */
951 uint32_t dest;
952};
953AssertCompileSize(struct E1kIpHeader, 20);
954
955#define E1K_TCP_FIN UINT16_C(0x01)
956#define E1K_TCP_SYN UINT16_C(0x02)
957#define E1K_TCP_RST UINT16_C(0x04)
958#define E1K_TCP_PSH UINT16_C(0x08)
959#define E1K_TCP_ACK UINT16_C(0x10)
960#define E1K_TCP_URG UINT16_C(0x20)
961#define E1K_TCP_ECE UINT16_C(0x40)
962#define E1K_TCP_CWR UINT16_C(0x80)
963#define E1K_TCP_FLAGS UINT16_C(0x3f)
964
965/** @todo use+extend RTNETTCP */
966struct E1kTcpHeader
967{
968 uint16_t src;
969 uint16_t dest;
970 uint32_t seqno;
971 uint32_t ackno;
972 uint16_t hdrlen_flags;
973 uint16_t wnd;
974 uint16_t chksum;
975 uint16_t urgp;
976};
977AssertCompileSize(struct E1kTcpHeader, 20);
978
979
980#ifdef E1K_WITH_TXD_CACHE
981/** The current Saved state version. */
982# define E1K_SAVEDSTATE_VERSION 4
983/** Saved state version for VirtualBox 4.2 with VLAN tag fields. */
984# define E1K_SAVEDSTATE_VERSION_VBOX_42_VTAG 3
985#else /* !E1K_WITH_TXD_CACHE */
986/** The current Saved state version. */
987# define E1K_SAVEDSTATE_VERSION 3
988#endif /* !E1K_WITH_TXD_CACHE */
989/** Saved state version for VirtualBox 4.1 and earlier.
990 * These did not include VLAN tag fields. */
991#define E1K_SAVEDSTATE_VERSION_VBOX_41 2
992/** Saved state version for VirtualBox 3.0 and earlier.
993 * This did not include the configuration part nor the E1kEEPROM. */
994#define E1K_SAVEDSTATE_VERSION_VBOX_30 1
995
996/**
997 * Device state structure.
998 *
999 * Holds the current state of device.
1000 *
1001 * @implements PDMINETWORKDOWN
1002 * @implements PDMINETWORKCONFIG
1003 * @implements PDMILEDPORTS
1004 */
1005struct E1kState_st
1006{
1007 char szPrf[8]; /**< Log prefix, e.g. E1000#1. */
1008 PDMIBASE IBase;
1009 PDMINETWORKDOWN INetworkDown;
1010 PDMINETWORKCONFIG INetworkConfig;
1011 PDMILEDPORTS ILeds; /**< LED interface */
1012 R3PTRTYPE(PPDMIBASE) pDrvBase; /**< Attached network driver. */
1013 R3PTRTYPE(PPDMILEDCONNECTORS) pLedsConnector;
1014
1015 PPDMDEVINSR3 pDevInsR3; /**< Device instance - R3. */
1016 R3PTRTYPE(PPDMQUEUE) pTxQueueR3; /**< Transmit queue - R3. */
1017 R3PTRTYPE(PPDMQUEUE) pCanRxQueueR3; /**< Rx wakeup signaller - R3. */
1018 PPDMINETWORKUPR3 pDrvR3; /**< Attached network driver - R3. */
1019 PTMTIMERR3 pRIDTimerR3; /**< Receive Interrupt Delay Timer - R3. */
1020 PTMTIMERR3 pRADTimerR3; /**< Receive Absolute Delay Timer - R3. */
1021 PTMTIMERR3 pTIDTimerR3; /**< Transmit Interrupt Delay Timer - R3. */
1022 PTMTIMERR3 pTADTimerR3; /**< Transmit Absolute Delay Timer - R3. */
1023 PTMTIMERR3 pTXDTimerR3; /**< Transmit Delay Timer - R3. */
1024 PTMTIMERR3 pIntTimerR3; /**< Late Interrupt Timer - R3. */
1025 PTMTIMERR3 pLUTimerR3; /**< Link Up(/Restore) Timer. */
1026 /** The scatter / gather buffer used for the current outgoing packet - R3. */
1027 R3PTRTYPE(PPDMSCATTERGATHER) pTxSgR3;
1028
1029 PPDMDEVINSR0 pDevInsR0; /**< Device instance - R0. */
1030 R0PTRTYPE(PPDMQUEUE) pTxQueueR0; /**< Transmit queue - R0. */
1031 R0PTRTYPE(PPDMQUEUE) pCanRxQueueR0; /**< Rx wakeup signaller - R0. */
1032 PPDMINETWORKUPR0 pDrvR0; /**< Attached network driver - R0. */
1033 PTMTIMERR0 pRIDTimerR0; /**< Receive Interrupt Delay Timer - R0. */
1034 PTMTIMERR0 pRADTimerR0; /**< Receive Absolute Delay Timer - R0. */
1035 PTMTIMERR0 pTIDTimerR0; /**< Transmit Interrupt Delay Timer - R0. */
1036 PTMTIMERR0 pTADTimerR0; /**< Transmit Absolute Delay Timer - R0. */
1037 PTMTIMERR0 pTXDTimerR0; /**< Transmit Delay Timer - R0. */
1038 PTMTIMERR0 pIntTimerR0; /**< Late Interrupt Timer - R0. */
1039 PTMTIMERR0 pLUTimerR0; /**< Link Up(/Restore) Timer - R0. */
1040 /** The scatter / gather buffer used for the current outgoing packet - R0. */
1041 R0PTRTYPE(PPDMSCATTERGATHER) pTxSgR0;
1042
1043 PPDMDEVINSRC pDevInsRC; /**< Device instance - RC. */
1044 RCPTRTYPE(PPDMQUEUE) pTxQueueRC; /**< Transmit queue - RC. */
1045 RCPTRTYPE(PPDMQUEUE) pCanRxQueueRC; /**< Rx wakeup signaller - RC. */
1046 PPDMINETWORKUPRC pDrvRC; /**< Attached network driver - RC. */
1047 PTMTIMERRC pRIDTimerRC; /**< Receive Interrupt Delay Timer - RC. */
1048 PTMTIMERRC pRADTimerRC; /**< Receive Absolute Delay Timer - RC. */
1049 PTMTIMERRC pTIDTimerRC; /**< Transmit Interrupt Delay Timer - RC. */
1050 PTMTIMERRC pTADTimerRC; /**< Transmit Absolute Delay Timer - RC. */
1051 PTMTIMERRC pTXDTimerRC; /**< Transmit Delay Timer - RC. */
1052 PTMTIMERRC pIntTimerRC; /**< Late Interrupt Timer - RC. */
1053 PTMTIMERRC pLUTimerRC; /**< Link Up(/Restore) Timer - RC. */
1054 /** The scatter / gather buffer used for the current outgoing packet - RC. */
1055 RCPTRTYPE(PPDMSCATTERGATHER) pTxSgRC;
1056 RTRCPTR RCPtrAlignment;
1057
1058#if HC_ARCH_BITS != 32
1059 uint32_t Alignment1;
1060#endif
1061 PDMCRITSECT cs; /**< Critical section - what is it protecting? */
1062 PDMCRITSECT csRx; /**< RX Critical section. */
1063#ifdef E1K_WITH_TX_CS
1064 PDMCRITSECT csTx; /**< TX Critical section. */
1065#endif /* E1K_WITH_TX_CS */
1066 /** Base address of memory-mapped registers. */
1067 RTGCPHYS addrMMReg;
1068 /** MAC address obtained from the configuration. */
1069 RTMAC macConfigured;
1070 /** Base port of I/O space region. */
1071 RTIOPORT IOPortBase;
1072 /** EMT: */
1073 PCIDEVICE pciDevice;
1074 /** EMT: Last time the interrupt was acknowledged. */
1075 uint64_t u64AckedAt;
1076 /** All: Used for eliminating spurious interrupts. */
1077 bool fIntRaised;
1078 /** EMT: false if the cable is disconnected by the GUI. */
1079 bool fCableConnected;
1080 /** EMT: */
1081 bool fR0Enabled;
1082 /** EMT: */
1083 bool fRCEnabled;
1084 /** EMT: Compute Ethernet CRC for RX packets. */
1085 bool fEthernetCRC;
1086
1087 bool Alignment2[3];
1088 /** Link up delay (in milliseconds). */
1089 uint32_t cMsLinkUpDelay;
1090
1091 /** All: Device register storage. */
1092 uint32_t auRegs[E1K_NUM_OF_32BIT_REGS];
1093 /** TX/RX: Status LED. */
1094 PDMLED led;
1095 /** TX/RX: Number of packet being sent/received to show in debug log. */
1096 uint32_t u32PktNo;
1097
1098 /** EMT: Offset of the register to be read via IO. */
1099 uint32_t uSelectedReg;
1100 /** EMT: Multicast Table Array. */
1101 uint32_t auMTA[128];
1102 /** EMT: Receive Address registers. */
1103 E1KRA aRecAddr;
1104 /** EMT: VLAN filter table array. */
1105 uint32_t auVFTA[128];
1106 /** EMT: Receive buffer size. */
1107 uint16_t u16RxBSize;
1108 /** EMT: Locked state -- no state alteration possible. */
1109 bool fLocked;
1110 /** EMT: */
1111 bool fDelayInts;
1112 /** All: */
1113 bool fIntMaskUsed;
1114
1115 /** N/A: */
1116 bool volatile fMaybeOutOfSpace;
1117 /** EMT: Gets signalled when more RX descriptors become available. */
1118 RTSEMEVENT hEventMoreRxDescAvail;
1119#ifdef E1K_WITH_RXD_CACHE
1120 /** RX: Fetched RX descriptors. */
1121 E1KRXDESC aRxDescriptors[E1K_RXD_CACHE_SIZE];
1122 //uint64_t aRxDescAddr[E1K_RXD_CACHE_SIZE];
1123 /** RX: Actual number of fetched RX descriptors. */
1124 uint32_t nRxDFetched;
1125 /** RX: Index in cache of RX descriptor being processed. */
1126 uint32_t iRxDCurrent;
1127#endif /* E1K_WITH_RXD_CACHE */
1128
1129 /** TX: Context used for TCP segmentation packets. */
1130 E1KTXCTX contextTSE;
1131 /** TX: Context used for ordinary packets. */
1132 E1KTXCTX contextNormal;
1133#ifdef E1K_WITH_TXD_CACHE
1134 /** TX: Fetched TX descriptors. */
1135 E1KTXDESC aTxDescriptors[E1K_TXD_CACHE_SIZE];
1136 /** TX: Actual number of fetched TX descriptors. */
1137 uint8_t nTxDFetched;
1138 /** TX: Index in cache of TX descriptor being processed. */
1139 uint8_t iTxDCurrent;
1140 /** TX: Will this frame be sent as GSO. */
1141 bool fGSO;
1142 /** Alignment padding. */
1143 bool fReserved;
1144 /** TX: Number of bytes in next packet. */
1145 uint32_t cbTxAlloc;
1146
1147#endif /* E1K_WITH_TXD_CACHE */
1148 /** GSO context. u8Type is set to PDMNETWORKGSOTYPE_INVALID when not
1149 * applicable to the current TSE mode. */
1150 PDMNETWORKGSO GsoCtx;
1151 /** Scratch space for holding the loopback / fallback scatter / gather
1152 * descriptor. */
1153 union
1154 {
1155 PDMSCATTERGATHER Sg;
1156 uint8_t padding[8 * sizeof(RTUINTPTR)];
1157 } uTxFallback;
1158 /** TX: Transmit packet buffer use for TSE fallback and loopback. */
1159 uint8_t aTxPacketFallback[E1K_MAX_TX_PKT_SIZE];
1160 /** TX: Number of bytes assembled in TX packet buffer. */
1161 uint16_t u16TxPktLen;
1162 /** TX: False will force segmentation in e1000 instead of sending frames as GSO. */
1163 bool fGSOEnabled;
1164 /** TX: IP checksum has to be inserted if true. */
1165 bool fIPcsum;
1166 /** TX: TCP/UDP checksum has to be inserted if true. */
1167 bool fTCPcsum;
1168 /** TX: VLAN tag has to be inserted if true. */
1169 bool fVTag;
1170 /** TX: TCI part of VLAN tag to be inserted. */
1171 uint16_t u16VTagTCI;
1172 /** TX TSE fallback: Number of payload bytes remaining in TSE context. */
1173 uint32_t u32PayRemain;
1174 /** TX TSE fallback: Number of header bytes remaining in TSE context. */
1175 uint16_t u16HdrRemain;
1176 /** TX TSE fallback: Flags from template header. */
1177 uint16_t u16SavedFlags;
1178 /** TX TSE fallback: Partial checksum from template header. */
1179 uint32_t u32SavedCsum;
1180 /** ?: Emulated controller type. */
1181 E1KCHIP eChip;
1182
1183 /** EMT: EEPROM emulation */
1184 E1kEEPROM eeprom;
1185 /** EMT: Physical interface emulation. */
1186 PHY phy;
1187
1188#if 0
1189 /** Alignment padding. */
1190 uint8_t Alignment[HC_ARCH_BITS == 64 ? 8 : 4];
1191#endif
1192
1193 STAMCOUNTER StatReceiveBytes;
1194 STAMCOUNTER StatTransmitBytes;
1195#if defined(VBOX_WITH_STATISTICS)
1196 STAMPROFILEADV StatMMIOReadRZ;
1197 STAMPROFILEADV StatMMIOReadR3;
1198 STAMPROFILEADV StatMMIOWriteRZ;
1199 STAMPROFILEADV StatMMIOWriteR3;
1200 STAMPROFILEADV StatEEPROMRead;
1201 STAMPROFILEADV StatEEPROMWrite;
1202 STAMPROFILEADV StatIOReadRZ;
1203 STAMPROFILEADV StatIOReadR3;
1204 STAMPROFILEADV StatIOWriteRZ;
1205 STAMPROFILEADV StatIOWriteR3;
1206 STAMPROFILEADV StatLateIntTimer;
1207 STAMCOUNTER StatLateInts;
1208 STAMCOUNTER StatIntsRaised;
1209 STAMCOUNTER StatIntsPrevented;
1210 STAMPROFILEADV StatReceive;
1211 STAMPROFILEADV StatReceiveCRC;
1212 STAMPROFILEADV StatReceiveFilter;
1213 STAMPROFILEADV StatReceiveStore;
1214 STAMPROFILEADV StatTransmitRZ;
1215 STAMPROFILEADV StatTransmitR3;
1216 STAMPROFILE StatTransmitSendRZ;
1217 STAMPROFILE StatTransmitSendR3;
1218 STAMPROFILE StatRxOverflow;
1219 STAMCOUNTER StatRxOverflowWakeup;
1220 STAMCOUNTER StatTxDescCtxNormal;
1221 STAMCOUNTER StatTxDescCtxTSE;
1222 STAMCOUNTER StatTxDescLegacy;
1223 STAMCOUNTER StatTxDescData;
1224 STAMCOUNTER StatTxDescTSEData;
1225 STAMCOUNTER StatTxPathFallback;
1226 STAMCOUNTER StatTxPathGSO;
1227 STAMCOUNTER StatTxPathRegular;
1228 STAMCOUNTER StatPHYAccesses;
1229 STAMCOUNTER aStatRegWrites[E1K_NUM_OF_REGS];
1230 STAMCOUNTER aStatRegReads[E1K_NUM_OF_REGS];
1231#endif /* VBOX_WITH_STATISTICS */
1232
1233#ifdef E1K_INT_STATS
1234 /* Internal stats */
1235 uint64_t u64ArmedAt;
1236 uint64_t uStatMaxTxDelay;
1237 uint32_t uStatInt;
1238 uint32_t uStatIntTry;
1239 uint32_t uStatIntLower;
1240 uint32_t uStatIntDly;
1241 int32_t iStatIntLost;
1242 int32_t iStatIntLostOne;
1243 uint32_t uStatDisDly;
1244 uint32_t uStatIntSkip;
1245 uint32_t uStatIntLate;
1246 uint32_t uStatIntMasked;
1247 uint32_t uStatIntEarly;
1248 uint32_t uStatIntRx;
1249 uint32_t uStatIntTx;
1250 uint32_t uStatIntICS;
1251 uint32_t uStatIntRDTR;
1252 uint32_t uStatIntRXDMT0;
1253 uint32_t uStatIntTXQE;
1254 uint32_t uStatTxNoRS;
1255 uint32_t uStatTxIDE;
1256 uint32_t uStatTxDelayed;
1257 uint32_t uStatTxDelayExp;
1258 uint32_t uStatTAD;
1259 uint32_t uStatTID;
1260 uint32_t uStatRAD;
1261 uint32_t uStatRID;
1262 uint32_t uStatRxFrm;
1263 uint32_t uStatTxFrm;
1264 uint32_t uStatDescCtx;
1265 uint32_t uStatDescDat;
1266 uint32_t uStatDescLeg;
1267 uint32_t uStatTx1514;
1268 uint32_t uStatTx2962;
1269 uint32_t uStatTx4410;
1270 uint32_t uStatTx5858;
1271 uint32_t uStatTx7306;
1272 uint32_t uStatTx8754;
1273 uint32_t uStatTx16384;
1274 uint32_t uStatTx32768;
1275 uint32_t uStatTxLarge;
1276 uint32_t uStatAlign;
1277#endif /* E1K_INT_STATS */
1278};
1279typedef struct E1kState_st E1KSTATE;
1280/** Pointer to the E1000 device state. */
1281typedef E1KSTATE *PE1KSTATE;
1282
1283#ifndef VBOX_DEVICE_STRUCT_TESTCASE
1284
1285/* Forward declarations ******************************************************/
1286static int e1kXmitPending(PE1KSTATE pThis, bool fOnWorkerThread);
1287
1288static int e1kRegReadUnimplemented (PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t *pu32Value);
1289static int e1kRegWriteUnimplemented(PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t u32Value);
1290static int e1kRegReadAutoClear (PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t *pu32Value);
1291static int e1kRegReadDefault (PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t *pu32Value);
1292static int e1kRegWriteDefault (PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t u32Value);
1293#if 0 /* unused */
1294static int e1kRegReadCTRL (PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t *pu32Value);
1295#endif
1296static int e1kRegWriteCTRL (PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t u32Value);
1297static int e1kRegReadEECD (PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t *pu32Value);
1298static int e1kRegWriteEECD (PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t u32Value);
1299static int e1kRegWriteEERD (PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t u32Value);
1300static int e1kRegWriteMDIC (PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t u32Value);
1301static int e1kRegReadICR (PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t *pu32Value);
1302static int e1kRegWriteICR (PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t u32Value);
1303static int e1kRegWriteICS (PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t u32Value);
1304static int e1kRegWriteIMS (PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t u32Value);
1305static int e1kRegWriteIMC (PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t u32Value);
1306static int e1kRegWriteRCTL (PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t u32Value);
1307static int e1kRegWritePBA (PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t u32Value);
1308static int e1kRegWriteRDT (PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t u32Value);
1309static int e1kRegWriteRDTR (PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t u32Value);
1310static int e1kRegWriteTDT (PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t u32Value);
1311static int e1kRegReadMTA (PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t *pu32Value);
1312static int e1kRegWriteMTA (PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t u32Value);
1313static int e1kRegReadRA (PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t *pu32Value);
1314static int e1kRegWriteRA (PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t u32Value);
1315static int e1kRegReadVFTA (PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t *pu32Value);
1316static int e1kRegWriteVFTA (PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t u32Value);
1317
1318/**
1319 * Register map table.
1320 *
1321 * Override pfnRead and pfnWrite to get register-specific behavior.
1322 */
1323static const struct E1kRegMap_st
1324{
1325 /** Register offset in the register space. */
1326 uint32_t offset;
1327 /** Size in bytes. Registers of size > 4 are in fact tables. */
1328 uint32_t size;
1329 /** Readable bits. */
1330 uint32_t readable;
1331 /** Writable bits. */
1332 uint32_t writable;
1333 /** Read callback. */
1334 int (*pfnRead)(PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t *pu32Value);
1335 /** Write callback. */
1336 int (*pfnWrite)(PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t u32Value);
1337 /** Abbreviated name. */
1338 const char *abbrev;
1339 /** Full name. */
1340 const char *name;
1341} g_aE1kRegMap[E1K_NUM_OF_REGS] =
1342{
1343 /* offset size read mask write mask read callback write callback abbrev full name */
1344 /*------- ------- ---------- ---------- ----------------------- ------------------------ ---------- ------------------------------*/
1345 { 0x00000, 0x00004, 0xDBF31BE9, 0xDBF31BE9, e1kRegReadDefault , e1kRegWriteCTRL , "CTRL" , "Device Control" },
1346 { 0x00008, 0x00004, 0x0000FDFF, 0x00000000, e1kRegReadDefault , e1kRegWriteUnimplemented, "STATUS" , "Device Status" },
1347 { 0x00010, 0x00004, 0x000027F0, 0x00000070, e1kRegReadEECD , e1kRegWriteEECD , "EECD" , "EEPROM/Flash Control/Data" },
1348 { 0x00014, 0x00004, 0xFFFFFF10, 0xFFFFFF00, e1kRegReadDefault , e1kRegWriteEERD , "EERD" , "EEPROM Read" },
1349 { 0x00018, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, e1kRegReadUnimplemented, e1kRegWriteUnimplemented, "CTRL_EXT", "Extended Device Control" },
1350 { 0x0001c, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, e1kRegReadUnimplemented, e1kRegWriteUnimplemented, "FLA" , "Flash Access (N/A)" },
1351 { 0x00020, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, e1kRegReadDefault , e1kRegWriteMDIC , "MDIC" , "MDI Control" },
1352 { 0x00028, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, e1kRegReadUnimplemented, e1kRegWriteUnimplemented, "FCAL" , "Flow Control Address Low" },
1353 { 0x0002c, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, e1kRegReadUnimplemented, e1kRegWriteUnimplemented, "FCAH" , "Flow Control Address High" },
1354 { 0x00030, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, e1kRegReadUnimplemented, e1kRegWriteUnimplemented, "FCT" , "Flow Control Type" },
1355 { 0x00038, 0x00004, 0x0000FFFF, 0x0000FFFF, e1kRegReadDefault , e1kRegWriteDefault , "VET" , "VLAN EtherType" },
1356 { 0x000c0, 0x00004, 0x0001F6DF, 0x0001F6DF, e1kRegReadICR , e1kRegWriteICR , "ICR" , "Interrupt Cause Read" },
1357 { 0x000c4, 0x00004, 0x0000FFFF, 0x0000FFFF, e1kRegReadDefault , e1kRegWriteDefault , "ITR" , "Interrupt Throttling" },
1358 { 0x000c8, 0x00004, 0x00000000, 0xFFFFFFFF, e1kRegReadUnimplemented, e1kRegWriteICS , "ICS" , "Interrupt Cause Set" },
1359 { 0x000d0, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, e1kRegReadDefault , e1kRegWriteIMS , "IMS" , "Interrupt Mask Set/Read" },
1360 { 0x000d8, 0x00004, 0x00000000, 0xFFFFFFFF, e1kRegReadUnimplemented, e1kRegWriteIMC , "IMC" , "Interrupt Mask Clear" },
1361 { 0x00100, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, e1kRegReadDefault , e1kRegWriteRCTL , "RCTL" , "Receive Control" },
1362 { 0x00170, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, e1kRegReadUnimplemented, e1kRegWriteUnimplemented, "FCTTV" , "Flow Control Transmit Timer Value" },
1363 { 0x00178, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, e1kRegReadUnimplemented, e1kRegWriteUnimplemented, "TXCW" , "Transmit Configuration Word (N/A)" },
1364 { 0x00180, 0x00004, 0xFFFFFFFF, 0x00000000, e1kRegReadUnimplemented, e1kRegWriteUnimplemented, "RXCW" , "Receive Configuration Word (N/A)" },
1365 { 0x00400, 0x00004, 0x017FFFFA, 0x017FFFFA, e1kRegReadDefault , e1kRegWriteDefault , "TCTL" , "Transmit Control" },
1366 { 0x00410, 0x00004, 0x3FFFFFFF, 0x3FFFFFFF, e1kRegReadDefault , e1kRegWriteDefault , "TIPG" , "Transmit IPG" },
1367 { 0x00458, 0x00004, 0x0000FFFF, 0x0000FFFF, e1kRegReadDefault , e1kRegWriteDefault , "AIFS" , "Adaptive IFS Throttle - AIT" },
1368 { 0x00e00, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, e1kRegReadUnimplemented, e1kRegWriteUnimplemented, "LEDCTL" , "LED Control" },
1369 { 0x01000, 0x00004, 0xFFFF007F, 0x0000007F, e1kRegReadDefault , e1kRegWritePBA , "PBA" , "Packet Buffer Allocation" },
1370 { 0x02160, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, e1kRegReadUnimplemented, e1kRegWriteUnimplemented, "FCRTL" , "Flow Control Receive Threshold Low" },
1371 { 0x02168, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, e1kRegReadUnimplemented, e1kRegWriteUnimplemented, "FCRTH" , "Flow Control Receive Threshold High" },
1372 { 0x02410, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, e1kRegReadUnimplemented, e1kRegWriteUnimplemented, "RDFH" , "Receive Data FIFO Head" },
1373 { 0x02418, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, e1kRegReadUnimplemented, e1kRegWriteUnimplemented, "RDFT" , "Receive Data FIFO Tail" },
1374 { 0x02420, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, e1kRegReadUnimplemented, e1kRegWriteUnimplemented, "RDFHS" , "Receive Data FIFO Head Saved Register" },
1375 { 0x02428, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, e1kRegReadUnimplemented, e1kRegWriteUnimplemented, "RDFTS" , "Receive Data FIFO Tail Saved Register" },
1376 { 0x02430, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, e1kRegReadUnimplemented, e1kRegWriteUnimplemented, "RDFPC" , "Receive Data FIFO Packet Count" },
1377 { 0x02800, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, e1kRegReadDefault , e1kRegWriteDefault , "RDBAL" , "Receive Descriptor Base Low" },
1378 { 0x02804, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, e1kRegReadDefault , e1kRegWriteDefault , "RDBAH" , "Receive Descriptor Base High" },
1379 { 0x02808, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, e1kRegReadDefault , e1kRegWriteDefault , "RDLEN" , "Receive Descriptor Length" },
1380 { 0x02810, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, e1kRegReadDefault , e1kRegWriteDefault , "RDH" , "Receive Descriptor Head" },
1381 { 0x02818, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, e1kRegReadDefault , e1kRegWriteRDT , "RDT" , "Receive Descriptor Tail" },
1382 { 0x02820, 0x00004, 0x0000FFFF, 0x0000FFFF, e1kRegReadDefault , e1kRegWriteRDTR , "RDTR" , "Receive Delay Timer" },
1383 { 0x02828, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, e1kRegReadUnimplemented, e1kRegWriteUnimplemented, "RXDCTL" , "Receive Descriptor Control" },
1384 { 0x0282c, 0x00004, 0x0000FFFF, 0x0000FFFF, e1kRegReadDefault , e1kRegWriteDefault , "RADV" , "Receive Interrupt Absolute Delay Timer" },
1385 { 0x02c00, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, e1kRegReadUnimplemented, e1kRegWriteUnimplemented, "RSRPD" , "Receive Small Packet Detect Interrupt" },
1386 { 0x03000, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, e1kRegReadUnimplemented, e1kRegWriteUnimplemented, "TXDMAC" , "TX DMA Control (N/A)" },
1387 { 0x03410, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, e1kRegReadUnimplemented, e1kRegWriteUnimplemented, "TDFH" , "Transmit Data FIFO Head" },
1388 { 0x03418, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, e1kRegReadUnimplemented, e1kRegWriteUnimplemented, "TDFT" , "Transmit Data FIFO Tail" },
1389 { 0x03420, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, e1kRegReadUnimplemented, e1kRegWriteUnimplemented, "TDFHS" , "Transmit Data FIFO Head Saved Register" },
1390 { 0x03428, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, e1kRegReadUnimplemented, e1kRegWriteUnimplemented, "TDFTS" , "Transmit Data FIFO Tail Saved Register" },
1391 { 0x03430, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, e1kRegReadUnimplemented, e1kRegWriteUnimplemented, "TDFPC" , "Transmit Data FIFO Packet Count" },
1392 { 0x03800, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, e1kRegReadDefault , e1kRegWriteDefault , "TDBAL" , "Transmit Descriptor Base Low" },
1393 { 0x03804, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, e1kRegReadDefault , e1kRegWriteDefault , "TDBAH" , "Transmit Descriptor Base High" },
1394 { 0x03808, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, e1kRegReadDefault , e1kRegWriteDefault , "TDLEN" , "Transmit Descriptor Length" },
1395 { 0x03810, 0x00004, 0x0000FFFF, 0x0000FFFF, e1kRegReadDefault , e1kRegWriteDefault , "TDH" , "Transmit Descriptor Head" },
1396 { 0x03818, 0x00004, 0x0000FFFF, 0x0000FFFF, e1kRegReadDefault , e1kRegWriteTDT , "TDT" , "Transmit Descriptor Tail" },
1397 { 0x03820, 0x00004, 0x0000FFFF, 0x0000FFFF, e1kRegReadDefault , e1kRegWriteDefault , "TIDV" , "Transmit Interrupt Delay Value" },
1398 { 0x03828, 0x00004, 0xFF3F3F3F, 0xFF3F3F3F, e1kRegReadDefault , e1kRegWriteDefault , "TXDCTL" , "Transmit Descriptor Control" },
1399 { 0x0382c, 0x00004, 0x0000FFFF, 0x0000FFFF, e1kRegReadDefault , e1kRegWriteDefault , "TADV" , "Transmit Absolute Interrupt Delay Timer" },
1400 { 0x03830, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, e1kRegReadDefault , e1kRegWriteDefault , "TSPMT" , "TCP Segmentation Pad and Threshold" },
1401 { 0x04000, 0x00004, 0xFFFFFFFF, 0x00000000, e1kRegReadUnimplemented, e1kRegWriteUnimplemented, "CRCERRS" , "CRC Error Count" },
1402 { 0x04004, 0x00004, 0xFFFFFFFF, 0x00000000, e1kRegReadUnimplemented, e1kRegWriteUnimplemented, "ALGNERRC", "Alignment Error Count" },
1403 { 0x04008, 0x00004, 0xFFFFFFFF, 0x00000000, e1kRegReadUnimplemented, e1kRegWriteUnimplemented, "SYMERRS" , "Symbol Error Count" },
1404 { 0x0400c, 0x00004, 0xFFFFFFFF, 0x00000000, e1kRegReadUnimplemented, e1kRegWriteUnimplemented, "RXERRC" , "RX Error Count" },
1405 { 0x04010, 0x00004, 0xFFFFFFFF, 0x00000000, e1kRegReadUnimplemented, e1kRegWriteUnimplemented, "MPC" , "Missed Packets Count" },
1406 { 0x04014, 0x00004, 0xFFFFFFFF, 0x00000000, e1kRegReadUnimplemented, e1kRegWriteUnimplemented, "SCC" , "Single Collision Count" },
1407 { 0x04018, 0x00004, 0xFFFFFFFF, 0x00000000, e1kRegReadUnimplemented, e1kRegWriteUnimplemented, "ECOL" , "Excessive Collisions Count" },
1408 { 0x0401c, 0x00004, 0xFFFFFFFF, 0x00000000, e1kRegReadUnimplemented, e1kRegWriteUnimplemented, "MCC" , "Multiple Collision Count" },
1409 { 0x04020, 0x00004, 0xFFFFFFFF, 0x00000000, e1kRegReadUnimplemented, e1kRegWriteUnimplemented, "LATECOL" , "Late Collisions Count" },
1410 { 0x04028, 0x00004, 0xFFFFFFFF, 0x00000000, e1kRegReadUnimplemented, e1kRegWriteUnimplemented, "COLC" , "Collision Count" },
1411 { 0x04030, 0x00004, 0xFFFFFFFF, 0x00000000, e1kRegReadUnimplemented, e1kRegWriteUnimplemented, "DC" , "Defer Count" },
1412 { 0x04034, 0x00004, 0xFFFFFFFF, 0x00000000, e1kRegReadUnimplemented, e1kRegWriteUnimplemented, "TNCRS" , "Transmit - No CRS" },
1413 { 0x04038, 0x00004, 0xFFFFFFFF, 0x00000000, e1kRegReadUnimplemented, e1kRegWriteUnimplemented, "SEC" , "Sequence Error Count" },
1414 { 0x0403c, 0x00004, 0xFFFFFFFF, 0x00000000, e1kRegReadUnimplemented, e1kRegWriteUnimplemented, "CEXTERR" , "Carrier Extension Error Count" },
1415 { 0x04040, 0x00004, 0xFFFFFFFF, 0x00000000, e1kRegReadUnimplemented, e1kRegWriteUnimplemented, "RLEC" , "Receive Length Error Count" },
1416 { 0x04048, 0x00004, 0xFFFFFFFF, 0x00000000, e1kRegReadUnimplemented, e1kRegWriteUnimplemented, "XONRXC" , "XON Received Count" },
1417 { 0x0404c, 0x00004, 0xFFFFFFFF, 0x00000000, e1kRegReadUnimplemented, e1kRegWriteUnimplemented, "XONTXC" , "XON Transmitted Count" },
1418 { 0x04050, 0x00004, 0xFFFFFFFF, 0x00000000, e1kRegReadUnimplemented, e1kRegWriteUnimplemented, "XOFFRXC" , "XOFF Received Count" },
1419 { 0x04054, 0x00004, 0xFFFFFFFF, 0x00000000, e1kRegReadUnimplemented, e1kRegWriteUnimplemented, "XOFFTXC" , "XOFF Transmitted Count" },
1420 { 0x04058, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, e1kRegReadUnimplemented, e1kRegWriteUnimplemented, "FCRUC" , "FC Received Unsupported Count" },
1421 { 0x0405c, 0x00004, 0xFFFFFFFF, 0x00000000, e1kRegReadAutoClear , e1kRegWriteUnimplemented, "PRC64" , "Packets Received (64 Bytes) Count" },
1422 { 0x04060, 0x00004, 0xFFFFFFFF, 0x00000000, e1kRegReadAutoClear , e1kRegWriteUnimplemented, "PRC127" , "Packets Received (65-127 Bytes) Count" },
1423 { 0x04064, 0x00004, 0xFFFFFFFF, 0x00000000, e1kRegReadAutoClear , e1kRegWriteUnimplemented, "PRC255" , "Packets Received (128-255 Bytes) Count" },
1424 { 0x04068, 0x00004, 0xFFFFFFFF, 0x00000000, e1kRegReadAutoClear , e1kRegWriteUnimplemented, "PRC511" , "Packets Received (256-511 Bytes) Count" },
1425 { 0x0406c, 0x00004, 0xFFFFFFFF, 0x00000000, e1kRegReadAutoClear , e1kRegWriteUnimplemented, "PRC1023" , "Packets Received (512-1023 Bytes) Count" },
1426 { 0x04070, 0x00004, 0xFFFFFFFF, 0x00000000, e1kRegReadAutoClear , e1kRegWriteUnimplemented, "PRC1522" , "Packets Received (1024-Max Bytes)" },
1427 { 0x04074, 0x00004, 0xFFFFFFFF, 0x00000000, e1kRegReadAutoClear , e1kRegWriteUnimplemented, "GPRC" , "Good Packets Received Count" },
1428 { 0x04078, 0x00004, 0xFFFFFFFF, 0x00000000, e1kRegReadAutoClear , e1kRegWriteUnimplemented, "BPRC" , "Broadcast Packets Received Count" },
1429 { 0x0407c, 0x00004, 0xFFFFFFFF, 0x00000000, e1kRegReadAutoClear , e1kRegWriteUnimplemented, "MPRC" , "Multicast Packets Received Count" },
1430 { 0x04080, 0x00004, 0xFFFFFFFF, 0x00000000, e1kRegReadAutoClear , e1kRegWriteUnimplemented, "GPTC" , "Good Packets Transmitted Count" },
1431 { 0x04088, 0x00004, 0xFFFFFFFF, 0x00000000, e1kRegReadAutoClear , e1kRegWriteUnimplemented, "GORCL" , "Good Octets Received Count (Low)" },
1432 { 0x0408c, 0x00004, 0xFFFFFFFF, 0x00000000, e1kRegReadAutoClear , e1kRegWriteUnimplemented, "GORCH" , "Good Octets Received Count (Hi)" },
1433 { 0x04090, 0x00004, 0xFFFFFFFF, 0x00000000, e1kRegReadAutoClear , e1kRegWriteUnimplemented, "GOTCL" , "Good Octets Transmitted Count (Low)" },
1434 { 0x04094, 0x00004, 0xFFFFFFFF, 0x00000000, e1kRegReadAutoClear , e1kRegWriteUnimplemented, "GOTCH" , "Good Octets Transmitted Count (Hi)" },
1435 { 0x040a0, 0x00004, 0xFFFFFFFF, 0x00000000, e1kRegReadUnimplemented, e1kRegWriteUnimplemented, "RNBC" , "Receive No Buffers Count" },
1436 { 0x040a4, 0x00004, 0xFFFFFFFF, 0x00000000, e1kRegReadUnimplemented, e1kRegWriteUnimplemented, "RUC" , "Receive Undersize Count" },
1437 { 0x040a8, 0x00004, 0xFFFFFFFF, 0x00000000, e1kRegReadUnimplemented, e1kRegWriteUnimplemented, "RFC" , "Receive Fragment Count" },
1438 { 0x040ac, 0x00004, 0xFFFFFFFF, 0x00000000, e1kRegReadAutoClear , e1kRegWriteUnimplemented, "ROC" , "Receive Oversize Count" },
1439 { 0x040b0, 0x00004, 0xFFFFFFFF, 0x00000000, e1kRegReadUnimplemented, e1kRegWriteUnimplemented, "RJC" , "Receive Jabber Count" },
1440 { 0x040b4, 0x00004, 0xFFFFFFFF, 0x00000000, e1kRegReadUnimplemented, e1kRegWriteUnimplemented, "MGTPRC" , "Management Packets Received Count" },
1441 { 0x040b8, 0x00004, 0xFFFFFFFF, 0x00000000, e1kRegReadUnimplemented, e1kRegWriteUnimplemented, "MGTPDC" , "Management Packets Dropped Count" },
1442 { 0x040bc, 0x00004, 0xFFFFFFFF, 0x00000000, e1kRegReadUnimplemented, e1kRegWriteUnimplemented, "MGTPTC" , "Management Pkts Transmitted Count" },
1443 { 0x040c0, 0x00004, 0xFFFFFFFF, 0x00000000, e1kRegReadAutoClear , e1kRegWriteUnimplemented, "TORL" , "Total Octets Received (Lo)" },
1444 { 0x040c4, 0x00004, 0xFFFFFFFF, 0x00000000, e1kRegReadAutoClear , e1kRegWriteUnimplemented, "TORH" , "Total Octets Received (Hi)" },
1445 { 0x040c8, 0x00004, 0xFFFFFFFF, 0x00000000, e1kRegReadAutoClear , e1kRegWriteUnimplemented, "TOTL" , "Total Octets Transmitted (Lo)" },
1446 { 0x040cc, 0x00004, 0xFFFFFFFF, 0x00000000, e1kRegReadAutoClear , e1kRegWriteUnimplemented, "TOTH" , "Total Octets Transmitted (Hi)" },
1447 { 0x040d0, 0x00004, 0xFFFFFFFF, 0x00000000, e1kRegReadAutoClear , e1kRegWriteUnimplemented, "TPR" , "Total Packets Received" },
1448 { 0x040d4, 0x00004, 0xFFFFFFFF, 0x00000000, e1kRegReadAutoClear , e1kRegWriteUnimplemented, "TPT" , "Total Packets Transmitted" },
1449 { 0x040d8, 0x00004, 0xFFFFFFFF, 0x00000000, e1kRegReadAutoClear , e1kRegWriteUnimplemented, "PTC64" , "Packets Transmitted (64 Bytes) Count" },
1450 { 0x040dc, 0x00004, 0xFFFFFFFF, 0x00000000, e1kRegReadAutoClear , e1kRegWriteUnimplemented, "PTC127" , "Packets Transmitted (65-127 Bytes) Count" },
1451 { 0x040e0, 0x00004, 0xFFFFFFFF, 0x00000000, e1kRegReadAutoClear , e1kRegWriteUnimplemented, "PTC255" , "Packets Transmitted (128-255 Bytes) Count" },
1452 { 0x040e4, 0x00004, 0xFFFFFFFF, 0x00000000, e1kRegReadAutoClear , e1kRegWriteUnimplemented, "PTC511" , "Packets Transmitted (256-511 Bytes) Count" },
1453 { 0x040e8, 0x00004, 0xFFFFFFFF, 0x00000000, e1kRegReadAutoClear , e1kRegWriteUnimplemented, "PTC1023" , "Packets Transmitted (512-1023 Bytes) Count" },
1454 { 0x040ec, 0x00004, 0xFFFFFFFF, 0x00000000, e1kRegReadAutoClear , e1kRegWriteUnimplemented, "PTC1522" , "Packets Transmitted (1024 Bytes or Greater) Count" },
1455 { 0x040f0, 0x00004, 0xFFFFFFFF, 0x00000000, e1kRegReadAutoClear , e1kRegWriteUnimplemented, "MPTC" , "Multicast Packets Transmitted Count" },
1456 { 0x040f4, 0x00004, 0xFFFFFFFF, 0x00000000, e1kRegReadAutoClear , e1kRegWriteUnimplemented, "BPTC" , "Broadcast Packets Transmitted Count" },
1457 { 0x040f8, 0x00004, 0xFFFFFFFF, 0x00000000, e1kRegReadAutoClear , e1kRegWriteUnimplemented, "TSCTC" , "TCP Segmentation Context Transmitted Count" },
1458 { 0x040fc, 0x00004, 0xFFFFFFFF, 0x00000000, e1kRegReadAutoClear , e1kRegWriteUnimplemented, "TSCTFC" , "TCP Segmentation Context Tx Fail Count" },
1459 { 0x05000, 0x00004, 0x000007FF, 0x000007FF, e1kRegReadDefault , e1kRegWriteDefault , "RXCSUM" , "Receive Checksum Control" },
1460 { 0x05800, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, e1kRegReadUnimplemented, e1kRegWriteUnimplemented, "WUC" , "Wakeup Control" },
1461 { 0x05808, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, e1kRegReadUnimplemented, e1kRegWriteUnimplemented, "WUFC" , "Wakeup Filter Control" },
1462 { 0x05810, 0x00004, 0xFFFFFFFF, 0x00000000, e1kRegReadUnimplemented, e1kRegWriteUnimplemented, "WUS" , "Wakeup Status" },
1463 { 0x05820, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, e1kRegReadDefault , e1kRegWriteDefault , "MANC" , "Management Control" },
1464 { 0x05838, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, e1kRegReadUnimplemented, e1kRegWriteUnimplemented, "IPAV" , "IP Address Valid" },
1465 { 0x05900, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, e1kRegReadUnimplemented, e1kRegWriteUnimplemented, "WUPL" , "Wakeup Packet Length" },
1466 { 0x05200, 0x00200, 0xFFFFFFFF, 0xFFFFFFFF, e1kRegReadMTA , e1kRegWriteMTA , "MTA" , "Multicast Table Array (n)" },
1467 { 0x05400, 0x00080, 0xFFFFFFFF, 0xFFFFFFFF, e1kRegReadRA , e1kRegWriteRA , "RA" , "Receive Address (64-bit) (n)" },
1468 { 0x05600, 0x00200, 0xFFFFFFFF, 0xFFFFFFFF, e1kRegReadVFTA , e1kRegWriteVFTA , "VFTA" , "VLAN Filter Table Array (n)" },
1469 { 0x05840, 0x0001c, 0xFFFFFFFF, 0xFFFFFFFF, e1kRegReadUnimplemented, e1kRegWriteUnimplemented, "IP4AT" , "IPv4 Address Table" },
1470 { 0x05880, 0x00010, 0xFFFFFFFF, 0xFFFFFFFF, e1kRegReadUnimplemented, e1kRegWriteUnimplemented, "IP6AT" , "IPv6 Address Table" },
1471 { 0x05a00, 0x00080, 0xFFFFFFFF, 0xFFFFFFFF, e1kRegReadUnimplemented, e1kRegWriteUnimplemented, "WUPM" , "Wakeup Packet Memory" },
1472 { 0x05f00, 0x0001c, 0xFFFFFFFF, 0xFFFFFFFF, e1kRegReadUnimplemented, e1kRegWriteUnimplemented, "FFLT" , "Flexible Filter Length Table" },
1473 { 0x09000, 0x003fc, 0xFFFFFFFF, 0xFFFFFFFF, e1kRegReadUnimplemented, e1kRegWriteUnimplemented, "FFMT" , "Flexible Filter Mask Table" },
1474 { 0x09800, 0x003fc, 0xFFFFFFFF, 0xFFFFFFFF, e1kRegReadUnimplemented, e1kRegWriteUnimplemented, "FFVT" , "Flexible Filter Value Table" },
1475 { 0x10000, 0x10000, 0xFFFFFFFF, 0xFFFFFFFF, e1kRegReadUnimplemented, e1kRegWriteUnimplemented, "PBM" , "Packet Buffer Memory (n)" },
1476 { 0x00040, 0x00080, 0xFFFFFFFF, 0xFFFFFFFF, e1kRegReadRA , e1kRegWriteRA , "RA82542" , "Receive Address (64-bit) (n) (82542)" },
1477 { 0x00200, 0x00200, 0xFFFFFFFF, 0xFFFFFFFF, e1kRegReadMTA , e1kRegWriteMTA , "MTA82542", "Multicast Table Array (n) (82542)" },
1478 { 0x00600, 0x00200, 0xFFFFFFFF, 0xFFFFFFFF, e1kRegReadVFTA , e1kRegWriteVFTA , "VFTA82542", "VLAN Filter Table Array (n) (82542)" }
1479};
1480
1481#ifdef DEBUG
1482
1483/**
1484 * Convert U32 value to hex string. Masked bytes are replaced with dots.
1485 *
1486 * @remarks The mask has byte (not bit) granularity (e.g. 000000FF).
1487 *
1488 * @returns The buffer.
1489 *
1490 * @param u32 The word to convert into string.
1491 * @param mask Selects which bytes to convert.
1492 * @param buf Where to put the result.
1493 */
1494static char *e1kU32toHex(uint32_t u32, uint32_t mask, char *buf)
1495{
1496 for (char *ptr = buf + 7; ptr >= buf; --ptr, u32 >>=4, mask >>=4)
1497 {
1498 if (mask & 0xF)
1499 *ptr = (u32 & 0xF) + ((u32 & 0xF) > 9 ? '7' : '0');
1500 else
1501 *ptr = '.';
1502 }
1503 buf[8] = 0;
1504 return buf;
1505}
1506
1507/**
1508 * Returns timer name for debug purposes.
1509 *
1510 * @returns The timer name.
1511 *
1512 * @param pThis The device state structure.
1513 * @param pTimer The timer to get the name for.
1514 */
1515DECLINLINE(const char *) e1kGetTimerName(PE1KSTATE pThis, PTMTIMER pTimer)
1516{
1517 if (pTimer == pThis->CTX_SUFF(pTIDTimer))
1518 return "TID";
1519 if (pTimer == pThis->CTX_SUFF(pTADTimer))
1520 return "TAD";
1521 if (pTimer == pThis->CTX_SUFF(pRIDTimer))
1522 return "RID";
1523 if (pTimer == pThis->CTX_SUFF(pRADTimer))
1524 return "RAD";
1525 if (pTimer == pThis->CTX_SUFF(pIntTimer))
1526 return "Int";
1527 if (pTimer == pThis->CTX_SUFF(pTXDTimer))
1528 return "TXD";
1529 return "unknown";
1530}
1531
1532#endif /* DEBUG */
1533
1534/**
1535 * Arm a timer.
1536 *
1537 * @param pThis Pointer to the device state structure.
1538 * @param pTimer Pointer to the timer.
1539 * @param uExpireIn Expiration interval in microseconds.
1540 */
1541DECLINLINE(void) e1kArmTimer(PE1KSTATE pThis, PTMTIMER pTimer, uint32_t uExpireIn)
1542{
1543 if (pThis->fLocked)
1544 return;
1545
1546 E1kLog2(("%s Arming %s timer to fire in %d usec...\n",
1547 pThis->szPrf, e1kGetTimerName(pThis, pTimer), uExpireIn));
1548 TMTimerSetMicro(pTimer, uExpireIn);
1549}
1550
1551/**
1552 * Cancel a timer.
1553 *
1554 * @param pThis Pointer to the device state structure.
1555 * @param pTimer Pointer to the timer.
1556 */
1557DECLINLINE(void) e1kCancelTimer(PE1KSTATE pThis, PTMTIMER pTimer)
1558{
1559 E1kLog2(("%s Stopping %s timer...\n",
1560 pThis->szPrf, e1kGetTimerName(pThis, pTimer)));
1561 int rc = TMTimerStop(pTimer);
1562 if (RT_FAILURE(rc))
1563 {
1564 E1kLog2(("%s e1kCancelTimer: TMTimerStop() failed with %Rrc\n",
1565 pThis->szPrf, rc));
1566 }
1567}
1568
1569#define e1kCsEnter(ps, rc) PDMCritSectEnter(&ps->cs, rc)
1570#define e1kCsLeave(ps) PDMCritSectLeave(&ps->cs)
1571
1572#define e1kCsRxEnter(ps, rc) PDMCritSectEnter(&ps->csRx, rc)
1573#define e1kCsRxLeave(ps) PDMCritSectLeave(&ps->csRx)
1574#define e1kCsRxIsOwner(ps) PDMCritSectIsOwner(&ps->csRx)
1575
1576#ifndef E1K_WITH_TX_CS
1577# define e1kCsTxEnter(ps, rc) VINF_SUCCESS
1578# define e1kCsTxLeave(ps) do { } while (0)
1579#else /* E1K_WITH_TX_CS */
1580# define e1kCsTxEnter(ps, rc) PDMCritSectEnter(&ps->csTx, rc)
1581# define e1kCsTxLeave(ps) PDMCritSectLeave(&ps->csTx)
1582#endif /* E1K_WITH_TX_CS */
1583
1584#ifdef IN_RING3
1585
1586/**
1587 * Wakeup the RX thread.
1588 */
1589static void e1kWakeupReceive(PPDMDEVINS pDevIns)
1590{
1591 PE1KSTATE pThis = PDMINS_2_DATA(pDevIns, PE1KSTATE);
1592 if ( pThis->fMaybeOutOfSpace
1593 && pThis->hEventMoreRxDescAvail != NIL_RTSEMEVENT)
1594 {
1595 STAM_COUNTER_INC(&pThis->StatRxOverflowWakeup);
1596 E1kLog(("%s Waking up Out-of-RX-space semaphore\n", pThis->szPrf));
1597 RTSemEventSignal(pThis->hEventMoreRxDescAvail);
1598 }
1599}
1600
1601/**
1602 * Hardware reset. Revert all registers to initial values.
1603 *
1604 * @param pThis The device state structure.
1605 */
1606static void e1kHardReset(PE1KSTATE pThis)
1607{
1608 E1kLog(("%s Hard reset triggered\n", pThis->szPrf));
1609 memset(pThis->auRegs, 0, sizeof(pThis->auRegs));
1610 memset(pThis->aRecAddr.au32, 0, sizeof(pThis->aRecAddr.au32));
1611#ifdef E1K_INIT_RA0
1612 memcpy(pThis->aRecAddr.au32, pThis->macConfigured.au8,
1613 sizeof(pThis->macConfigured.au8));
1614 pThis->aRecAddr.array[0].ctl |= RA_CTL_AV;
1615#endif /* E1K_INIT_RA0 */
1616 STATUS = 0x0081; /* SPEED=10b (1000 Mb/s), FD=1b (Full Duplex) */
1617 EECD = 0x0100; /* EE_PRES=1b (EEPROM present) */
1618 CTRL = 0x0a09; /* FRCSPD=1b SPEED=10b LRST=1b FD=1b */
1619 TSPMT = 0x01000400;/* TSMT=0400h TSPBP=0100h */
1620 Assert(GET_BITS(RCTL, BSIZE) == 0);
1621 pThis->u16RxBSize = 2048;
1622
1623 /* Reset promiscuous mode */
1624 if (pThis->pDrvR3)
1625 pThis->pDrvR3->pfnSetPromiscuousMode(pThis->pDrvR3, false);
1626
1627#ifdef E1K_WITH_TXD_CACHE
1628 int rc = e1kCsTxEnter(pThis, VERR_SEM_BUSY);
1629 if (RT_LIKELY(rc == VINF_SUCCESS))
1630 {
1631 pThis->nTxDFetched = 0;
1632 pThis->iTxDCurrent = 0;
1633 pThis->fGSO = false;
1634 pThis->cbTxAlloc = 0;
1635 e1kCsTxLeave(pThis);
1636 }
1637#endif /* E1K_WITH_TXD_CACHE */
1638#ifdef E1K_WITH_RXD_CACHE
1639 if (RT_LIKELY(e1kCsRxEnter(pThis, VERR_SEM_BUSY) == VINF_SUCCESS))
1640 {
1641 pThis->iRxDCurrent = pThis->nRxDFetched = 0;
1642 e1kCsRxLeave(pThis);
1643 }
1644#endif /* E1K_WITH_RXD_CACHE */
1645}
1646
1647#endif /* IN_RING3 */
1648
1649/**
1650 * Compute Internet checksum.
1651 *
1652 * @remarks Refer to http://www.netfor2.com/checksum.html for short intro.
1653 *
1654 * @param pThis The device state structure.
1655 * @param cpPacket The packet.
1656 * @param cb The size of the packet.
1657 * @param cszText A string denoting direction of packet transfer.
1658 *
1659 * @return The 1's complement of the 1's complement sum.
1660 *
1661 * @thread E1000_TX
1662 */
1663static uint16_t e1kCSum16(const void *pvBuf, size_t cb)
1664{
1665 uint32_t csum = 0;
1666 uint16_t *pu16 = (uint16_t *)pvBuf;
1667
1668 while (cb > 1)
1669 {
1670 csum += *pu16++;
1671 cb -= 2;
1672 }
1673 if (cb)
1674 csum += *(uint8_t*)pu16;
1675 while (csum >> 16)
1676 csum = (csum >> 16) + (csum & 0xFFFF);
1677 return ~csum;
1678}
1679
1680/**
1681 * Dump a packet to debug log.
1682 *
1683 * @param pThis The device state structure.
1684 * @param cpPacket The packet.
1685 * @param cb The size of the packet.
1686 * @param cszText A string denoting direction of packet transfer.
1687 * @thread E1000_TX
1688 */
1689DECLINLINE(void) e1kPacketDump(PE1KSTATE pThis, const uint8_t *cpPacket, size_t cb, const char *cszText)
1690{
1691#ifdef DEBUG
1692 if (RT_LIKELY(e1kCsEnter(pThis, VERR_SEM_BUSY) == VINF_SUCCESS))
1693 {
1694 Log4(("%s --- %s packet #%d: %RTmac => %RTmac (%d bytes) ---\n",
1695 pThis->szPrf, cszText, ++pThis->u32PktNo, cpPacket+6, cpPacket, cb));
1696 if (ntohs(*(uint16_t*)(cpPacket+12)) == 0x86DD)
1697 {
1698 Log4(("%s --- IPv6: %RTnaipv6 => %RTnaipv6\n",
1699 pThis->szPrf, cpPacket+14+8, cpPacket+14+24));
1700 if (*(cpPacket+14+6) == 0x6)
1701 Log4(("%s --- TCP: seq=%x ack=%x\n", pThis->szPrf,
1702 ntohl(*(uint32_t*)(cpPacket+14+40+4)), ntohl(*(uint32_t*)(cpPacket+14+40+8))));
1703 }
1704 else if (ntohs(*(uint16_t*)(cpPacket+12)) == 0x800)
1705 {
1706 Log4(("%s --- IPv4: %RTnaipv4 => %RTnaipv4\n",
1707 pThis->szPrf, *(uint32_t*)(cpPacket+14+12), *(uint32_t*)(cpPacket+14+16)));
1708 if (*(cpPacket+14+6) == 0x6)
1709 Log4(("%s --- TCP: seq=%x ack=%x\n", pThis->szPrf,
1710 ntohl(*(uint32_t*)(cpPacket+14+20+4)), ntohl(*(uint32_t*)(cpPacket+14+20+8))));
1711 }
1712 E1kLog3(("%.*Rhxd\n", cb, cpPacket));
1713 e1kCsLeave(pThis);
1714 }
1715#else
1716 if (RT_LIKELY(e1kCsEnter(pThis, VERR_SEM_BUSY) == VINF_SUCCESS))
1717 {
1718 if (ntohs(*(uint16_t*)(cpPacket+12)) == 0x86DD)
1719 E1kLogRel(("E1000: %s packet #%d, %RTmac => %RTmac, %RTnaipv6 => %RTnaipv6, seq=%x ack=%x\n",
1720 cszText, ++pThis->u32PktNo, cpPacket+6, cpPacket, cpPacket+14+8, cpPacket+14+24,
1721 ntohl(*(uint32_t*)(cpPacket+14+40+4)), ntohl(*(uint32_t*)(cpPacket+14+40+8))));
1722 else
1723 E1kLogRel(("E1000: %s packet #%d, %RTmac => %RTmac, %RTnaipv4 => %RTnaipv4, seq=%x ack=%x\n",
1724 cszText, ++pThis->u32PktNo, cpPacket+6, cpPacket,
1725 *(uint32_t*)(cpPacket+14+12), *(uint32_t*)(cpPacket+14+16),
1726 ntohl(*(uint32_t*)(cpPacket+14+20+4)), ntohl(*(uint32_t*)(cpPacket+14+20+8))));
1727 e1kCsLeave(pThis);
1728 }
1729#endif
1730}
1731
1732/**
1733 * Determine the type of transmit descriptor.
1734 *
1735 * @returns Descriptor type. See E1K_DTYP_XXX defines.
1736 *
1737 * @param pDesc Pointer to descriptor union.
1738 * @thread E1000_TX
1739 */
1740DECLINLINE(int) e1kGetDescType(E1KTXDESC* pDesc)
1741{
1742 if (pDesc->legacy.cmd.fDEXT)
1743 return pDesc->context.dw2.u4DTYP;
1744 return E1K_DTYP_LEGACY;
1745}
1746
1747/**
1748 * Dump receive descriptor to debug log.
1749 *
1750 * @param pThis The device state structure.
1751 * @param pDesc Pointer to the descriptor.
1752 * @thread E1000_RX
1753 */
1754static void e1kPrintRDesc(PE1KSTATE pThis, E1KRXDESC* pDesc)
1755{
1756 E1kLog2(("%s <-- Receive Descriptor (%d bytes):\n", pThis->szPrf, pDesc->u16Length));
1757 E1kLog2((" Address=%16LX Length=%04X Csum=%04X\n",
1758 pDesc->u64BufAddr, pDesc->u16Length, pDesc->u16Checksum));
1759 E1kLog2((" STA: %s %s %s %s %s %s %s ERR: %s %s %s %s SPECIAL: %s VLAN=%03x PRI=%x\n",
1760 pDesc->status.fPIF ? "PIF" : "pif",
1761 pDesc->status.fIPCS ? "IPCS" : "ipcs",
1762 pDesc->status.fTCPCS ? "TCPCS" : "tcpcs",
1763 pDesc->status.fVP ? "VP" : "vp",
1764 pDesc->status.fIXSM ? "IXSM" : "ixsm",
1765 pDesc->status.fEOP ? "EOP" : "eop",
1766 pDesc->status.fDD ? "DD" : "dd",
1767 pDesc->status.fRXE ? "RXE" : "rxe",
1768 pDesc->status.fIPE ? "IPE" : "ipe",
1769 pDesc->status.fTCPE ? "TCPE" : "tcpe",
1770 pDesc->status.fCE ? "CE" : "ce",
1771 E1K_SPEC_CFI(pDesc->status.u16Special) ? "CFI" :"cfi",
1772 E1K_SPEC_VLAN(pDesc->status.u16Special),
1773 E1K_SPEC_PRI(pDesc->status.u16Special)));
1774}
1775
1776/**
1777 * Dump transmit descriptor to debug log.
1778 *
1779 * @param pThis The device state structure.
1780 * @param pDesc Pointer to descriptor union.
1781 * @param cszDir A string denoting direction of descriptor transfer
1782 * @thread E1000_TX
1783 */
1784static void e1kPrintTDesc(PE1KSTATE pThis, E1KTXDESC* pDesc, const char* cszDir,
1785 unsigned uLevel = RTLOGGRPFLAGS_LEVEL_2)
1786{
1787 /*
1788 * Unfortunately we cannot use our format handler here, we want R0 logging
1789 * as well.
1790 */
1791 switch (e1kGetDescType(pDesc))
1792 {
1793 case E1K_DTYP_CONTEXT:
1794 E1kLogX(uLevel, ("%s %s Context Transmit Descriptor %s\n",
1795 pThis->szPrf, cszDir, cszDir));
1796 E1kLogX(uLevel, (" IPCSS=%02X IPCSO=%02X IPCSE=%04X TUCSS=%02X TUCSO=%02X TUCSE=%04X\n",
1797 pDesc->context.ip.u8CSS, pDesc->context.ip.u8CSO, pDesc->context.ip.u16CSE,
1798 pDesc->context.tu.u8CSS, pDesc->context.tu.u8CSO, pDesc->context.tu.u16CSE));
1799 E1kLogX(uLevel, (" TUCMD:%s%s%s %s %s PAYLEN=%04x HDRLEN=%04x MSS=%04x STA: %s\n",
1800 pDesc->context.dw2.fIDE ? " IDE":"",
1801 pDesc->context.dw2.fRS ? " RS" :"",
1802 pDesc->context.dw2.fTSE ? " TSE":"",
1803 pDesc->context.dw2.fIP ? "IPv4":"IPv6",
1804 pDesc->context.dw2.fTCP ? "TCP":"UDP",
1805 pDesc->context.dw2.u20PAYLEN,
1806 pDesc->context.dw3.u8HDRLEN,
1807 pDesc->context.dw3.u16MSS,
1808 pDesc->context.dw3.fDD?"DD":""));
1809 break;
1810 case E1K_DTYP_DATA:
1811 E1kLogX(uLevel, ("%s %s Data Transmit Descriptor (%d bytes) %s\n",
1812 pThis->szPrf, cszDir, pDesc->data.cmd.u20DTALEN, cszDir));
1813 E1kLogX(uLevel, (" Address=%16LX DTALEN=%05X\n",
1814 pDesc->data.u64BufAddr,
1815 pDesc->data.cmd.u20DTALEN));
1816 E1kLogX(uLevel, (" DCMD:%s%s%s%s%s%s%s STA:%s%s%s POPTS:%s%s SPECIAL:%s VLAN=%03x PRI=%x\n",
1817 pDesc->data.cmd.fIDE ? " IDE" :"",
1818 pDesc->data.cmd.fVLE ? " VLE" :"",
1819 pDesc->data.cmd.fRPS ? " RPS" :"",
1820 pDesc->data.cmd.fRS ? " RS" :"",
1821 pDesc->data.cmd.fTSE ? " TSE" :"",
1822 pDesc->data.cmd.fIFCS? " IFCS":"",
1823 pDesc->data.cmd.fEOP ? " EOP" :"",
1824 pDesc->data.dw3.fDD ? " DD" :"",
1825 pDesc->data.dw3.fEC ? " EC" :"",
1826 pDesc->data.dw3.fLC ? " LC" :"",
1827 pDesc->data.dw3.fTXSM? " TXSM":"",
1828 pDesc->data.dw3.fIXSM? " IXSM":"",
1829 E1K_SPEC_CFI(pDesc->data.dw3.u16Special) ? "CFI" :"cfi",
1830 E1K_SPEC_VLAN(pDesc->data.dw3.u16Special),
1831 E1K_SPEC_PRI(pDesc->data.dw3.u16Special)));
1832 break;
1833 case E1K_DTYP_LEGACY:
1834 E1kLogX(uLevel, ("%s %s Legacy Transmit Descriptor (%d bytes) %s\n",
1835 pThis->szPrf, cszDir, pDesc->legacy.cmd.u16Length, cszDir));
1836 E1kLogX(uLevel, (" Address=%16LX DTALEN=%05X\n",
1837 pDesc->data.u64BufAddr,
1838 pDesc->legacy.cmd.u16Length));
1839 E1kLogX(uLevel, (" CMD:%s%s%s%s%s%s%s STA:%s%s%s CSO=%02x CSS=%02x SPECIAL:%s VLAN=%03x PRI=%x\n",
1840 pDesc->legacy.cmd.fIDE ? " IDE" :"",
1841 pDesc->legacy.cmd.fVLE ? " VLE" :"",
1842 pDesc->legacy.cmd.fRPS ? " RPS" :"",
1843 pDesc->legacy.cmd.fRS ? " RS" :"",
1844 pDesc->legacy.cmd.fIC ? " IC" :"",
1845 pDesc->legacy.cmd.fIFCS? " IFCS":"",
1846 pDesc->legacy.cmd.fEOP ? " EOP" :"",
1847 pDesc->legacy.dw3.fDD ? " DD" :"",
1848 pDesc->legacy.dw3.fEC ? " EC" :"",
1849 pDesc->legacy.dw3.fLC ? " LC" :"",
1850 pDesc->legacy.cmd.u8CSO,
1851 pDesc->legacy.dw3.u8CSS,
1852 E1K_SPEC_CFI(pDesc->legacy.dw3.u16Special) ? "CFI" :"cfi",
1853 E1K_SPEC_VLAN(pDesc->legacy.dw3.u16Special),
1854 E1K_SPEC_PRI(pDesc->legacy.dw3.u16Special)));
1855 break;
1856 default:
1857 E1kLog(("%s %s Invalid Transmit Descriptor %s\n",
1858 pThis->szPrf, cszDir, cszDir));
1859 break;
1860 }
1861}
1862
1863/**
1864 * Raise interrupt if not masked.
1865 *
1866 * @param pThis The device state structure.
1867 */
1868static int e1kRaiseInterrupt(PE1KSTATE pThis, int rcBusy, uint32_t u32IntCause = 0)
1869{
1870 int rc = e1kCsEnter(pThis, rcBusy);
1871 if (RT_UNLIKELY(rc != VINF_SUCCESS))
1872 return rc;
1873
1874 E1K_INC_ISTAT_CNT(pThis->uStatIntTry);
1875 ICR |= u32IntCause;
1876 if (ICR & IMS)
1877 {
1878#if 0
1879 if (pThis->fDelayInts)
1880 {
1881 E1K_INC_ISTAT_CNT(pThis->uStatIntDly);
1882 pThis->iStatIntLostOne = 1;
1883 E1kLog2(("%s e1kRaiseInterrupt: Delayed. ICR=%08x\n",
1884 pThis->szPrf, ICR));
1885#define E1K_LOST_IRQ_THRSLD 20
1886//#define E1K_LOST_IRQ_THRSLD 200000000
1887 if (pThis->iStatIntLost >= E1K_LOST_IRQ_THRSLD)
1888 {
1889 E1kLog2(("%s WARNING! Disabling delayed interrupt logic: delayed=%d, delivered=%d\n",
1890 pThis->szPrf, pThis->uStatIntDly, pThis->uStatIntLate));
1891 pThis->fIntMaskUsed = false;
1892 pThis->uStatDisDly++;
1893 }
1894 }
1895 else
1896#endif
1897 if (pThis->fIntRaised)
1898 {
1899 E1K_INC_ISTAT_CNT(pThis->uStatIntSkip);
1900 E1kLog2(("%s e1kRaiseInterrupt: Already raised, skipped. ICR&IMS=%08x\n",
1901 pThis->szPrf, ICR & IMS));
1902 }
1903 else
1904 {
1905#ifdef E1K_ITR_ENABLED
1906 uint64_t tstamp = TMTimerGet(pThis->CTX_SUFF(pIntTimer));
1907 /* interrupts/sec = 1 / (256 * 10E-9 * ITR) */
1908 E1kLog2(("%s e1kRaiseInterrupt: tstamp - pThis->u64AckedAt = %d, ITR * 256 = %d\n",
1909 pThis->szPrf, (uint32_t)(tstamp - pThis->u64AckedAt), ITR * 256));
1910 //if (!!ITR && pThis->fIntMaskUsed && tstamp - pThis->u64AckedAt < ITR * 256)
1911 if (!!ITR && tstamp - pThis->u64AckedAt < ITR * 256 && !(ICR & ICR_RXT0))
1912 {
1913 E1K_INC_ISTAT_CNT(pThis->uStatIntEarly);
1914 E1kLog2(("%s e1kRaiseInterrupt: Too early to raise again: %d ns < %d ns.\n",
1915 pThis->szPrf, (uint32_t)(tstamp - pThis->u64AckedAt), ITR * 256));
1916 }
1917 else
1918#endif
1919 {
1920
1921 /* Since we are delivering the interrupt now
1922 * there is no need to do it later -- stop the timer.
1923 */
1924 TMTimerStop(pThis->CTX_SUFF(pIntTimer));
1925 E1K_INC_ISTAT_CNT(pThis->uStatInt);
1926 STAM_COUNTER_INC(&pThis->StatIntsRaised);
1927 /* Got at least one unmasked interrupt cause */
1928 pThis->fIntRaised = true;
1929 /* Raise(1) INTA(0) */
1930 E1kLogRel(("E1000: irq RAISED icr&mask=0x%x, icr=0x%x\n", ICR & IMS, ICR));
1931 PDMDevHlpPCISetIrq(pThis->CTX_SUFF(pDevIns), 0, 1);
1932 E1kLog(("%s e1kRaiseInterrupt: Raised. ICR&IMS=%08x\n",
1933 pThis->szPrf, ICR & IMS));
1934 }
1935 }
1936 }
1937 else
1938 {
1939 E1K_INC_ISTAT_CNT(pThis->uStatIntMasked);
1940 E1kLog2(("%s e1kRaiseInterrupt: Not raising, ICR=%08x, IMS=%08x\n",
1941 pThis->szPrf, ICR, IMS));
1942 }
1943 e1kCsLeave(pThis);
1944 return VINF_SUCCESS;
1945}
1946
1947/**
1948 * Compute the physical address of the descriptor.
1949 *
1950 * @returns the physical address of the descriptor.
1951 *
1952 * @param baseHigh High-order 32 bits of descriptor table address.
1953 * @param baseLow Low-order 32 bits of descriptor table address.
1954 * @param idxDesc The descriptor index in the table.
1955 */
1956DECLINLINE(RTGCPHYS) e1kDescAddr(uint32_t baseHigh, uint32_t baseLow, uint32_t idxDesc)
1957{
1958 AssertCompile(sizeof(E1KRXDESC) == sizeof(E1KTXDESC));
1959 return ((uint64_t)baseHigh << 32) + baseLow + idxDesc * sizeof(E1KRXDESC);
1960}
1961
1962/**
1963 * Advance the head pointer of the receive descriptor queue.
1964 *
1965 * @remarks RDH always points to the next available RX descriptor.
1966 *
1967 * @param pThis The device state structure.
1968 */
1969DECLINLINE(void) e1kAdvanceRDH(PE1KSTATE pThis)
1970{
1971 Assert(e1kCsRxIsOwner(pThis));
1972 //e1kCsEnter(pThis, RT_SRC_POS);
1973 if (++RDH * sizeof(E1KRXDESC) >= RDLEN)
1974 RDH = 0;
1975 /*
1976 * Compute current receive queue length and fire RXDMT0 interrupt
1977 * if we are low on receive buffers
1978 */
1979 uint32_t uRQueueLen = RDH>RDT ? RDLEN/sizeof(E1KRXDESC)-RDH+RDT : RDT-RDH;
1980 /*
1981 * The minimum threshold is controlled by RDMTS bits of RCTL:
1982 * 00 = 1/2 of RDLEN
1983 * 01 = 1/4 of RDLEN
1984 * 10 = 1/8 of RDLEN
1985 * 11 = reserved
1986 */
1987 uint32_t uMinRQThreshold = RDLEN / sizeof(E1KRXDESC) / (2 << GET_BITS(RCTL, RDMTS));
1988 if (uRQueueLen <= uMinRQThreshold)
1989 {
1990 E1kLogRel(("E1000: low on RX descriptors, RDH=%x RDT=%x len=%x threshold=%x\n", RDH, RDT, uRQueueLen, uMinRQThreshold));
1991 E1kLog2(("%s Low on RX descriptors, RDH=%x RDT=%x len=%x threshold=%x, raise an interrupt\n",
1992 pThis->szPrf, RDH, RDT, uRQueueLen, uMinRQThreshold));
1993 E1K_INC_ISTAT_CNT(pThis->uStatIntRXDMT0);
1994 e1kRaiseInterrupt(pThis, VERR_SEM_BUSY, ICR_RXDMT0);
1995 }
1996 E1kLog2(("%s e1kAdvanceRDH: at exit RDH=%x RDT=%x len=%x\n",
1997 pThis->szPrf, RDH, RDT, uRQueueLen));
1998 //e1kCsLeave(pThis);
1999}
2000
2001#ifdef E1K_WITH_RXD_CACHE
2002/**
2003 * Return the number of RX descriptor that belong to the hardware.
2004 *
2005 * @returns the number of available descriptors in RX ring.
2006 * @param pThis The device state structure.
2007 * @thread ???
2008 */
2009DECLINLINE(uint32_t) e1kGetRxLen(PE1KSTATE pThis)
2010{
2011 /**
2012 * Make sure RDT won't change during computation. EMT may modify RDT at
2013 * any moment.
2014 */
2015 uint32_t rdt = RDT;
2016 return (RDH > rdt ? RDLEN/sizeof(E1KRXDESC) : 0) + rdt - RDH;
2017}
2018
2019DECLINLINE(unsigned) e1kRxDInCache(PE1KSTATE pThis)
2020{
2021 return pThis->nRxDFetched > pThis->iRxDCurrent ?
2022 pThis->nRxDFetched - pThis->iRxDCurrent : 0;
2023}
2024
2025DECLINLINE(unsigned) e1kRxDIsCacheEmpty(PE1KSTATE pThis)
2026{
2027 return pThis->iRxDCurrent >= pThis->nRxDFetched;
2028}
2029
2030/**
2031 * Load receive descriptors from guest memory. The caller needs to be in Rx
2032 * critical section.
2033 *
2034 * We need two physical reads in case the tail wrapped around the end of RX
2035 * descriptor ring.
2036 *
2037 * @returns the actual number of descriptors fetched.
2038 * @param pThis The device state structure.
2039 * @param pDesc Pointer to descriptor union.
2040 * @param addr Physical address in guest context.
2041 * @thread EMT, RX
2042 */
2043DECLINLINE(unsigned) e1kRxDPrefetch(PE1KSTATE pThis)
2044{
2045 /* We've already loaded pThis->nRxDFetched descriptors past RDH. */
2046 unsigned nDescsAvailable = e1kGetRxLen(pThis) - e1kRxDInCache(pThis);
2047 unsigned nDescsToFetch = RT_MIN(nDescsAvailable, E1K_RXD_CACHE_SIZE - pThis->nRxDFetched);
2048 unsigned nDescsTotal = RDLEN / sizeof(E1KRXDESC);
2049 Assert(nDescsTotal != 0);
2050 if (nDescsTotal == 0)
2051 return 0;
2052 unsigned nFirstNotLoaded = (RDH + e1kRxDInCache(pThis)) % nDescsTotal;
2053 unsigned nDescsInSingleRead = RT_MIN(nDescsToFetch, nDescsTotal - nFirstNotLoaded);
2054 E1kLog3(("%s e1kRxDPrefetch: nDescsAvailable=%u nDescsToFetch=%u "
2055 "nDescsTotal=%u nFirstNotLoaded=0x%x nDescsInSingleRead=%u\n",
2056 pThis->szPrf, nDescsAvailable, nDescsToFetch, nDescsTotal,
2057 nFirstNotLoaded, nDescsInSingleRead));
2058 if (nDescsToFetch == 0)
2059 return 0;
2060 E1KRXDESC* pFirstEmptyDesc = &pThis->aRxDescriptors[pThis->nRxDFetched];
2061 PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns),
2062 ((uint64_t)RDBAH << 32) + RDBAL + nFirstNotLoaded * sizeof(E1KRXDESC),
2063 pFirstEmptyDesc, nDescsInSingleRead * sizeof(E1KRXDESC));
2064 // uint64_t addrBase = ((uint64_t)RDBAH << 32) + RDBAL;
2065 // unsigned i, j;
2066 // for (i = pThis->nRxDFetched; i < pThis->nRxDFetched + nDescsInSingleRead; ++i)
2067 // {
2068 // pThis->aRxDescAddr[i] = addrBase + (nFirstNotLoaded + i - pThis->nRxDFetched) * sizeof(E1KRXDESC);
2069 // E1kLog3(("%s aRxDescAddr[%d] = %p\n", pThis->szPrf, i, pThis->aRxDescAddr[i]));
2070 // }
2071 E1kLog3(("%s Fetched %u RX descriptors at %08x%08x(0x%x), RDLEN=%08x, RDH=%08x, RDT=%08x\n",
2072 pThis->szPrf, nDescsInSingleRead,
2073 RDBAH, RDBAL + RDH * sizeof(E1KRXDESC),
2074 nFirstNotLoaded, RDLEN, RDH, RDT));
2075 if (nDescsToFetch > nDescsInSingleRead)
2076 {
2077 PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns),
2078 ((uint64_t)RDBAH << 32) + RDBAL,
2079 pFirstEmptyDesc + nDescsInSingleRead,
2080 (nDescsToFetch - nDescsInSingleRead) * sizeof(E1KRXDESC));
2081 // Assert(i == pThis->nRxDFetched + nDescsInSingleRead);
2082 // for (j = 0; i < pThis->nRxDFetched + nDescsToFetch; ++i, ++j)
2083 // {
2084 // pThis->aRxDescAddr[i] = addrBase + j * sizeof(E1KRXDESC);
2085 // E1kLog3(("%s aRxDescAddr[%d] = %p\n", pThis->szPrf, i, pThis->aRxDescAddr[i]));
2086 // }
2087 E1kLog3(("%s Fetched %u RX descriptors at %08x%08x\n",
2088 pThis->szPrf, nDescsToFetch - nDescsInSingleRead,
2089 RDBAH, RDBAL));
2090 }
2091 pThis->nRxDFetched += nDescsToFetch;
2092 return nDescsToFetch;
2093}
2094
2095/**
2096 * Obtain the next RX descriptor from RXD cache, fetching descriptors from the
2097 * RX ring if the cache is empty.
2098 *
2099 * Note that we cannot advance the cache pointer (iRxDCurrent) yet as it will
2100 * go out of sync with RDH which will cause trouble when EMT checks if the
2101 * cache is empty to do pre-fetch @bugref(6217).
2102 *
2103 * @param pThis The device state structure.
2104 * @thread RX
2105 */
2106DECLINLINE(E1KRXDESC*) e1kRxDGet(PE1KSTATE pThis)
2107{
2108 Assert(e1kCsRxIsOwner(pThis));
2109 /* Check the cache first. */
2110 if (pThis->iRxDCurrent < pThis->nRxDFetched)
2111 return &pThis->aRxDescriptors[pThis->iRxDCurrent];
2112 /* Cache is empty, reset it and check if we can fetch more. */
2113 pThis->iRxDCurrent = pThis->nRxDFetched = 0;
2114 if (e1kRxDPrefetch(pThis))
2115 return &pThis->aRxDescriptors[pThis->iRxDCurrent];
2116 /* Out of Rx descriptors. */
2117 return NULL;
2118}
2119
2120/**
2121 * Return the RX descriptor obtained with e1kRxDGet() and advance the cache
2122 * pointer. The descriptor gets written back to the RXD ring.
2123 *
2124 * @param pThis The device state structure.
2125 * @param pDesc The descriptor being "returned" to the RX ring.
2126 * @thread RX
2127 */
2128DECLINLINE(void) e1kRxDPut(PE1KSTATE pThis, E1KRXDESC* pDesc)
2129{
2130 Assert(e1kCsRxIsOwner(pThis));
2131 pThis->iRxDCurrent++;
2132 // Assert(pDesc >= pThis->aRxDescriptors);
2133 // Assert(pDesc < pThis->aRxDescriptors + E1K_RXD_CACHE_SIZE);
2134 // uint64_t addr = e1kDescAddr(RDBAH, RDBAL, RDH);
2135 // uint32_t rdh = RDH;
2136 // Assert(pThis->aRxDescAddr[pDesc - pThis->aRxDescriptors] == addr);
2137 PDMDevHlpPCIPhysWrite(pThis->CTX_SUFF(pDevIns),
2138 e1kDescAddr(RDBAH, RDBAL, RDH),
2139 pDesc, sizeof(E1KRXDESC));
2140 e1kAdvanceRDH(pThis);
2141 e1kPrintRDesc(pThis, pDesc);
2142}
2143
2144/**
2145 * Store a fragment of received packet at the specifed address.
2146 *
2147 * @param pThis The device state structure.
2148 * @param pDesc The next available RX descriptor.
2149 * @param pvBuf The fragment.
2150 * @param cb The size of the fragment.
2151 */
2152static DECLCALLBACK(void) e1kStoreRxFragment(PE1KSTATE pThis, E1KRXDESC *pDesc, const void *pvBuf, size_t cb)
2153{
2154 STAM_PROFILE_ADV_START(&pThis->StatReceiveStore, a);
2155 E1kLog2(("%s e1kStoreRxFragment: store fragment of %04X at %016LX, EOP=%d\n",
2156 pThis->szPrf, cb, pDesc->u64BufAddr, pDesc->status.fEOP));
2157 PDMDevHlpPCIPhysWrite(pThis->CTX_SUFF(pDevIns), pDesc->u64BufAddr, pvBuf, cb);
2158 pDesc->u16Length = (uint16_t)cb; Assert(pDesc->u16Length == cb);
2159 STAM_PROFILE_ADV_STOP(&pThis->StatReceiveStore, a);
2160}
2161
2162#else /* !E1K_WITH_RXD_CACHE */
2163
2164/**
2165 * Store a fragment of received packet that fits into the next available RX
2166 * buffer.
2167 *
2168 * @remarks Trigger the RXT0 interrupt if it is the last fragment of the packet.
2169 *
2170 * @param pThis The device state structure.
2171 * @param pDesc The next available RX descriptor.
2172 * @param pvBuf The fragment.
2173 * @param cb The size of the fragment.
2174 */
2175static DECLCALLBACK(void) e1kStoreRxFragment(PE1KSTATE pThis, E1KRXDESC *pDesc, const void *pvBuf, size_t cb)
2176{
2177 STAM_PROFILE_ADV_START(&pThis->StatReceiveStore, a);
2178 E1kLog2(("%s e1kStoreRxFragment: store fragment of %04X at %016LX, EOP=%d\n", pThis->szPrf, cb, pDesc->u64BufAddr, pDesc->status.fEOP));
2179 PDMDevHlpPCIPhysWrite(pThis->CTX_SUFF(pDevIns), pDesc->u64BufAddr, pvBuf, cb);
2180 pDesc->u16Length = (uint16_t)cb; Assert(pDesc->u16Length == cb);
2181 /* Write back the descriptor */
2182 PDMDevHlpPCIPhysWrite(pThis->CTX_SUFF(pDevIns), e1kDescAddr(RDBAH, RDBAL, RDH), pDesc, sizeof(E1KRXDESC));
2183 e1kPrintRDesc(pThis, pDesc);
2184 E1kLogRel(("E1000: Wrote back RX desc, RDH=%x\n", RDH));
2185 /* Advance head */
2186 e1kAdvanceRDH(pThis);
2187 //E1kLog2(("%s e1kStoreRxFragment: EOP=%d RDTR=%08X RADV=%08X\n", pThis->szPrf, pDesc->fEOP, RDTR, RADV));
2188 if (pDesc->status.fEOP)
2189 {
2190 /* Complete packet has been stored -- it is time to let the guest know. */
2191#ifdef E1K_USE_RX_TIMERS
2192 if (RDTR)
2193 {
2194 /* Arm the timer to fire in RDTR usec (discard .024) */
2195 e1kArmTimer(pThis, pThis->CTX_SUFF(pRIDTimer), RDTR);
2196 /* If absolute timer delay is enabled and the timer is not running yet, arm it. */
2197 if (RADV != 0 && !TMTimerIsActive(pThis->CTX_SUFF(pRADTimer)))
2198 e1kArmTimer(pThis, pThis->CTX_SUFF(pRADTimer), RADV);
2199 }
2200 else
2201 {
2202#endif
2203 /* 0 delay means immediate interrupt */
2204 E1K_INC_ISTAT_CNT(pThis->uStatIntRx);
2205 e1kRaiseInterrupt(pThis, VERR_SEM_BUSY, ICR_RXT0);
2206#ifdef E1K_USE_RX_TIMERS
2207 }
2208#endif
2209 }
2210 STAM_PROFILE_ADV_STOP(&pThis->StatReceiveStore, a);
2211}
2212#endif /* !E1K_WITH_RXD_CACHE */
2213
2214/**
2215 * Returns true if it is a broadcast packet.
2216 *
2217 * @returns true if destination address indicates broadcast.
2218 * @param pvBuf The ethernet packet.
2219 */
2220DECLINLINE(bool) e1kIsBroadcast(const void *pvBuf)
2221{
2222 static const uint8_t s_abBcastAddr[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
2223 return memcmp(pvBuf, s_abBcastAddr, sizeof(s_abBcastAddr)) == 0;
2224}
2225
2226/**
2227 * Returns true if it is a multicast packet.
2228 *
2229 * @remarks returns true for broadcast packets as well.
2230 * @returns true if destination address indicates multicast.
2231 * @param pvBuf The ethernet packet.
2232 */
2233DECLINLINE(bool) e1kIsMulticast(const void *pvBuf)
2234{
2235 return (*(char*)pvBuf) & 1;
2236}
2237
2238/**
2239 * Set IXSM, IPCS and TCPCS flags according to the packet type.
2240 *
2241 * @remarks We emulate checksum offloading for major packets types only.
2242 *
2243 * @returns VBox status code.
2244 * @param pThis The device state structure.
2245 * @param pFrame The available data.
2246 * @param cb Number of bytes available in the buffer.
2247 * @param status Bit fields containing status info.
2248 */
2249static int e1kRxChecksumOffload(PE1KSTATE pThis, const uint8_t *pFrame, size_t cb, E1KRXDST *pStatus)
2250{
2251 /** @todo
2252 * It is not safe to bypass checksum verification for packets coming
2253 * from real wire. We currently unable to tell where packets are
2254 * coming from so we tell the driver to ignore our checksum flags
2255 * and do verification in software.
2256 */
2257#if 0
2258 uint16_t uEtherType = ntohs(*(uint16_t*)(pFrame + 12));
2259
2260 E1kLog2(("%s e1kRxChecksumOffload: EtherType=%x\n", pThis->szPrf, uEtherType));
2261
2262 switch (uEtherType)
2263 {
2264 case 0x800: /* IPv4 */
2265 {
2266 pStatus->fIXSM = false;
2267 pStatus->fIPCS = true;
2268 PRTNETIPV4 pIpHdr4 = (PRTNETIPV4)(pFrame + 14);
2269 /* TCP/UDP checksum offloading works with TCP and UDP only */
2270 pStatus->fTCPCS = pIpHdr4->ip_p == 6 || pIpHdr4->ip_p == 17;
2271 break;
2272 }
2273 case 0x86DD: /* IPv6 */
2274 pStatus->fIXSM = false;
2275 pStatus->fIPCS = false;
2276 pStatus->fTCPCS = true;
2277 break;
2278 default: /* ARP, VLAN, etc. */
2279 pStatus->fIXSM = true;
2280 break;
2281 }
2282#else
2283 pStatus->fIXSM = true;
2284#endif
2285 return VINF_SUCCESS;
2286}
2287
2288/**
2289 * Pad and store received packet.
2290 *
2291 * @remarks Make sure that the packet appears to upper layer as one coming
2292 * from real Ethernet: pad it and insert FCS.
2293 *
2294 * @returns VBox status code.
2295 * @param pThis The device state structure.
2296 * @param pvBuf The available data.
2297 * @param cb Number of bytes available in the buffer.
2298 * @param status Bit fields containing status info.
2299 */
2300static int e1kHandleRxPacket(PE1KSTATE pThis, const void *pvBuf, size_t cb, E1KRXDST status)
2301{
2302#if defined(IN_RING3) /** @todo Remove this extra copying, it's gonna make us run out of kernel / hypervisor stack! */
2303 uint8_t rxPacket[E1K_MAX_RX_PKT_SIZE];
2304 uint8_t *ptr = rxPacket;
2305
2306 int rc = e1kCsRxEnter(pThis, VERR_SEM_BUSY);
2307 if (RT_UNLIKELY(rc != VINF_SUCCESS))
2308 return rc;
2309
2310 if (cb > 70) /* unqualified guess */
2311 pThis->led.Asserted.s.fReading = pThis->led.Actual.s.fReading = 1;
2312
2313 Assert(cb <= E1K_MAX_RX_PKT_SIZE);
2314 Assert(cb > 16);
2315 size_t cbMax = ((RCTL & RCTL_LPE) ? E1K_MAX_RX_PKT_SIZE - 4 : 1518) - (status.fVP ? 0 : 4);
2316 E1kLog3(("%s Max RX packet size is %u\n", pThis->szPrf, cbMax));
2317 if (status.fVP)
2318 {
2319 /* VLAN packet -- strip VLAN tag in VLAN mode */
2320 if ((CTRL & CTRL_VME) && cb > 16)
2321 {
2322 uint16_t *u16Ptr = (uint16_t*)pvBuf;
2323 memcpy(rxPacket, pvBuf, 12); /* Copy src and dst addresses */
2324 status.u16Special = RT_BE2H_U16(u16Ptr[7]); /* Extract VLAN tag */
2325 memcpy(rxPacket + 12, (uint8_t*)pvBuf + 16, cb - 16); /* Copy the rest of the packet */
2326 cb -= 4;
2327 E1kLog3(("%s Stripped tag for VLAN %u (cb=%u)\n",
2328 pThis->szPrf, status.u16Special, cb));
2329 }
2330 else
2331 status.fVP = false; /* Set VP only if we stripped the tag */
2332 }
2333 else
2334 memcpy(rxPacket, pvBuf, cb);
2335 /* Pad short packets */
2336 if (cb < 60)
2337 {
2338 memset(rxPacket + cb, 0, 60 - cb);
2339 cb = 60;
2340 }
2341 if (!(RCTL & RCTL_SECRC) && cb <= cbMax)
2342 {
2343 STAM_PROFILE_ADV_START(&pThis->StatReceiveCRC, a);
2344 /*
2345 * Add FCS if CRC stripping is not enabled. Since the value of CRC
2346 * is ignored by most of drivers we may as well save us the trouble
2347 * of calculating it (see EthernetCRC CFGM parameter).
2348 */
2349 if (pThis->fEthernetCRC)
2350 *(uint32_t*)(rxPacket + cb) = RTCrc32(rxPacket, cb);
2351 cb += sizeof(uint32_t);
2352 STAM_PROFILE_ADV_STOP(&pThis->StatReceiveCRC, a);
2353 E1kLog3(("%s Added FCS (cb=%u)\n", pThis->szPrf, cb));
2354 }
2355 /* Compute checksum of complete packet */
2356 uint16_t checksum = e1kCSum16(rxPacket + GET_BITS(RXCSUM, PCSS), cb);
2357 e1kRxChecksumOffload(pThis, rxPacket, cb, &status);
2358
2359 /* Update stats */
2360 E1K_INC_CNT32(GPRC);
2361 if (e1kIsBroadcast(pvBuf))
2362 E1K_INC_CNT32(BPRC);
2363 else if (e1kIsMulticast(pvBuf))
2364 E1K_INC_CNT32(MPRC);
2365 /* Update octet receive counter */
2366 E1K_ADD_CNT64(GORCL, GORCH, cb);
2367 STAM_REL_COUNTER_ADD(&pThis->StatReceiveBytes, cb);
2368 if (cb == 64)
2369 E1K_INC_CNT32(PRC64);
2370 else if (cb < 128)
2371 E1K_INC_CNT32(PRC127);
2372 else if (cb < 256)
2373 E1K_INC_CNT32(PRC255);
2374 else if (cb < 512)
2375 E1K_INC_CNT32(PRC511);
2376 else if (cb < 1024)
2377 E1K_INC_CNT32(PRC1023);
2378 else
2379 E1K_INC_CNT32(PRC1522);
2380
2381 E1K_INC_ISTAT_CNT(pThis->uStatRxFrm);
2382
2383#ifdef E1K_WITH_RXD_CACHE
2384 while (cb > 0)
2385 {
2386 E1KRXDESC *pDesc = e1kRxDGet(pThis);
2387
2388 if (pDesc == NULL)
2389 {
2390 E1kLog(("%s Out of receive buffers, dropping the packet "
2391 "(cb=%u, in_cache=%u, RDH=%x RDT=%x)\n",
2392 pThis->szPrf, cb, e1kRxDInCache(pThis), RDH, RDT));
2393 break;
2394 }
2395#else /* !E1K_WITH_RXD_CACHE */
2396 if (RDH == RDT)
2397 {
2398 E1kLog(("%s Out of receive buffers, dropping the packet\n",
2399 pThis->szPrf));
2400 }
2401 /* Store the packet to receive buffers */
2402 while (RDH != RDT)
2403 {
2404 /* Load the descriptor pointed by head */
2405 E1KRXDESC desc, *pDesc = &desc;
2406 PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns), e1kDescAddr(RDBAH, RDBAL, RDH),
2407 &desc, sizeof(desc));
2408#endif /* !E1K_WITH_RXD_CACHE */
2409 if (pDesc->u64BufAddr)
2410 {
2411 /* Update descriptor */
2412 pDesc->status = status;
2413 pDesc->u16Checksum = checksum;
2414 pDesc->status.fDD = true;
2415
2416 /*
2417 * We need to leave Rx critical section here or we risk deadlocking
2418 * with EMT in e1kRegWriteRDT when the write is to an unallocated
2419 * page or has an access handler associated with it.
2420 * Note that it is safe to leave the critical section here since
2421 * e1kRegWriteRDT() never modifies RDH. It never touches already
2422 * fetched RxD cache entries either.
2423 */
2424 if (cb > pThis->u16RxBSize)
2425 {
2426 pDesc->status.fEOP = false;
2427 e1kCsRxLeave(pThis);
2428 e1kStoreRxFragment(pThis, pDesc, ptr, pThis->u16RxBSize);
2429 rc = e1kCsRxEnter(pThis, VERR_SEM_BUSY);
2430 if (RT_UNLIKELY(rc != VINF_SUCCESS))
2431 return rc;
2432 ptr += pThis->u16RxBSize;
2433 cb -= pThis->u16RxBSize;
2434 }
2435 else
2436 {
2437 pDesc->status.fEOP = true;
2438 e1kCsRxLeave(pThis);
2439 e1kStoreRxFragment(pThis, pDesc, ptr, cb);
2440#ifdef E1K_WITH_RXD_CACHE
2441 rc = e1kCsRxEnter(pThis, VERR_SEM_BUSY);
2442 if (RT_UNLIKELY(rc != VINF_SUCCESS))
2443 return rc;
2444 cb = 0;
2445#else /* !E1K_WITH_RXD_CACHE */
2446 pThis->led.Actual.s.fReading = 0;
2447 return VINF_SUCCESS;
2448#endif /* !E1K_WITH_RXD_CACHE */
2449 }
2450 /*
2451 * Note: RDH is advanced by e1kStoreRxFragment if E1K_WITH_RXD_CACHE
2452 * is not defined.
2453 */
2454 }
2455#ifdef E1K_WITH_RXD_CACHE
2456 /* Write back the descriptor. */
2457 pDesc->status.fDD = true;
2458 e1kRxDPut(pThis, pDesc);
2459#else /* !E1K_WITH_RXD_CACHE */
2460 else
2461 {
2462 /* Write back the descriptor. */
2463 pDesc->status.fDD = true;
2464 PDMDevHlpPCIPhysWrite(pThis->CTX_SUFF(pDevIns),
2465 e1kDescAddr(RDBAH, RDBAL, RDH),
2466 pDesc, sizeof(E1KRXDESC));
2467 e1kAdvanceRDH(pThis);
2468 }
2469#endif /* !E1K_WITH_RXD_CACHE */
2470 }
2471
2472 if (cb > 0)
2473 E1kLog(("%s Out of receive buffers, dropping %u bytes", pThis->szPrf, cb));
2474
2475 pThis->led.Actual.s.fReading = 0;
2476
2477 e1kCsRxLeave(pThis);
2478#ifdef E1K_WITH_RXD_CACHE
2479 /* Complete packet has been stored -- it is time to let the guest know. */
2480# ifdef E1K_USE_RX_TIMERS
2481 if (RDTR)
2482 {
2483 /* Arm the timer to fire in RDTR usec (discard .024) */
2484 e1kArmTimer(pThis, pThis->CTX_SUFF(pRIDTimer), RDTR);
2485 /* If absolute timer delay is enabled and the timer is not running yet, arm it. */
2486 if (RADV != 0 && !TMTimerIsActive(pThis->CTX_SUFF(pRADTimer)))
2487 e1kArmTimer(pThis, pThis->CTX_SUFF(pRADTimer), RADV);
2488 }
2489 else
2490 {
2491# endif /* E1K_USE_RX_TIMERS */
2492 /* 0 delay means immediate interrupt */
2493 E1K_INC_ISTAT_CNT(pThis->uStatIntRx);
2494 e1kRaiseInterrupt(pThis, VERR_SEM_BUSY, ICR_RXT0);
2495# ifdef E1K_USE_RX_TIMERS
2496 }
2497# endif /* E1K_USE_RX_TIMERS */
2498#endif /* E1K_WITH_RXD_CACHE */
2499
2500 return VINF_SUCCESS;
2501#else
2502 return VERR_INTERNAL_ERROR_2;
2503#endif
2504}
2505
2506
2507/**
2508 * Bring the link up after the configured delay, 5 seconds by default.
2509 *
2510 * @param pThis The device state structure.
2511 * @thread any
2512 */
2513DECLINLINE(void) e1kBringLinkUpDelayed(PE1KSTATE pThis)
2514{
2515 E1kLog(("%s Will bring up the link in %d seconds...\n",
2516 pThis->szPrf, pThis->cMsLinkUpDelay / 1000));
2517 e1kArmTimer(pThis, pThis->CTX_SUFF(pLUTimer), pThis->cMsLinkUpDelay * 1000);
2518}
2519
2520#if 0 /* unused */
2521/**
2522 * Read handler for Device Status register.
2523 *
2524 * Get the link status from PHY.
2525 *
2526 * @returns VBox status code.
2527 *
2528 * @param pThis The device state structure.
2529 * @param offset Register offset in memory-mapped frame.
2530 * @param index Register index in register array.
2531 * @param mask Used to implement partial reads (8 and 16-bit).
2532 */
2533static int e1kRegReadCTRL(PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t *pu32Value)
2534{
2535 E1kLog(("%s e1kRegReadCTRL: mdio dir=%s mdc dir=%s mdc=%d\n",
2536 pThis->szPrf, (CTRL & CTRL_MDIO_DIR)?"OUT":"IN ",
2537 (CTRL & CTRL_MDC_DIR)?"OUT":"IN ", !!(CTRL & CTRL_MDC)));
2538 if ((CTRL & CTRL_MDIO_DIR) == 0 && (CTRL & CTRL_MDC))
2539 {
2540 /* MDC is high and MDIO pin is used for input, read MDIO pin from PHY */
2541 if (Phy::readMDIO(&pThis->phy))
2542 *pu32Value = CTRL | CTRL_MDIO;
2543 else
2544 *pu32Value = CTRL & ~CTRL_MDIO;
2545 E1kLog(("%s e1kRegReadCTRL: Phy::readMDIO(%d)\n",
2546 pThis->szPrf, !!(*pu32Value & CTRL_MDIO)));
2547 }
2548 else
2549 {
2550 /* MDIO pin is used for output, ignore it */
2551 *pu32Value = CTRL;
2552 }
2553 return VINF_SUCCESS;
2554}
2555#endif /* unused */
2556
2557/**
2558 * Write handler for Device Control register.
2559 *
2560 * Handles reset.
2561 *
2562 * @param pThis The device state structure.
2563 * @param offset Register offset in memory-mapped frame.
2564 * @param index Register index in register array.
2565 * @param value The value to store.
2566 * @param mask Used to implement partial writes (8 and 16-bit).
2567 * @thread EMT
2568 */
2569static int e1kRegWriteCTRL(PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t value)
2570{
2571 int rc = VINF_SUCCESS;
2572
2573 if (value & CTRL_RESET)
2574 { /* RST */
2575#ifndef IN_RING3
2576 return VINF_IOM_R3_IOPORT_WRITE;
2577#else
2578 e1kHardReset(pThis);
2579#endif
2580 }
2581 else
2582 {
2583 if ( (value & CTRL_SLU)
2584 && pThis->fCableConnected
2585 && !(STATUS & STATUS_LU))
2586 {
2587 /* The driver indicates that we should bring up the link */
2588 /* Do so in 5 seconds (by default). */
2589 e1kBringLinkUpDelayed(pThis);
2590 /*
2591 * Change the status (but not PHY status) anyway as Windows expects
2592 * it for 82543GC.
2593 */
2594 STATUS |= STATUS_LU;
2595 }
2596 if (value & CTRL_VME)
2597 {
2598 E1kLog(("%s VLAN Mode Enabled\n", pThis->szPrf));
2599 }
2600 E1kLog(("%s e1kRegWriteCTRL: mdio dir=%s mdc dir=%s mdc=%s mdio=%d\n",
2601 pThis->szPrf, (value & CTRL_MDIO_DIR)?"OUT":"IN ",
2602 (value & CTRL_MDC_DIR)?"OUT":"IN ", (value & CTRL_MDC)?"HIGH":"LOW ", !!(value & CTRL_MDIO)));
2603 if (value & CTRL_MDC)
2604 {
2605 if (value & CTRL_MDIO_DIR)
2606 {
2607 E1kLog(("%s e1kRegWriteCTRL: Phy::writeMDIO(%d)\n", pThis->szPrf, !!(value & CTRL_MDIO)));
2608 /* MDIO direction pin is set to output and MDC is high, write MDIO pin value to PHY */
2609 Phy::writeMDIO(&pThis->phy, !!(value & CTRL_MDIO));
2610 }
2611 else
2612 {
2613 if (Phy::readMDIO(&pThis->phy))
2614 value |= CTRL_MDIO;
2615 else
2616 value &= ~CTRL_MDIO;
2617 E1kLog(("%s e1kRegWriteCTRL: Phy::readMDIO(%d)\n",
2618 pThis->szPrf, !!(value & CTRL_MDIO)));
2619 }
2620 }
2621 rc = e1kRegWriteDefault(pThis, offset, index, value);
2622 }
2623
2624 return rc;
2625}
2626
2627/**
2628 * Write handler for EEPROM/Flash Control/Data register.
2629 *
2630 * Handles EEPROM access requests; forwards writes to EEPROM device if access has been granted.
2631 *
2632 * @param pThis The device state structure.
2633 * @param offset Register offset in memory-mapped frame.
2634 * @param index Register index in register array.
2635 * @param value The value to store.
2636 * @param mask Used to implement partial writes (8 and 16-bit).
2637 * @thread EMT
2638 */
2639static int e1kRegWriteEECD(PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t value)
2640{
2641#ifdef IN_RING3
2642 /* So far we are concerned with lower byte only */
2643 if ((EECD & EECD_EE_GNT) || pThis->eChip == E1K_CHIP_82543GC)
2644 {
2645 /* Access to EEPROM granted -- forward 4-wire bits to EEPROM device */
2646 /* Note: 82543GC does not need to request EEPROM access */
2647 STAM_PROFILE_ADV_START(&pThis->StatEEPROMWrite, a);
2648 pThis->eeprom.write(value & EECD_EE_WIRES);
2649 STAM_PROFILE_ADV_STOP(&pThis->StatEEPROMWrite, a);
2650 }
2651 if (value & EECD_EE_REQ)
2652 EECD |= EECD_EE_REQ|EECD_EE_GNT;
2653 else
2654 EECD &= ~EECD_EE_GNT;
2655 //e1kRegWriteDefault(pThis, offset, index, value );
2656
2657 return VINF_SUCCESS;
2658#else /* !IN_RING3 */
2659 return VINF_IOM_R3_MMIO_WRITE;
2660#endif /* !IN_RING3 */
2661}
2662
2663/**
2664 * Read handler for EEPROM/Flash Control/Data register.
2665 *
2666 * Lower 4 bits come from EEPROM device if EEPROM access has been granted.
2667 *
2668 * @returns VBox status code.
2669 *
2670 * @param pThis The device state structure.
2671 * @param offset Register offset in memory-mapped frame.
2672 * @param index Register index in register array.
2673 * @param mask Used to implement partial reads (8 and 16-bit).
2674 * @thread EMT
2675 */
2676static int e1kRegReadEECD(PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t *pu32Value)
2677{
2678#ifdef IN_RING3
2679 uint32_t value;
2680 int rc = e1kRegReadDefault(pThis, offset, index, &value);
2681 if (RT_SUCCESS(rc))
2682 {
2683 if ((value & EECD_EE_GNT) || pThis->eChip == E1K_CHIP_82543GC)
2684 {
2685 /* Note: 82543GC does not need to request EEPROM access */
2686 /* Access to EEPROM granted -- get 4-wire bits to EEPROM device */
2687 STAM_PROFILE_ADV_START(&pThis->StatEEPROMRead, a);
2688 value |= pThis->eeprom.read();
2689 STAM_PROFILE_ADV_STOP(&pThis->StatEEPROMRead, a);
2690 }
2691 *pu32Value = value;
2692 }
2693
2694 return rc;
2695#else /* !IN_RING3 */
2696 return VINF_IOM_R3_MMIO_READ;
2697#endif /* !IN_RING3 */
2698}
2699
2700/**
2701 * Write handler for EEPROM Read register.
2702 *
2703 * Handles EEPROM word access requests, reads EEPROM and stores the result
2704 * into DATA field.
2705 *
2706 * @param pThis The device state structure.
2707 * @param offset Register offset in memory-mapped frame.
2708 * @param index Register index in register array.
2709 * @param value The value to store.
2710 * @param mask Used to implement partial writes (8 and 16-bit).
2711 * @thread EMT
2712 */
2713static int e1kRegWriteEERD(PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t value)
2714{
2715#ifdef IN_RING3
2716 /* Make use of 'writable' and 'readable' masks. */
2717 e1kRegWriteDefault(pThis, offset, index, value);
2718 /* DONE and DATA are set only if read was triggered by START. */
2719 if (value & EERD_START)
2720 {
2721 uint16_t tmp;
2722 STAM_PROFILE_ADV_START(&pThis->StatEEPROMRead, a);
2723 if (pThis->eeprom.readWord(GET_BITS_V(value, EERD, ADDR), &tmp))
2724 SET_BITS(EERD, DATA, tmp);
2725 EERD |= EERD_DONE;
2726 STAM_PROFILE_ADV_STOP(&pThis->StatEEPROMRead, a);
2727 }
2728
2729 return VINF_SUCCESS;
2730#else /* !IN_RING3 */
2731 return VINF_IOM_R3_MMIO_WRITE;
2732#endif /* !IN_RING3 */
2733}
2734
2735
2736/**
2737 * Write handler for MDI Control register.
2738 *
2739 * Handles PHY read/write requests; forwards requests to internal PHY device.
2740 *
2741 * @param pThis The device state structure.
2742 * @param offset Register offset in memory-mapped frame.
2743 * @param index Register index in register array.
2744 * @param value The value to store.
2745 * @param mask Used to implement partial writes (8 and 16-bit).
2746 * @thread EMT
2747 */
2748static int e1kRegWriteMDIC(PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t value)
2749{
2750 if (value & MDIC_INT_EN)
2751 {
2752 E1kLog(("%s ERROR! Interrupt at the end of an MDI cycle is not supported yet.\n",
2753 pThis->szPrf));
2754 }
2755 else if (value & MDIC_READY)
2756 {
2757 E1kLog(("%s ERROR! Ready bit is not reset by software during write operation.\n",
2758 pThis->szPrf));
2759 }
2760 else if (GET_BITS_V(value, MDIC, PHY) != 1)
2761 {
2762 E1kLog(("%s ERROR! Access to invalid PHY detected, phy=%d.\n",
2763 pThis->szPrf, GET_BITS_V(value, MDIC, PHY)));
2764 }
2765 else
2766 {
2767 /* Store the value */
2768 e1kRegWriteDefault(pThis, offset, index, value);
2769 STAM_COUNTER_INC(&pThis->StatPHYAccesses);
2770 /* Forward op to PHY */
2771 if (value & MDIC_OP_READ)
2772 SET_BITS(MDIC, DATA, Phy::readRegister(&pThis->phy, GET_BITS_V(value, MDIC, REG)));
2773 else
2774 Phy::writeRegister(&pThis->phy, GET_BITS_V(value, MDIC, REG), value & MDIC_DATA_MASK);
2775 /* Let software know that we are done */
2776 MDIC |= MDIC_READY;
2777 }
2778
2779 return VINF_SUCCESS;
2780}
2781
2782/**
2783 * Write handler for Interrupt Cause Read register.
2784 *
2785 * Bits corresponding to 1s in 'value' will be cleared in ICR register.
2786 *
2787 * @param pThis The device state structure.
2788 * @param offset Register offset in memory-mapped frame.
2789 * @param index Register index in register array.
2790 * @param value The value to store.
2791 * @param mask Used to implement partial writes (8 and 16-bit).
2792 * @thread EMT
2793 */
2794static int e1kRegWriteICR(PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t value)
2795{
2796 ICR &= ~value;
2797
2798 return VINF_SUCCESS;
2799}
2800
2801/**
2802 * Read handler for Interrupt Cause Read register.
2803 *
2804 * Reading this register acknowledges all interrupts.
2805 *
2806 * @returns VBox status code.
2807 *
2808 * @param pThis The device state structure.
2809 * @param offset Register offset in memory-mapped frame.
2810 * @param index Register index in register array.
2811 * @param mask Not used.
2812 * @thread EMT
2813 */
2814static int e1kRegReadICR(PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t *pu32Value)
2815{
2816 int rc = e1kCsEnter(pThis, VINF_IOM_R3_MMIO_READ);
2817 if (RT_UNLIKELY(rc != VINF_SUCCESS))
2818 return rc;
2819
2820 uint32_t value = 0;
2821 rc = e1kRegReadDefault(pThis, offset, index, &value);
2822 if (RT_SUCCESS(rc))
2823 {
2824 if (value)
2825 {
2826 /*
2827 * Not clearing ICR causes QNX to hang as it reads ICR in a loop
2828 * with disabled interrupts.
2829 */
2830 //if (IMS)
2831 if (1)
2832 {
2833 /*
2834 * Interrupts were enabled -- we are supposedly at the very
2835 * beginning of interrupt handler
2836 */
2837 E1kLogRel(("E1000: irq lowered, icr=0x%x\n", ICR));
2838 E1kLog(("%s e1kRegReadICR: Lowered IRQ (%08x)\n", pThis->szPrf, ICR));
2839 /* Clear all pending interrupts */
2840 ICR = 0;
2841 pThis->fIntRaised = false;
2842 /* Lower(0) INTA(0) */
2843 PDMDevHlpPCISetIrq(pThis->CTX_SUFF(pDevIns), 0, 0);
2844
2845 pThis->u64AckedAt = TMTimerGet(pThis->CTX_SUFF(pIntTimer));
2846 if (pThis->fIntMaskUsed)
2847 pThis->fDelayInts = true;
2848 }
2849 else
2850 {
2851 /*
2852 * Interrupts are disabled -- in windows guests ICR read is done
2853 * just before re-enabling interrupts
2854 */
2855 E1kLog(("%s e1kRegReadICR: Suppressing auto-clear due to disabled interrupts (%08x)\n", pThis->szPrf, ICR));
2856 }
2857 }
2858 *pu32Value = value;
2859 }
2860 e1kCsLeave(pThis);
2861
2862 return rc;
2863}
2864
2865/**
2866 * Write handler for Interrupt Cause Set register.
2867 *
2868 * Bits corresponding to 1s in 'value' will be set in ICR register.
2869 *
2870 * @param pThis The device state structure.
2871 * @param offset Register offset in memory-mapped frame.
2872 * @param index Register index in register array.
2873 * @param value The value to store.
2874 * @param mask Used to implement partial writes (8 and 16-bit).
2875 * @thread EMT
2876 */
2877static int e1kRegWriteICS(PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t value)
2878{
2879 E1K_INC_ISTAT_CNT(pThis->uStatIntICS);
2880 return e1kRaiseInterrupt(pThis, VINF_IOM_R3_MMIO_WRITE, value & g_aE1kRegMap[ICS_IDX].writable);
2881}
2882
2883/**
2884 * Write handler for Interrupt Mask Set register.
2885 *
2886 * Will trigger pending interrupts.
2887 *
2888 * @param pThis The device state structure.
2889 * @param offset Register offset in memory-mapped frame.
2890 * @param index Register index in register array.
2891 * @param value The value to store.
2892 * @param mask Used to implement partial writes (8 and 16-bit).
2893 * @thread EMT
2894 */
2895static int e1kRegWriteIMS(PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t value)
2896{
2897 IMS |= value;
2898 E1kLogRel(("E1000: irq enabled, RDH=%x RDT=%x TDH=%x TDT=%x\n", RDH, RDT, TDH, TDT));
2899 E1kLog(("%s e1kRegWriteIMS: IRQ enabled\n", pThis->szPrf));
2900 /* Mask changes, we need to raise pending interrupts. */
2901 if ((ICR & IMS) && !pThis->fLocked)
2902 {
2903 E1kLog2(("%s e1kRegWriteIMS: IRQ pending (%08x), arming late int timer...\n",
2904 pThis->szPrf, ICR));
2905 /* Raising an interrupt immediately causes win7 to hang upon NIC reconfiguration, see @bugref{5023}. */
2906 TMTimerSet(pThis->CTX_SUFF(pIntTimer), TMTimerFromNano(pThis->CTX_SUFF(pIntTimer), ITR * 256) +
2907 TMTimerGet(pThis->CTX_SUFF(pIntTimer)));
2908 }
2909
2910 return VINF_SUCCESS;
2911}
2912
2913/**
2914 * Write handler for Interrupt Mask Clear register.
2915 *
2916 * Bits corresponding to 1s in 'value' will be cleared in IMS register.
2917 *
2918 * @param pThis The device state structure.
2919 * @param offset Register offset in memory-mapped frame.
2920 * @param index Register index in register array.
2921 * @param value The value to store.
2922 * @param mask Used to implement partial writes (8 and 16-bit).
2923 * @thread EMT
2924 */
2925static int e1kRegWriteIMC(PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t value)
2926{
2927 int rc = e1kCsEnter(pThis, VINF_IOM_R3_MMIO_WRITE);
2928 if (RT_UNLIKELY(rc != VINF_SUCCESS))
2929 return rc;
2930 if (pThis->fIntRaised)
2931 {
2932 /*
2933 * Technically we should reset fIntRaised in ICR read handler, but it will cause
2934 * Windows to freeze since it may receive an interrupt while still in the very beginning
2935 * of interrupt handler.
2936 */
2937 E1K_INC_ISTAT_CNT(pThis->uStatIntLower);
2938 STAM_COUNTER_INC(&pThis->StatIntsPrevented);
2939 E1kLogRel(("E1000: irq lowered (IMC), icr=0x%x\n", ICR));
2940 /* Lower(0) INTA(0) */
2941 PDMDevHlpPCISetIrq(pThis->CTX_SUFF(pDevIns), 0, 0);
2942 pThis->fIntRaised = false;
2943 E1kLog(("%s e1kRegWriteIMC: Lowered IRQ: ICR=%08x\n", pThis->szPrf, ICR));
2944 }
2945 IMS &= ~value;
2946 E1kLog(("%s e1kRegWriteIMC: IRQ disabled\n", pThis->szPrf));
2947 e1kCsLeave(pThis);
2948
2949 return VINF_SUCCESS;
2950}
2951
2952/**
2953 * Write handler for Receive Control register.
2954 *
2955 * @param pThis The device state structure.
2956 * @param offset Register offset in memory-mapped frame.
2957 * @param index Register index in register array.
2958 * @param value The value to store.
2959 * @param mask Used to implement partial writes (8 and 16-bit).
2960 * @thread EMT
2961 */
2962static int e1kRegWriteRCTL(PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t value)
2963{
2964 /* Update promiscuous mode */
2965 bool fBecomePromiscous = !!(value & (RCTL_UPE | RCTL_MPE));
2966 if (fBecomePromiscous != !!( RCTL & (RCTL_UPE | RCTL_MPE)))
2967 {
2968 /* Promiscuity has changed, pass the knowledge on. */
2969#ifndef IN_RING3
2970 return VINF_IOM_R3_IOPORT_WRITE;
2971#else
2972 if (pThis->pDrvR3)
2973 pThis->pDrvR3->pfnSetPromiscuousMode(pThis->pDrvR3, fBecomePromiscous);
2974#endif
2975 }
2976
2977 /* Adjust receive buffer size */
2978 unsigned cbRxBuf = 2048 >> GET_BITS_V(value, RCTL, BSIZE);
2979 if (value & RCTL_BSEX)
2980 cbRxBuf *= 16;
2981 if (cbRxBuf != pThis->u16RxBSize)
2982 E1kLog2(("%s e1kRegWriteRCTL: Setting receive buffer size to %d (old %d)\n",
2983 pThis->szPrf, cbRxBuf, pThis->u16RxBSize));
2984 pThis->u16RxBSize = cbRxBuf;
2985
2986 /* Update the register */
2987 e1kRegWriteDefault(pThis, offset, index, value);
2988
2989 return VINF_SUCCESS;
2990}
2991
2992/**
2993 * Write handler for Packet Buffer Allocation register.
2994 *
2995 * TXA = 64 - RXA.
2996 *
2997 * @param pThis The device state structure.
2998 * @param offset Register offset in memory-mapped frame.
2999 * @param index Register index in register array.
3000 * @param value The value to store.
3001 * @param mask Used to implement partial writes (8 and 16-bit).
3002 * @thread EMT
3003 */
3004static int e1kRegWritePBA(PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t value)
3005{
3006 e1kRegWriteDefault(pThis, offset, index, value);
3007 PBA_st->txa = 64 - PBA_st->rxa;
3008
3009 return VINF_SUCCESS;
3010}
3011
3012/**
3013 * Write handler for Receive Descriptor Tail register.
3014 *
3015 * @remarks Write into RDT forces switch to HC and signal to
3016 * e1kR3NetworkDown_WaitReceiveAvail().
3017 *
3018 * @returns VBox status code.
3019 *
3020 * @param pThis The device state structure.
3021 * @param offset Register offset in memory-mapped frame.
3022 * @param index Register index in register array.
3023 * @param value The value to store.
3024 * @param mask Used to implement partial writes (8 and 16-bit).
3025 * @thread EMT
3026 */
3027static int e1kRegWriteRDT(PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t value)
3028{
3029#ifndef IN_RING3
3030 /* XXX */
3031// return VINF_IOM_R3_MMIO_WRITE;
3032#endif
3033 int rc = e1kCsRxEnter(pThis, VINF_IOM_R3_MMIO_WRITE);
3034 if (RT_LIKELY(rc == VINF_SUCCESS))
3035 {
3036 E1kLog(("%s e1kRegWriteRDT\n", pThis->szPrf));
3037 rc = e1kRegWriteDefault(pThis, offset, index, value);
3038#ifdef E1K_WITH_RXD_CACHE
3039 /*
3040 * We need to fetch descriptors now as RDT may go whole circle
3041 * before we attempt to store a received packet. For example,
3042 * Intel's DOS drivers use 2 (!) RX descriptors with the total ring
3043 * size being only 8 descriptors! Note that we fetch descriptors
3044 * only when the cache is empty to reduce the number of memory reads
3045 * in case of frequent RDT writes. Don't fetch anything when the
3046 * receiver is disabled either as RDH, RDT, RDLEN can be in some
3047 * messed up state.
3048 * Note that despite the cache may seem empty, meaning that there are
3049 * no more available descriptors in it, it may still be used by RX
3050 * thread which has not yet written the last descriptor back but has
3051 * temporarily released the RX lock in order to write the packet body
3052 * to descriptor's buffer. At this point we still going to do prefetch
3053 * but it won't actually fetch anything if there are no unused slots in
3054 * our "empty" cache (nRxDFetched==E1K_RXD_CACHE_SIZE). We must not
3055 * reset the cache here even if it appears empty. It will be reset at
3056 * a later point in e1kRxDGet().
3057 */
3058 if (e1kRxDIsCacheEmpty(pThis) && (RCTL & RCTL_EN))
3059 e1kRxDPrefetch(pThis);
3060#endif /* E1K_WITH_RXD_CACHE */
3061 e1kCsRxLeave(pThis);
3062 if (RT_SUCCESS(rc))
3063 {
3064/** @todo bird: Use SUPSem* for this so we can signal it in ring-0 as well
3065 * without requiring any context switches. We should also check the
3066 * wait condition before bothering to queue the item as we're currently
3067 * queuing thousands of items per second here in a normal transmit
3068 * scenario. Expect performance changes when fixing this! */
3069#ifdef IN_RING3
3070 /* Signal that we have more receive descriptors available. */
3071 e1kWakeupReceive(pThis->CTX_SUFF(pDevIns));
3072#else
3073 PPDMQUEUEITEMCORE pItem = PDMQueueAlloc(pThis->CTX_SUFF(pCanRxQueue));
3074 if (pItem)
3075 PDMQueueInsert(pThis->CTX_SUFF(pCanRxQueue), pItem);
3076#endif
3077 }
3078 }
3079 return rc;
3080}
3081
3082/**
3083 * Write handler for Receive Delay Timer register.
3084 *
3085 * @param pThis The device state structure.
3086 * @param offset Register offset in memory-mapped frame.
3087 * @param index Register index in register array.
3088 * @param value The value to store.
3089 * @param mask Used to implement partial writes (8 and 16-bit).
3090 * @thread EMT
3091 */
3092static int e1kRegWriteRDTR(PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t value)
3093{
3094 e1kRegWriteDefault(pThis, offset, index, value);
3095 if (value & RDTR_FPD)
3096 {
3097 /* Flush requested, cancel both timers and raise interrupt */
3098#ifdef E1K_USE_RX_TIMERS
3099 e1kCancelTimer(pThis, pThis->CTX_SUFF(pRIDTimer));
3100 e1kCancelTimer(pThis, pThis->CTX_SUFF(pRADTimer));
3101#endif
3102 E1K_INC_ISTAT_CNT(pThis->uStatIntRDTR);
3103 return e1kRaiseInterrupt(pThis, VINF_IOM_R3_MMIO_WRITE, ICR_RXT0);
3104 }
3105
3106 return VINF_SUCCESS;
3107}
3108
3109DECLINLINE(uint32_t) e1kGetTxLen(PE1KSTATE pThis)
3110{
3111 /**
3112 * Make sure TDT won't change during computation. EMT may modify TDT at
3113 * any moment.
3114 */
3115 uint32_t tdt = TDT;
3116 return (TDH>tdt ? TDLEN/sizeof(E1KTXDESC) : 0) + tdt - TDH;
3117}
3118
3119#ifdef IN_RING3
3120#ifdef E1K_TX_DELAY
3121
3122/**
3123 * Transmit Delay Timer handler.
3124 *
3125 * @remarks We only get here when the timer expires.
3126 *
3127 * @param pDevIns Pointer to device instance structure.
3128 * @param pTimer Pointer to the timer.
3129 * @param pvUser NULL.
3130 * @thread EMT
3131 */
3132static DECLCALLBACK(void) e1kTxDelayTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
3133{
3134 PE1KSTATE pThis = (PE1KSTATE )pvUser;
3135 Assert(PDMCritSectIsOwner(&pThis->csTx));
3136
3137 E1K_INC_ISTAT_CNT(pThis->uStatTxDelayExp);
3138#ifdef E1K_INT_STATS
3139 uint64_t u64Elapsed = RTTimeNanoTS() - pThis->u64ArmedAt;
3140 if (u64Elapsed > pThis->uStatMaxTxDelay)
3141 pThis->uStatMaxTxDelay = u64Elapsed;
3142#endif
3143 int rc = e1kXmitPending(pThis, false /*fOnWorkerThread*/);
3144 AssertMsg(RT_SUCCESS(rc) || rc == VERR_TRY_AGAIN, ("%Rrc\n", rc));
3145}
3146#endif /* E1K_TX_DELAY */
3147
3148#ifdef E1K_USE_TX_TIMERS
3149
3150/**
3151 * Transmit Interrupt Delay Timer handler.
3152 *
3153 * @remarks We only get here when the timer expires.
3154 *
3155 * @param pDevIns Pointer to device instance structure.
3156 * @param pTimer Pointer to the timer.
3157 * @param pvUser NULL.
3158 * @thread EMT
3159 */
3160static DECLCALLBACK(void) e1kTxIntDelayTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
3161{
3162 PE1KSTATE pThis = (PE1KSTATE )pvUser;
3163
3164 E1K_INC_ISTAT_CNT(pThis->uStatTID);
3165 /* Cancel absolute delay timer as we have already got attention */
3166#ifndef E1K_NO_TAD
3167 e1kCancelTimer(pThis, pThis->CTX_SUFF(pTADTimer));
3168#endif /* E1K_NO_TAD */
3169 e1kRaiseInterrupt(pThis, ICR_TXDW);
3170}
3171
3172/**
3173 * Transmit Absolute Delay Timer handler.
3174 *
3175 * @remarks We only get here when the timer expires.
3176 *
3177 * @param pDevIns Pointer to device instance structure.
3178 * @param pTimer Pointer to the timer.
3179 * @param pvUser NULL.
3180 * @thread EMT
3181 */
3182static DECLCALLBACK(void) e1kTxAbsDelayTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
3183{
3184 PE1KSTATE pThis = (PE1KSTATE )pvUser;
3185
3186 E1K_INC_ISTAT_CNT(pThis->uStatTAD);
3187 /* Cancel interrupt delay timer as we have already got attention */
3188 e1kCancelTimer(pThis, pThis->CTX_SUFF(pTIDTimer));
3189 e1kRaiseInterrupt(pThis, ICR_TXDW);
3190}
3191
3192#endif /* E1K_USE_TX_TIMERS */
3193#ifdef E1K_USE_RX_TIMERS
3194
3195/**
3196 * Receive Interrupt Delay Timer handler.
3197 *
3198 * @remarks We only get here when the timer expires.
3199 *
3200 * @param pDevIns Pointer to device instance structure.
3201 * @param pTimer Pointer to the timer.
3202 * @param pvUser NULL.
3203 * @thread EMT
3204 */
3205static DECLCALLBACK(void) e1kRxIntDelayTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
3206{
3207 PE1KSTATE pThis = (PE1KSTATE )pvUser;
3208
3209 E1K_INC_ISTAT_CNT(pThis->uStatRID);
3210 /* Cancel absolute delay timer as we have already got attention */
3211 e1kCancelTimer(pThis, pThis->CTX_SUFF(pRADTimer));
3212 e1kRaiseInterrupt(pThis, ICR_RXT0);
3213}
3214
3215/**
3216 * Receive Absolute Delay Timer handler.
3217 *
3218 * @remarks We only get here when the timer expires.
3219 *
3220 * @param pDevIns Pointer to device instance structure.
3221 * @param pTimer Pointer to the timer.
3222 * @param pvUser NULL.
3223 * @thread EMT
3224 */
3225static DECLCALLBACK(void) e1kRxAbsDelayTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
3226{
3227 PE1KSTATE pThis = (PE1KSTATE )pvUser;
3228
3229 E1K_INC_ISTAT_CNT(pThis->uStatRAD);
3230 /* Cancel interrupt delay timer as we have already got attention */
3231 e1kCancelTimer(pThis, pThis->CTX_SUFF(pRIDTimer));
3232 e1kRaiseInterrupt(pThis, ICR_RXT0);
3233}
3234
3235#endif /* E1K_USE_RX_TIMERS */
3236
3237/**
3238 * Late Interrupt Timer handler.
3239 *
3240 * @param pDevIns Pointer to device instance structure.
3241 * @param pTimer Pointer to the timer.
3242 * @param pvUser NULL.
3243 * @thread EMT
3244 */
3245static DECLCALLBACK(void) e1kLateIntTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
3246{
3247 PE1KSTATE pThis = (PE1KSTATE )pvUser;
3248
3249 STAM_PROFILE_ADV_START(&pThis->StatLateIntTimer, a);
3250 STAM_COUNTER_INC(&pThis->StatLateInts);
3251 E1K_INC_ISTAT_CNT(pThis->uStatIntLate);
3252#if 0
3253 if (pThis->iStatIntLost > -100)
3254 pThis->iStatIntLost--;
3255#endif
3256 e1kRaiseInterrupt(pThis, VERR_SEM_BUSY, 0);
3257 STAM_PROFILE_ADV_STOP(&pThis->StatLateIntTimer, a);
3258}
3259
3260/**
3261 * Link Up Timer handler.
3262 *
3263 * @param pDevIns Pointer to device instance structure.
3264 * @param pTimer Pointer to the timer.
3265 * @param pvUser NULL.
3266 * @thread EMT
3267 */
3268static DECLCALLBACK(void) e1kLinkUpTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
3269{
3270 PE1KSTATE pThis = (PE1KSTATE )pvUser;
3271
3272 /*
3273 * This can happen if we set the link status to down when the Link up timer was
3274 * already armed (shortly after e1kLoadDone() or when the cable was disconnected
3275 * and connect+disconnect the cable very quick.
3276 */
3277 if (!pThis->fCableConnected)
3278 return;
3279
3280 E1kLog(("%s e1kLinkUpTimer: Link is up\n", pThis->szPrf));
3281 STATUS |= STATUS_LU;
3282 Phy::setLinkStatus(&pThis->phy, true);
3283 e1kRaiseInterrupt(pThis, VERR_SEM_BUSY, ICR_LSC);
3284}
3285
3286#endif /* IN_RING3 */
3287
3288/**
3289 * Sets up the GSO context according to the TSE new context descriptor.
3290 *
3291 * @param pGso The GSO context to setup.
3292 * @param pCtx The context descriptor.
3293 */
3294DECLINLINE(void) e1kSetupGsoCtx(PPDMNETWORKGSO pGso, E1KTXCTX const *pCtx)
3295{
3296 pGso->u8Type = PDMNETWORKGSOTYPE_INVALID;
3297
3298 /*
3299 * See if the context descriptor describes something that could be TCP or
3300 * UDP over IPv[46].
3301 */
3302 /* Check the header ordering and spacing: 1. Ethernet, 2. IP, 3. TCP/UDP. */
3303 if (RT_UNLIKELY( pCtx->ip.u8CSS < sizeof(RTNETETHERHDR) ))
3304 {
3305 E1kLog(("e1kSetupGsoCtx: IPCSS=%#x\n", pCtx->ip.u8CSS));
3306 return;
3307 }
3308 if (RT_UNLIKELY( pCtx->tu.u8CSS < (size_t)pCtx->ip.u8CSS + (pCtx->dw2.fIP ? RTNETIPV4_MIN_LEN : RTNETIPV6_MIN_LEN) ))
3309 {
3310 E1kLog(("e1kSetupGsoCtx: TUCSS=%#x\n", pCtx->tu.u8CSS));
3311 return;
3312 }
3313 if (RT_UNLIKELY( pCtx->dw2.fTCP
3314 ? pCtx->dw3.u8HDRLEN < (size_t)pCtx->tu.u8CSS + RTNETTCP_MIN_LEN
3315 : pCtx->dw3.u8HDRLEN != (size_t)pCtx->tu.u8CSS + RTNETUDP_MIN_LEN ))
3316 {
3317 E1kLog(("e1kSetupGsoCtx: HDRLEN=%#x TCP=%d\n", pCtx->dw3.u8HDRLEN, pCtx->dw2.fTCP));
3318 return;
3319 }
3320
3321 /* The end of the TCP/UDP checksum should stop at the end of the packet or at least after the headers. */
3322 if (RT_UNLIKELY( pCtx->tu.u16CSE > 0 && pCtx->tu.u16CSE <= pCtx->dw3.u8HDRLEN ))
3323 {
3324 E1kLog(("e1kSetupGsoCtx: TUCSE=%#x HDRLEN=%#x\n", pCtx->tu.u16CSE, pCtx->dw3.u8HDRLEN));
3325 return;
3326 }
3327
3328 /* IPv4 checksum offset. */
3329 if (RT_UNLIKELY( pCtx->dw2.fIP && (size_t)pCtx->ip.u8CSO - pCtx->ip.u8CSS != RT_UOFFSETOF(RTNETIPV4, ip_sum) ))
3330 {
3331 E1kLog(("e1kSetupGsoCtx: IPCSO=%#x IPCSS=%#x\n", pCtx->ip.u8CSO, pCtx->ip.u8CSS));
3332 return;
3333 }
3334
3335 /* TCP/UDP checksum offsets. */
3336 if (RT_UNLIKELY( (size_t)pCtx->tu.u8CSO - pCtx->tu.u8CSS
3337 != ( pCtx->dw2.fTCP
3338 ? RT_UOFFSETOF(RTNETTCP, th_sum)
3339 : RT_UOFFSETOF(RTNETUDP, uh_sum) ) ))
3340 {
3341 E1kLog(("e1kSetupGsoCtx: TUCSO=%#x TUCSS=%#x TCP=%d\n", pCtx->ip.u8CSO, pCtx->ip.u8CSS, pCtx->dw2.fTCP));
3342 return;
3343 }
3344
3345 /*
3346 * Because of internal networking using a 16-bit size field for GSO context
3347 * plus frame, we have to make sure we don't exceed this.
3348 */
3349 if (RT_UNLIKELY( pCtx->dw3.u8HDRLEN + pCtx->dw2.u20PAYLEN > VBOX_MAX_GSO_SIZE ))
3350 {
3351 E1kLog(("e1kSetupGsoCtx: HDRLEN(=%#x) + PAYLEN(=%#x) = %#x, max is %#x\n",
3352 pCtx->dw3.u8HDRLEN, pCtx->dw2.u20PAYLEN, pCtx->dw3.u8HDRLEN + pCtx->dw2.u20PAYLEN, VBOX_MAX_GSO_SIZE));
3353 return;
3354 }
3355
3356 /*
3357 * We're good for now - we'll do more checks when seeing the data.
3358 * So, figure the type of offloading and setup the context.
3359 */
3360 if (pCtx->dw2.fIP)
3361 {
3362 if (pCtx->dw2.fTCP)
3363 {
3364 pGso->u8Type = PDMNETWORKGSOTYPE_IPV4_TCP;
3365 pGso->cbHdrsSeg = pCtx->dw3.u8HDRLEN;
3366 }
3367 else
3368 {
3369 pGso->u8Type = PDMNETWORKGSOTYPE_IPV4_UDP;
3370 pGso->cbHdrsSeg = pCtx->tu.u8CSS; /* IP header only */
3371 }
3372 /** @todo Detect IPv4-IPv6 tunneling (need test setup since linux doesn't do
3373 * this yet it seems)... */
3374 }
3375 else
3376 {
3377 pGso->cbHdrsSeg = pCtx->dw3.u8HDRLEN; /* @todo IPv6 UFO */
3378 if (pCtx->dw2.fTCP)
3379 pGso->u8Type = PDMNETWORKGSOTYPE_IPV6_TCP;
3380 else
3381 pGso->u8Type = PDMNETWORKGSOTYPE_IPV6_UDP;
3382 }
3383 pGso->offHdr1 = pCtx->ip.u8CSS;
3384 pGso->offHdr2 = pCtx->tu.u8CSS;
3385 pGso->cbHdrsTotal = pCtx->dw3.u8HDRLEN;
3386 pGso->cbMaxSeg = pCtx->dw3.u16MSS;
3387 Assert(PDMNetGsoIsValid(pGso, sizeof(*pGso), pGso->cbMaxSeg * 5));
3388 E1kLog2(("e1kSetupGsoCtx: mss=%#x hdr=%#x hdrseg=%#x hdr1=%#x hdr2=%#x %s\n",
3389 pGso->cbMaxSeg, pGso->cbHdrsTotal, pGso->cbHdrsSeg, pGso->offHdr1, pGso->offHdr2, PDMNetGsoTypeName((PDMNETWORKGSOTYPE)pGso->u8Type) ));
3390}
3391
3392/**
3393 * Checks if we can use GSO processing for the current TSE frame.
3394 *
3395 * @param pThis The device state structure.
3396 * @param pGso The GSO context.
3397 * @param pData The first data descriptor of the frame.
3398 * @param pCtx The TSO context descriptor.
3399 */
3400DECLINLINE(bool) e1kCanDoGso(PE1KSTATE pThis, PCPDMNETWORKGSO pGso, E1KTXDAT const *pData, E1KTXCTX const *pCtx)
3401{
3402 if (!pData->cmd.fTSE)
3403 {
3404 E1kLog2(("e1kCanDoGso: !TSE\n"));
3405 return false;
3406 }
3407 if (pData->cmd.fVLE) /** @todo VLAN tagging. */
3408 {
3409 E1kLog(("e1kCanDoGso: VLE\n"));
3410 return false;
3411 }
3412 if (RT_UNLIKELY(!pThis->fGSOEnabled))
3413 {
3414 E1kLog3(("e1kCanDoGso: GSO disabled via CFGM\n"));
3415 return false;
3416 }
3417
3418 switch ((PDMNETWORKGSOTYPE)pGso->u8Type)
3419 {
3420 case PDMNETWORKGSOTYPE_IPV4_TCP:
3421 case PDMNETWORKGSOTYPE_IPV4_UDP:
3422 if (!pData->dw3.fIXSM)
3423 {
3424 E1kLog(("e1kCanDoGso: !IXSM (IPv4)\n"));
3425 return false;
3426 }
3427 if (!pData->dw3.fTXSM)
3428 {
3429 E1kLog(("e1kCanDoGso: !TXSM (IPv4)\n"));
3430 return false;
3431 }
3432 /** @todo what more check should we perform here? Ethernet frame type? */
3433 E1kLog2(("e1kCanDoGso: OK, IPv4\n"));
3434 return true;
3435
3436 case PDMNETWORKGSOTYPE_IPV6_TCP:
3437 case PDMNETWORKGSOTYPE_IPV6_UDP:
3438 if (pData->dw3.fIXSM && pCtx->ip.u8CSO)
3439 {
3440 E1kLog(("e1kCanDoGso: IXSM (IPv6)\n"));
3441 return false;
3442 }
3443 if (!pData->dw3.fTXSM)
3444 {
3445 E1kLog(("e1kCanDoGso: TXSM (IPv6)\n"));
3446 return false;
3447 }
3448 /** @todo what more check should we perform here? Ethernet frame type? */
3449 E1kLog2(("e1kCanDoGso: OK, IPv4\n"));
3450 return true;
3451
3452 default:
3453 Assert(pGso->u8Type == PDMNETWORKGSOTYPE_INVALID);
3454 E1kLog2(("e1kCanDoGso: e1kSetupGsoCtx failed\n"));
3455 return false;
3456 }
3457}
3458
3459/**
3460 * Frees the current xmit buffer.
3461 *
3462 * @param pThis The device state structure.
3463 */
3464static void e1kXmitFreeBuf(PE1KSTATE pThis)
3465{
3466 PPDMSCATTERGATHER pSg = pThis->CTX_SUFF(pTxSg);
3467 if (pSg)
3468 {
3469 pThis->CTX_SUFF(pTxSg) = NULL;
3470
3471 if (pSg->pvAllocator != pThis)
3472 {
3473 PPDMINETWORKUP pDrv = pThis->CTX_SUFF(pDrv);
3474 if (pDrv)
3475 pDrv->pfnFreeBuf(pDrv, pSg);
3476 }
3477 else
3478 {
3479 /* loopback */
3480 AssertCompileMemberSize(E1KSTATE, uTxFallback.Sg, 8 * sizeof(size_t));
3481 Assert(pSg->fFlags == (PDMSCATTERGATHER_FLAGS_MAGIC | PDMSCATTERGATHER_FLAGS_OWNER_3));
3482 pSg->fFlags = 0;
3483 pSg->pvAllocator = NULL;
3484 }
3485 }
3486}
3487
3488#ifndef E1K_WITH_TXD_CACHE
3489/**
3490 * Allocates an xmit buffer.
3491 *
3492 * @returns See PDMINETWORKUP::pfnAllocBuf.
3493 * @param pThis The device state structure.
3494 * @param cbMin The minimum frame size.
3495 * @param fExactSize Whether cbMin is exact or if we have to max it
3496 * out to the max MTU size.
3497 * @param fGso Whether this is a GSO frame or not.
3498 */
3499DECLINLINE(int) e1kXmitAllocBuf(PE1KSTATE pThis, size_t cbMin, bool fExactSize, bool fGso)
3500{
3501 /* Adjust cbMin if necessary. */
3502 if (!fExactSize)
3503 cbMin = RT_MAX(cbMin, E1K_MAX_TX_PKT_SIZE);
3504
3505 /* Deal with existing buffer (descriptor screw up, reset, etc). */
3506 if (RT_UNLIKELY(pThis->CTX_SUFF(pTxSg)))
3507 e1kXmitFreeBuf(pThis);
3508 Assert(pThis->CTX_SUFF(pTxSg) == NULL);
3509
3510 /*
3511 * Allocate the buffer.
3512 */
3513 PPDMSCATTERGATHER pSg;
3514 if (RT_LIKELY(GET_BITS(RCTL, LBM) != RCTL_LBM_TCVR))
3515 {
3516 PPDMINETWORKUP pDrv = pThis->CTX_SUFF(pDrv);
3517 if (RT_UNLIKELY(!pDrv))
3518 return VERR_NET_DOWN;
3519 int rc = pDrv->pfnAllocBuf(pDrv, cbMin, fGso ? &pThis->GsoCtx : NULL, &pSg);
3520 if (RT_FAILURE(rc))
3521 {
3522 /* Suspend TX as we are out of buffers atm */
3523 STATUS |= STATUS_TXOFF;
3524 return rc;
3525 }
3526 }
3527 else
3528 {
3529 /* Create a loopback using the fallback buffer and preallocated SG. */
3530 AssertCompileMemberSize(E1KSTATE, uTxFallback.Sg, 8 * sizeof(size_t));
3531 pSg = &pThis->uTxFallback.Sg;
3532 pSg->fFlags = PDMSCATTERGATHER_FLAGS_MAGIC | PDMSCATTERGATHER_FLAGS_OWNER_3;
3533 pSg->cbUsed = 0;
3534 pSg->cbAvailable = 0;
3535 pSg->pvAllocator = pThis;
3536 pSg->pvUser = NULL; /* No GSO here. */
3537 pSg->cSegs = 1;
3538 pSg->aSegs[0].pvSeg = pThis->aTxPacketFallback;
3539 pSg->aSegs[0].cbSeg = sizeof(pThis->aTxPacketFallback);
3540 }
3541
3542 pThis->CTX_SUFF(pTxSg) = pSg;
3543 return VINF_SUCCESS;
3544}
3545#else /* E1K_WITH_TXD_CACHE */
3546/**
3547 * Allocates an xmit buffer.
3548 *
3549 * @returns See PDMINETWORKUP::pfnAllocBuf.
3550 * @param pThis The device state structure.
3551 * @param cbMin The minimum frame size.
3552 * @param fExactSize Whether cbMin is exact or if we have to max it
3553 * out to the max MTU size.
3554 * @param fGso Whether this is a GSO frame or not.
3555 */
3556DECLINLINE(int) e1kXmitAllocBuf(PE1KSTATE pThis, bool fGso)
3557{
3558 /* Deal with existing buffer (descriptor screw up, reset, etc). */
3559 if (RT_UNLIKELY(pThis->CTX_SUFF(pTxSg)))
3560 e1kXmitFreeBuf(pThis);
3561 Assert(pThis->CTX_SUFF(pTxSg) == NULL);
3562
3563 /*
3564 * Allocate the buffer.
3565 */
3566 PPDMSCATTERGATHER pSg;
3567 if (RT_LIKELY(GET_BITS(RCTL, LBM) != RCTL_LBM_TCVR))
3568 {
3569 if (pThis->cbTxAlloc == 0)
3570 {
3571 /* Zero packet, no need for the buffer */
3572 return VINF_SUCCESS;
3573 }
3574
3575 PPDMINETWORKUP pDrv = pThis->CTX_SUFF(pDrv);
3576 if (RT_UNLIKELY(!pDrv))
3577 return VERR_NET_DOWN;
3578 int rc = pDrv->pfnAllocBuf(pDrv, pThis->cbTxAlloc, fGso ? &pThis->GsoCtx : NULL, &pSg);
3579 if (RT_FAILURE(rc))
3580 {
3581 /* Suspend TX as we are out of buffers atm */
3582 STATUS |= STATUS_TXOFF;
3583 return rc;
3584 }
3585 E1kLog3(("%s Allocated buffer for TX packet: cb=%u %s%s\n",
3586 pThis->szPrf, pThis->cbTxAlloc,
3587 pThis->fVTag ? "VLAN " : "",
3588 pThis->fGSO ? "GSO " : ""));
3589 pThis->cbTxAlloc = 0;
3590 }
3591 else
3592 {
3593 /* Create a loopback using the fallback buffer and preallocated SG. */
3594 AssertCompileMemberSize(E1KSTATE, uTxFallback.Sg, 8 * sizeof(size_t));
3595 pSg = &pThis->uTxFallback.Sg;
3596 pSg->fFlags = PDMSCATTERGATHER_FLAGS_MAGIC | PDMSCATTERGATHER_FLAGS_OWNER_3;
3597 pSg->cbUsed = 0;
3598 pSg->cbAvailable = 0;
3599 pSg->pvAllocator = pThis;
3600 pSg->pvUser = NULL; /* No GSO here. */
3601 pSg->cSegs = 1;
3602 pSg->aSegs[0].pvSeg = pThis->aTxPacketFallback;
3603 pSg->aSegs[0].cbSeg = sizeof(pThis->aTxPacketFallback);
3604 }
3605
3606 pThis->CTX_SUFF(pTxSg) = pSg;
3607 return VINF_SUCCESS;
3608}
3609#endif /* E1K_WITH_TXD_CACHE */
3610
3611/**
3612 * Checks if it's a GSO buffer or not.
3613 *
3614 * @returns true / false.
3615 * @param pTxSg The scatter / gather buffer.
3616 */
3617DECLINLINE(bool) e1kXmitIsGsoBuf(PDMSCATTERGATHER const *pTxSg)
3618{
3619#if 0
3620 if (!pTxSg)
3621 E1kLog(("e1kXmitIsGsoBuf: pTxSG is NULL\n"));
3622 if (pTxSg && pTxSg->pvUser)
3623 E1kLog(("e1kXmitIsGsoBuf: pvUser is NULL\n"));
3624#endif
3625 return pTxSg && pTxSg->pvUser /* GSO indicator */;
3626}
3627
3628#ifndef E1K_WITH_TXD_CACHE
3629/**
3630 * Load transmit descriptor from guest memory.
3631 *
3632 * @param pThis The device state structure.
3633 * @param pDesc Pointer to descriptor union.
3634 * @param addr Physical address in guest context.
3635 * @thread E1000_TX
3636 */
3637DECLINLINE(void) e1kLoadDesc(PE1KSTATE pThis, E1KTXDESC* pDesc, RTGCPHYS addr)
3638{
3639 PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns), addr, pDesc, sizeof(E1KTXDESC));
3640}
3641#else /* E1K_WITH_TXD_CACHE */
3642/**
3643 * Load transmit descriptors from guest memory.
3644 *
3645 * We need two physical reads in case the tail wrapped around the end of TX
3646 * descriptor ring.
3647 *
3648 * @returns the actual number of descriptors fetched.
3649 * @param pThis The device state structure.
3650 * @param pDesc Pointer to descriptor union.
3651 * @param addr Physical address in guest context.
3652 * @thread E1000_TX
3653 */
3654DECLINLINE(unsigned) e1kTxDLoadMore(PE1KSTATE pThis)
3655{
3656 Assert(pThis->iTxDCurrent == 0);
3657 /* We've already loaded pThis->nTxDFetched descriptors past TDH. */
3658 unsigned nDescsAvailable = e1kGetTxLen(pThis) - pThis->nTxDFetched;
3659 unsigned nDescsToFetch = RT_MIN(nDescsAvailable, E1K_TXD_CACHE_SIZE - pThis->nTxDFetched);
3660 unsigned nDescsTotal = TDLEN / sizeof(E1KTXDESC);
3661 unsigned nFirstNotLoaded = (TDH + pThis->nTxDFetched) % nDescsTotal;
3662 unsigned nDescsInSingleRead = RT_MIN(nDescsToFetch, nDescsTotal - nFirstNotLoaded);
3663 E1kLog3(("%s e1kTxDLoadMore: nDescsAvailable=%u nDescsToFetch=%u "
3664 "nDescsTotal=%u nFirstNotLoaded=0x%x nDescsInSingleRead=%u\n",
3665 pThis->szPrf, nDescsAvailable, nDescsToFetch, nDescsTotal,
3666 nFirstNotLoaded, nDescsInSingleRead));
3667 if (nDescsToFetch == 0)
3668 return 0;
3669 E1KTXDESC* pFirstEmptyDesc = &pThis->aTxDescriptors[pThis->nTxDFetched];
3670 PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns),
3671 ((uint64_t)TDBAH << 32) + TDBAL + nFirstNotLoaded * sizeof(E1KTXDESC),
3672 pFirstEmptyDesc, nDescsInSingleRead * sizeof(E1KTXDESC));
3673 E1kLog3(("%s Fetched %u TX descriptors at %08x%08x(0x%x), TDLEN=%08x, TDH=%08x, TDT=%08x\n",
3674 pThis->szPrf, nDescsInSingleRead,
3675 TDBAH, TDBAL + TDH * sizeof(E1KTXDESC),
3676 nFirstNotLoaded, TDLEN, TDH, TDT));
3677 if (nDescsToFetch > nDescsInSingleRead)
3678 {
3679 PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns),
3680 ((uint64_t)TDBAH << 32) + TDBAL,
3681 pFirstEmptyDesc + nDescsInSingleRead,
3682 (nDescsToFetch - nDescsInSingleRead) * sizeof(E1KTXDESC));
3683 E1kLog3(("%s Fetched %u TX descriptors at %08x%08x\n",
3684 pThis->szPrf, nDescsToFetch - nDescsInSingleRead,
3685 TDBAH, TDBAL));
3686 }
3687 pThis->nTxDFetched += nDescsToFetch;
3688 return nDescsToFetch;
3689}
3690
3691/**
3692 * Load transmit descriptors from guest memory only if there are no loaded
3693 * descriptors.
3694 *
3695 * @returns true if there are descriptors in cache.
3696 * @param pThis The device state structure.
3697 * @param pDesc Pointer to descriptor union.
3698 * @param addr Physical address in guest context.
3699 * @thread E1000_TX
3700 */
3701DECLINLINE(bool) e1kTxDLazyLoad(PE1KSTATE pThis)
3702{
3703 if (pThis->nTxDFetched == 0)
3704 return e1kTxDLoadMore(pThis) != 0;
3705 return true;
3706}
3707#endif /* E1K_WITH_TXD_CACHE */
3708
3709/**
3710 * Write back transmit descriptor to guest memory.
3711 *
3712 * @param pThis The device state structure.
3713 * @param pDesc Pointer to descriptor union.
3714 * @param addr Physical address in guest context.
3715 * @thread E1000_TX
3716 */
3717DECLINLINE(void) e1kWriteBackDesc(PE1KSTATE pThis, E1KTXDESC* pDesc, RTGCPHYS addr)
3718{
3719 /* Only the last half of the descriptor has to be written back. */
3720 e1kPrintTDesc(pThis, pDesc, "^^^");
3721 PDMDevHlpPCIPhysWrite(pThis->CTX_SUFF(pDevIns), addr, pDesc, sizeof(E1KTXDESC));
3722}
3723
3724/**
3725 * Transmit complete frame.
3726 *
3727 * @remarks We skip the FCS since we're not responsible for sending anything to
3728 * a real ethernet wire.
3729 *
3730 * @param pThis The device state structure.
3731 * @param fOnWorkerThread Whether we're on a worker thread or an EMT.
3732 * @thread E1000_TX
3733 */
3734static void e1kTransmitFrame(PE1KSTATE pThis, bool fOnWorkerThread)
3735{
3736 PPDMSCATTERGATHER pSg = pThis->CTX_SUFF(pTxSg);
3737 uint32_t cbFrame = pSg ? (uint32_t)pSg->cbUsed : 0;
3738 Assert(!pSg || pSg->cSegs == 1);
3739
3740 if (cbFrame > 70) /* unqualified guess */
3741 pThis->led.Asserted.s.fWriting = pThis->led.Actual.s.fWriting = 1;
3742
3743#ifdef E1K_INT_STATS
3744 if (cbFrame <= 1514)
3745 E1K_INC_ISTAT_CNT(pThis->uStatTx1514);
3746 else if (cbFrame <= 2962)
3747 E1K_INC_ISTAT_CNT(pThis->uStatTx2962);
3748 else if (cbFrame <= 4410)
3749 E1K_INC_ISTAT_CNT(pThis->uStatTx4410);
3750 else if (cbFrame <= 5858)
3751 E1K_INC_ISTAT_CNT(pThis->uStatTx5858);
3752 else if (cbFrame <= 7306)
3753 E1K_INC_ISTAT_CNT(pThis->uStatTx7306);
3754 else if (cbFrame <= 8754)
3755 E1K_INC_ISTAT_CNT(pThis->uStatTx8754);
3756 else if (cbFrame <= 16384)
3757 E1K_INC_ISTAT_CNT(pThis->uStatTx16384);
3758 else if (cbFrame <= 32768)
3759 E1K_INC_ISTAT_CNT(pThis->uStatTx32768);
3760 else
3761 E1K_INC_ISTAT_CNT(pThis->uStatTxLarge);
3762#endif /* E1K_INT_STATS */
3763
3764 /* Add VLAN tag */
3765 if (cbFrame > 12 && pThis->fVTag)
3766 {
3767 E1kLog3(("%s Inserting VLAN tag %08x\n",
3768 pThis->szPrf, RT_BE2H_U16(VET) | (RT_BE2H_U16(pThis->u16VTagTCI) << 16)));
3769 memmove((uint8_t*)pSg->aSegs[0].pvSeg + 16, (uint8_t*)pSg->aSegs[0].pvSeg + 12, cbFrame - 12);
3770 *((uint32_t*)pSg->aSegs[0].pvSeg + 3) = RT_BE2H_U16(VET) | (RT_BE2H_U16(pThis->u16VTagTCI) << 16);
3771 pSg->cbUsed += 4;
3772 cbFrame += 4;
3773 Assert(pSg->cbUsed == cbFrame);
3774 Assert(pSg->cbUsed <= pSg->cbAvailable);
3775 }
3776/* E1kLog2(("%s < < < Outgoing packet. Dump follows: > > >\n"
3777 "%.*Rhxd\n"
3778 "%s < < < < < < < < < < < < < End of dump > > > > > > > > > > > >\n",
3779 pThis->szPrf, cbFrame, pSg->aSegs[0].pvSeg, pThis->szPrf));*/
3780
3781 /* Update the stats */
3782 E1K_INC_CNT32(TPT);
3783 E1K_ADD_CNT64(TOTL, TOTH, cbFrame);
3784 E1K_INC_CNT32(GPTC);
3785 if (pSg && e1kIsBroadcast(pSg->aSegs[0].pvSeg))
3786 E1K_INC_CNT32(BPTC);
3787 else if (pSg && e1kIsMulticast(pSg->aSegs[0].pvSeg))
3788 E1K_INC_CNT32(MPTC);
3789 /* Update octet transmit counter */
3790 E1K_ADD_CNT64(GOTCL, GOTCH, cbFrame);
3791 if (pThis->CTX_SUFF(pDrv))
3792 STAM_REL_COUNTER_ADD(&pThis->StatTransmitBytes, cbFrame);
3793 if (cbFrame == 64)
3794 E1K_INC_CNT32(PTC64);
3795 else if (cbFrame < 128)
3796 E1K_INC_CNT32(PTC127);
3797 else if (cbFrame < 256)
3798 E1K_INC_CNT32(PTC255);
3799 else if (cbFrame < 512)
3800 E1K_INC_CNT32(PTC511);
3801 else if (cbFrame < 1024)
3802 E1K_INC_CNT32(PTC1023);
3803 else
3804 E1K_INC_CNT32(PTC1522);
3805
3806 E1K_INC_ISTAT_CNT(pThis->uStatTxFrm);
3807
3808 /*
3809 * Dump and send the packet.
3810 */
3811 int rc = VERR_NET_DOWN;
3812 if (pSg && pSg->pvAllocator != pThis)
3813 {
3814 e1kPacketDump(pThis, (uint8_t const *)pSg->aSegs[0].pvSeg, cbFrame, "--> Outgoing");
3815
3816 pThis->CTX_SUFF(pTxSg) = NULL;
3817 PPDMINETWORKUP pDrv = pThis->CTX_SUFF(pDrv);
3818 if (pDrv)
3819 {
3820 /* Release critical section to avoid deadlock in CanReceive */
3821 //e1kCsLeave(pThis);
3822 STAM_PROFILE_START(&pThis->CTX_SUFF_Z(StatTransmitSend), a);
3823 rc = pDrv->pfnSendBuf(pDrv, pSg, fOnWorkerThread);
3824 STAM_PROFILE_STOP(&pThis->CTX_SUFF_Z(StatTransmitSend), a);
3825 //e1kCsEnter(pThis, RT_SRC_POS);
3826 }
3827 }
3828 else if (pSg)
3829 {
3830 Assert(pSg->aSegs[0].pvSeg == pThis->aTxPacketFallback);
3831 e1kPacketDump(pThis, (uint8_t const *)pSg->aSegs[0].pvSeg, cbFrame, "--> Loopback");
3832
3833 /** @todo do we actually need to check that we're in loopback mode here? */
3834 if (GET_BITS(RCTL, LBM) == RCTL_LBM_TCVR)
3835 {
3836 E1KRXDST status;
3837 RT_ZERO(status);
3838 status.fPIF = true;
3839 e1kHandleRxPacket(pThis, pSg->aSegs[0].pvSeg, cbFrame, status);
3840 rc = VINF_SUCCESS;
3841 }
3842 e1kXmitFreeBuf(pThis);
3843 }
3844 else
3845 rc = VERR_NET_DOWN;
3846 if (RT_FAILURE(rc))
3847 {
3848 E1kLogRel(("E1000: ERROR! pfnSend returned %Rrc\n", rc));
3849 /** @todo handle VERR_NET_DOWN and VERR_NET_NO_BUFFER_SPACE. Signal error ? */
3850 }
3851
3852 pThis->led.Actual.s.fWriting = 0;
3853}
3854
3855/**
3856 * Compute and write internet checksum (e1kCSum16) at the specified offset.
3857 *
3858 * @param pThis The device state structure.
3859 * @param pPkt Pointer to the packet.
3860 * @param u16PktLen Total length of the packet.
3861 * @param cso Offset in packet to write checksum at.
3862 * @param css Offset in packet to start computing
3863 * checksum from.
3864 * @param cse Offset in packet to stop computing
3865 * checksum at.
3866 * @thread E1000_TX
3867 */
3868static void e1kInsertChecksum(PE1KSTATE pThis, uint8_t *pPkt, uint16_t u16PktLen, uint8_t cso, uint8_t css, uint16_t cse)
3869{
3870 if (css >= u16PktLen)
3871 {
3872 E1kLog2(("%s css(%X) is greater than packet length-1(%X), checksum is not inserted\n",
3873 pThis->szPrf, cso, u16PktLen));
3874 return;
3875 }
3876
3877 if (cso >= u16PktLen - 1)
3878 {
3879 E1kLog2(("%s cso(%X) is greater than packet length-2(%X), checksum is not inserted\n",
3880 pThis->szPrf, cso, u16PktLen));
3881 return;
3882 }
3883
3884 if (cse == 0)
3885 cse = u16PktLen - 1;
3886 uint16_t u16ChkSum = e1kCSum16(pPkt + css, cse - css + 1);
3887 E1kLog2(("%s Inserting csum: %04X at %02X, old value: %04X\n", pThis->szPrf,
3888 u16ChkSum, cso, *(uint16_t*)(pPkt + cso)));
3889 *(uint16_t*)(pPkt + cso) = u16ChkSum;
3890}
3891
3892/**
3893 * Add a part of descriptor's buffer to transmit frame.
3894 *
3895 * @remarks data.u64BufAddr is used unconditionally for both data
3896 * and legacy descriptors since it is identical to
3897 * legacy.u64BufAddr.
3898 *
3899 * @param pThis The device state structure.
3900 * @param pDesc Pointer to the descriptor to transmit.
3901 * @param u16Len Length of buffer to the end of segment.
3902 * @param fSend Force packet sending.
3903 * @param fOnWorkerThread Whether we're on a worker thread or an EMT.
3904 * @thread E1000_TX
3905 */
3906#ifndef E1K_WITH_TXD_CACHE
3907static void e1kFallbackAddSegment(PE1KSTATE pThis, RTGCPHYS PhysAddr, uint16_t u16Len, bool fSend, bool fOnWorkerThread)
3908{
3909 /* TCP header being transmitted */
3910 struct E1kTcpHeader *pTcpHdr = (struct E1kTcpHeader *)
3911 (pThis->aTxPacketFallback + pThis->contextTSE.tu.u8CSS);
3912 /* IP header being transmitted */
3913 struct E1kIpHeader *pIpHdr = (struct E1kIpHeader *)
3914 (pThis->aTxPacketFallback + pThis->contextTSE.ip.u8CSS);
3915
3916 E1kLog3(("%s e1kFallbackAddSegment: Length=%x, remaining payload=%x, header=%x, send=%RTbool\n",
3917 pThis->szPrf, u16Len, pThis->u32PayRemain, pThis->u16HdrRemain, fSend));
3918 Assert(pThis->u32PayRemain + pThis->u16HdrRemain > 0);
3919
3920 PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns), PhysAddr,
3921 pThis->aTxPacketFallback + pThis->u16TxPktLen, u16Len);
3922 E1kLog3(("%s Dump of the segment:\n"
3923 "%.*Rhxd\n"
3924 "%s --- End of dump ---\n",
3925 pThis->szPrf, u16Len, pThis->aTxPacketFallback + pThis->u16TxPktLen, pThis->szPrf));
3926 pThis->u16TxPktLen += u16Len;
3927 E1kLog3(("%s e1kFallbackAddSegment: pThis->u16TxPktLen=%x\n",
3928 pThis->szPrf, pThis->u16TxPktLen));
3929 if (pThis->u16HdrRemain > 0)
3930 {
3931 /* The header was not complete, check if it is now */
3932 if (u16Len >= pThis->u16HdrRemain)
3933 {
3934 /* The rest is payload */
3935 u16Len -= pThis->u16HdrRemain;
3936 pThis->u16HdrRemain = 0;
3937 /* Save partial checksum and flags */
3938 pThis->u32SavedCsum = pTcpHdr->chksum;
3939 pThis->u16SavedFlags = pTcpHdr->hdrlen_flags;
3940 /* Clear FIN and PSH flags now and set them only in the last segment */
3941 pTcpHdr->hdrlen_flags &= ~htons(E1K_TCP_FIN | E1K_TCP_PSH);
3942 }
3943 else
3944 {
3945 /* Still not */
3946 pThis->u16HdrRemain -= u16Len;
3947 E1kLog3(("%s e1kFallbackAddSegment: Header is still incomplete, 0x%x bytes remain.\n",
3948 pThis->szPrf, pThis->u16HdrRemain));
3949 return;
3950 }
3951 }
3952
3953 pThis->u32PayRemain -= u16Len;
3954
3955 if (fSend)
3956 {
3957 /* Leave ethernet header intact */
3958 /* IP Total Length = payload + headers - ethernet header */
3959 pIpHdr->total_len = htons(pThis->u16TxPktLen - pThis->contextTSE.ip.u8CSS);
3960 E1kLog3(("%s e1kFallbackAddSegment: End of packet, pIpHdr->total_len=%x\n",
3961 pThis->szPrf, ntohs(pIpHdr->total_len)));
3962 /* Update IP Checksum */
3963 pIpHdr->chksum = 0;
3964 e1kInsertChecksum(pThis, pThis->aTxPacketFallback, pThis->u16TxPktLen,
3965 pThis->contextTSE.ip.u8CSO,
3966 pThis->contextTSE.ip.u8CSS,
3967 pThis->contextTSE.ip.u16CSE);
3968
3969 /* Update TCP flags */
3970 /* Restore original FIN and PSH flags for the last segment */
3971 if (pThis->u32PayRemain == 0)
3972 {
3973 pTcpHdr->hdrlen_flags = pThis->u16SavedFlags;
3974 E1K_INC_CNT32(TSCTC);
3975 }
3976 /* Add TCP length to partial pseudo header sum */
3977 uint32_t csum = pThis->u32SavedCsum
3978 + htons(pThis->u16TxPktLen - pThis->contextTSE.tu.u8CSS);
3979 while (csum >> 16)
3980 csum = (csum >> 16) + (csum & 0xFFFF);
3981 pTcpHdr->chksum = csum;
3982 /* Compute final checksum */
3983 e1kInsertChecksum(pThis, pThis->aTxPacketFallback, pThis->u16TxPktLen,
3984 pThis->contextTSE.tu.u8CSO,
3985 pThis->contextTSE.tu.u8CSS,
3986 pThis->contextTSE.tu.u16CSE);
3987
3988 /*
3989 * Transmit it. If we've use the SG already, allocate a new one before
3990 * we copy of the data.
3991 */
3992 if (!pThis->CTX_SUFF(pTxSg))
3993 e1kXmitAllocBuf(pThis, pThis->u16TxPktLen + (pThis->fVTag ? 4 : 0), true /*fExactSize*/, false /*fGso*/);
3994 if (pThis->CTX_SUFF(pTxSg))
3995 {
3996 Assert(pThis->u16TxPktLen <= pThis->CTX_SUFF(pTxSg)->cbAvailable);
3997 Assert(pThis->CTX_SUFF(pTxSg)->cSegs == 1);
3998 if (pThis->CTX_SUFF(pTxSg)->aSegs[0].pvSeg != pThis->aTxPacketFallback)
3999 memcpy(pThis->CTX_SUFF(pTxSg)->aSegs[0].pvSeg, pThis->aTxPacketFallback, pThis->u16TxPktLen);
4000 pThis->CTX_SUFF(pTxSg)->cbUsed = pThis->u16TxPktLen;
4001 pThis->CTX_SUFF(pTxSg)->aSegs[0].cbSeg = pThis->u16TxPktLen;
4002 }
4003 e1kTransmitFrame(pThis, fOnWorkerThread);
4004
4005 /* Update Sequence Number */
4006 pTcpHdr->seqno = htonl(ntohl(pTcpHdr->seqno) + pThis->u16TxPktLen
4007 - pThis->contextTSE.dw3.u8HDRLEN);
4008 /* Increment IP identification */
4009 pIpHdr->ident = htons(ntohs(pIpHdr->ident) + 1);
4010 }
4011}
4012#else /* E1K_WITH_TXD_CACHE */
4013static int e1kFallbackAddSegment(PE1KSTATE pThis, RTGCPHYS PhysAddr, uint16_t u16Len, bool fSend, bool fOnWorkerThread)
4014{
4015 int rc = VINF_SUCCESS;
4016 /* TCP header being transmitted */
4017 struct E1kTcpHeader *pTcpHdr = (struct E1kTcpHeader *)
4018 (pThis->aTxPacketFallback + pThis->contextTSE.tu.u8CSS);
4019 /* IP header being transmitted */
4020 struct E1kIpHeader *pIpHdr = (struct E1kIpHeader *)
4021 (pThis->aTxPacketFallback + pThis->contextTSE.ip.u8CSS);
4022
4023 E1kLog3(("%s e1kFallbackAddSegment: Length=%x, remaining payload=%x, header=%x, send=%RTbool\n",
4024 pThis->szPrf, u16Len, pThis->u32PayRemain, pThis->u16HdrRemain, fSend));
4025 Assert(pThis->u32PayRemain + pThis->u16HdrRemain > 0);
4026
4027 PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns), PhysAddr,
4028 pThis->aTxPacketFallback + pThis->u16TxPktLen, u16Len);
4029 E1kLog3(("%s Dump of the segment:\n"
4030 "%.*Rhxd\n"
4031 "%s --- End of dump ---\n",
4032 pThis->szPrf, u16Len, pThis->aTxPacketFallback + pThis->u16TxPktLen, pThis->szPrf));
4033 pThis->u16TxPktLen += u16Len;
4034 E1kLog3(("%s e1kFallbackAddSegment: pThis->u16TxPktLen=%x\n",
4035 pThis->szPrf, pThis->u16TxPktLen));
4036 if (pThis->u16HdrRemain > 0)
4037 {
4038 /* The header was not complete, check if it is now */
4039 if (u16Len >= pThis->u16HdrRemain)
4040 {
4041 /* The rest is payload */
4042 u16Len -= pThis->u16HdrRemain;
4043 pThis->u16HdrRemain = 0;
4044 /* Save partial checksum and flags */
4045 pThis->u32SavedCsum = pTcpHdr->chksum;
4046 pThis->u16SavedFlags = pTcpHdr->hdrlen_flags;
4047 /* Clear FIN and PSH flags now and set them only in the last segment */
4048 pTcpHdr->hdrlen_flags &= ~htons(E1K_TCP_FIN | E1K_TCP_PSH);
4049 }
4050 else
4051 {
4052 /* Still not */
4053 pThis->u16HdrRemain -= u16Len;
4054 E1kLog3(("%s e1kFallbackAddSegment: Header is still incomplete, 0x%x bytes remain.\n",
4055 pThis->szPrf, pThis->u16HdrRemain));
4056 return rc;
4057 }
4058 }
4059
4060 pThis->u32PayRemain -= u16Len;
4061
4062 if (fSend)
4063 {
4064 /* Leave ethernet header intact */
4065 /* IP Total Length = payload + headers - ethernet header */
4066 pIpHdr->total_len = htons(pThis->u16TxPktLen - pThis->contextTSE.ip.u8CSS);
4067 E1kLog3(("%s e1kFallbackAddSegment: End of packet, pIpHdr->total_len=%x\n",
4068 pThis->szPrf, ntohs(pIpHdr->total_len)));
4069 /* Update IP Checksum */
4070 pIpHdr->chksum = 0;
4071 e1kInsertChecksum(pThis, pThis->aTxPacketFallback, pThis->u16TxPktLen,
4072 pThis->contextTSE.ip.u8CSO,
4073 pThis->contextTSE.ip.u8CSS,
4074 pThis->contextTSE.ip.u16CSE);
4075
4076 /* Update TCP flags */
4077 /* Restore original FIN and PSH flags for the last segment */
4078 if (pThis->u32PayRemain == 0)
4079 {
4080 pTcpHdr->hdrlen_flags = pThis->u16SavedFlags;
4081 E1K_INC_CNT32(TSCTC);
4082 }
4083 /* Add TCP length to partial pseudo header sum */
4084 uint32_t csum = pThis->u32SavedCsum
4085 + htons(pThis->u16TxPktLen - pThis->contextTSE.tu.u8CSS);
4086 while (csum >> 16)
4087 csum = (csum >> 16) + (csum & 0xFFFF);
4088 pTcpHdr->chksum = csum;
4089 /* Compute final checksum */
4090 e1kInsertChecksum(pThis, pThis->aTxPacketFallback, pThis->u16TxPktLen,
4091 pThis->contextTSE.tu.u8CSO,
4092 pThis->contextTSE.tu.u8CSS,
4093 pThis->contextTSE.tu.u16CSE);
4094
4095 /*
4096 * Transmit it.
4097 */
4098 if (pThis->CTX_SUFF(pTxSg))
4099 {
4100 Assert(pThis->u16TxPktLen <= pThis->CTX_SUFF(pTxSg)->cbAvailable);
4101 Assert(pThis->CTX_SUFF(pTxSg)->cSegs == 1);
4102 if (pThis->CTX_SUFF(pTxSg)->aSegs[0].pvSeg != pThis->aTxPacketFallback)
4103 memcpy(pThis->CTX_SUFF(pTxSg)->aSegs[0].pvSeg, pThis->aTxPacketFallback, pThis->u16TxPktLen);
4104 pThis->CTX_SUFF(pTxSg)->cbUsed = pThis->u16TxPktLen;
4105 pThis->CTX_SUFF(pTxSg)->aSegs[0].cbSeg = pThis->u16TxPktLen;
4106 }
4107 e1kTransmitFrame(pThis, fOnWorkerThread);
4108
4109 /* Update Sequence Number */
4110 pTcpHdr->seqno = htonl(ntohl(pTcpHdr->seqno) + pThis->u16TxPktLen
4111 - pThis->contextTSE.dw3.u8HDRLEN);
4112 /* Increment IP identification */
4113 pIpHdr->ident = htons(ntohs(pIpHdr->ident) + 1);
4114
4115 /* Allocate new buffer for the next segment. */
4116 if (pThis->u32PayRemain)
4117 {
4118 pThis->cbTxAlloc = RT_MIN(pThis->u32PayRemain,
4119 pThis->contextTSE.dw3.u16MSS)
4120 + pThis->contextTSE.dw3.u8HDRLEN
4121 + (pThis->fVTag ? 4 : 0);
4122 rc = e1kXmitAllocBuf(pThis, false /* fGSO */);
4123 }
4124 }
4125
4126 return rc;
4127}
4128#endif /* E1K_WITH_TXD_CACHE */
4129
4130#ifndef E1K_WITH_TXD_CACHE
4131/**
4132 * TCP segmentation offloading fallback: Add descriptor's buffer to transmit
4133 * frame.
4134 *
4135 * We construct the frame in the fallback buffer first and the copy it to the SG
4136 * buffer before passing it down to the network driver code.
4137 *
4138 * @returns true if the frame should be transmitted, false if not.
4139 *
4140 * @param pThis The device state structure.
4141 * @param pDesc Pointer to the descriptor to transmit.
4142 * @param cbFragment Length of descriptor's buffer.
4143 * @param fOnWorkerThread Whether we're on a worker thread or an EMT.
4144 * @thread E1000_TX
4145 */
4146static bool e1kFallbackAddToFrame(PE1KSTATE pThis, E1KTXDESC* pDesc, uint32_t cbFragment, bool fOnWorkerThread)
4147{
4148 PPDMSCATTERGATHER pTxSg = pThis->CTX_SUFF(pTxSg);
4149 Assert(e1kGetDescType(pDesc) == E1K_DTYP_DATA);
4150 Assert(pDesc->data.cmd.fTSE);
4151 Assert(!e1kXmitIsGsoBuf(pTxSg));
4152
4153 uint16_t u16MaxPktLen = pThis->contextTSE.dw3.u8HDRLEN + pThis->contextTSE.dw3.u16MSS;
4154 Assert(u16MaxPktLen != 0);
4155 Assert(u16MaxPktLen < E1K_MAX_TX_PKT_SIZE);
4156
4157 /*
4158 * Carve out segments.
4159 */
4160 do
4161 {
4162 /* Calculate how many bytes we have left in this TCP segment */
4163 uint32_t cb = u16MaxPktLen - pThis->u16TxPktLen;
4164 if (cb > cbFragment)
4165 {
4166 /* This descriptor fits completely into current segment */
4167 cb = cbFragment;
4168 e1kFallbackAddSegment(pThis, pDesc->data.u64BufAddr, cb, pDesc->data.cmd.fEOP /*fSend*/, fOnWorkerThread);
4169 }
4170 else
4171 {
4172 e1kFallbackAddSegment(pThis, pDesc->data.u64BufAddr, cb, true /*fSend*/, fOnWorkerThread);
4173 /*
4174 * Rewind the packet tail pointer to the beginning of payload,
4175 * so we continue writing right beyond the header.
4176 */
4177 pThis->u16TxPktLen = pThis->contextTSE.dw3.u8HDRLEN;
4178 }
4179
4180 pDesc->data.u64BufAddr += cb;
4181 cbFragment -= cb;
4182 } while (cbFragment > 0);
4183
4184 if (pDesc->data.cmd.fEOP)
4185 {
4186 /* End of packet, next segment will contain header. */
4187 if (pThis->u32PayRemain != 0)
4188 E1K_INC_CNT32(TSCTFC);
4189 pThis->u16TxPktLen = 0;
4190 e1kXmitFreeBuf(pThis);
4191 }
4192
4193 return false;
4194}
4195#else /* E1K_WITH_TXD_CACHE */
4196/**
4197 * TCP segmentation offloading fallback: Add descriptor's buffer to transmit
4198 * frame.
4199 *
4200 * We construct the frame in the fallback buffer first and the copy it to the SG
4201 * buffer before passing it down to the network driver code.
4202 *
4203 * @returns error code
4204 *
4205 * @param pThis The device state structure.
4206 * @param pDesc Pointer to the descriptor to transmit.
4207 * @param cbFragment Length of descriptor's buffer.
4208 * @param fOnWorkerThread Whether we're on a worker thread or an EMT.
4209 * @thread E1000_TX
4210 */
4211static int e1kFallbackAddToFrame(PE1KSTATE pThis, E1KTXDESC* pDesc, bool fOnWorkerThread)
4212{
4213 int rc = VINF_SUCCESS;
4214 PPDMSCATTERGATHER pTxSg = pThis->CTX_SUFF(pTxSg);
4215 Assert(e1kGetDescType(pDesc) == E1K_DTYP_DATA);
4216 Assert(pDesc->data.cmd.fTSE);
4217 Assert(!e1kXmitIsGsoBuf(pTxSg));
4218
4219 uint16_t u16MaxPktLen = pThis->contextTSE.dw3.u8HDRLEN + pThis->contextTSE.dw3.u16MSS;
4220 Assert(u16MaxPktLen != 0);
4221 Assert(u16MaxPktLen < E1K_MAX_TX_PKT_SIZE);
4222
4223 /*
4224 * Carve out segments.
4225 */
4226 do
4227 {
4228 /* Calculate how many bytes we have left in this TCP segment */
4229 uint32_t cb = u16MaxPktLen - pThis->u16TxPktLen;
4230 if (cb > pDesc->data.cmd.u20DTALEN)
4231 {
4232 /* This descriptor fits completely into current segment */
4233 cb = pDesc->data.cmd.u20DTALEN;
4234 rc = e1kFallbackAddSegment(pThis, pDesc->data.u64BufAddr, cb, pDesc->data.cmd.fEOP /*fSend*/, fOnWorkerThread);
4235 }
4236 else
4237 {
4238 rc = e1kFallbackAddSegment(pThis, pDesc->data.u64BufAddr, cb, true /*fSend*/, fOnWorkerThread);
4239 /*
4240 * Rewind the packet tail pointer to the beginning of payload,
4241 * so we continue writing right beyond the header.
4242 */
4243 pThis->u16TxPktLen = pThis->contextTSE.dw3.u8HDRLEN;
4244 }
4245
4246 pDesc->data.u64BufAddr += cb;
4247 pDesc->data.cmd.u20DTALEN -= cb;
4248 } while (pDesc->data.cmd.u20DTALEN > 0 && RT_SUCCESS(rc));
4249
4250 if (pDesc->data.cmd.fEOP)
4251 {
4252 /* End of packet, next segment will contain header. */
4253 if (pThis->u32PayRemain != 0)
4254 E1K_INC_CNT32(TSCTFC);
4255 pThis->u16TxPktLen = 0;
4256 e1kXmitFreeBuf(pThis);
4257 }
4258
4259 return false;
4260}
4261#endif /* E1K_WITH_TXD_CACHE */
4262
4263
4264/**
4265 * Add descriptor's buffer to transmit frame.
4266 *
4267 * This deals with GSO and normal frames, e1kFallbackAddToFrame deals with the
4268 * TSE frames we cannot handle as GSO.
4269 *
4270 * @returns true on success, false on failure.
4271 *
4272 * @param pThis The device state structure.
4273 * @param PhysAddr The physical address of the descriptor buffer.
4274 * @param cbFragment Length of descriptor's buffer.
4275 * @thread E1000_TX
4276 */
4277static bool e1kAddToFrame(PE1KSTATE pThis, RTGCPHYS PhysAddr, uint32_t cbFragment)
4278{
4279 PPDMSCATTERGATHER pTxSg = pThis->CTX_SUFF(pTxSg);
4280 bool const fGso = e1kXmitIsGsoBuf(pTxSg);
4281 uint32_t const cbNewPkt = cbFragment + pThis->u16TxPktLen;
4282
4283 if (RT_UNLIKELY( !fGso && cbNewPkt > E1K_MAX_TX_PKT_SIZE ))
4284 {
4285 E1kLog(("%s Transmit packet is too large: %u > %u(max)\n", pThis->szPrf, cbNewPkt, E1K_MAX_TX_PKT_SIZE));
4286 return false;
4287 }
4288 if (RT_UNLIKELY( fGso && cbNewPkt > pTxSg->cbAvailable ))
4289 {
4290 E1kLog(("%s Transmit packet is too large: %u > %u(max)/GSO\n", pThis->szPrf, cbNewPkt, pTxSg->cbAvailable));
4291 return false;
4292 }
4293
4294 if (RT_LIKELY(pTxSg))
4295 {
4296 Assert(pTxSg->cSegs == 1);
4297 Assert(pTxSg->cbUsed == pThis->u16TxPktLen);
4298
4299 PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns), PhysAddr,
4300 (uint8_t *)pTxSg->aSegs[0].pvSeg + pThis->u16TxPktLen, cbFragment);
4301
4302 pTxSg->cbUsed = cbNewPkt;
4303 }
4304 pThis->u16TxPktLen = cbNewPkt;
4305
4306 return true;
4307}
4308
4309
4310/**
4311 * Write the descriptor back to guest memory and notify the guest.
4312 *
4313 * @param pThis The device state structure.
4314 * @param pDesc Pointer to the descriptor have been transmitted.
4315 * @param addr Physical address of the descriptor in guest memory.
4316 * @thread E1000_TX
4317 */
4318static void e1kDescReport(PE1KSTATE pThis, E1KTXDESC* pDesc, RTGCPHYS addr)
4319{
4320 /*
4321 * We fake descriptor write-back bursting. Descriptors are written back as they are
4322 * processed.
4323 */
4324 /* Let's pretend we process descriptors. Write back with DD set. */
4325 /*
4326 * Prior to r71586 we tried to accomodate the case when write-back bursts
4327 * are enabled without actually implementing bursting by writing back all
4328 * descriptors, even the ones that do not have RS set. This caused kernel
4329 * panics with Linux SMP kernels, as the e1000 driver tried to free up skb
4330 * associated with written back descriptor if it happened to be a context
4331 * descriptor since context descriptors do not have skb associated to them.
4332 * Starting from r71586 we write back only the descriptors with RS set,
4333 * which is a little bit different from what the real hardware does in
4334 * case there is a chain of data descritors where some of them have RS set
4335 * and others do not. It is very uncommon scenario imho.
4336 * We need to check RPS as well since some legacy drivers use it instead of
4337 * RS even with newer cards.
4338 */
4339 if (pDesc->legacy.cmd.fRS || pDesc->legacy.cmd.fRPS)
4340 {
4341 pDesc->legacy.dw3.fDD = 1; /* Descriptor Done */
4342 e1kWriteBackDesc(pThis, pDesc, addr);
4343 if (pDesc->legacy.cmd.fEOP)
4344 {
4345#ifdef E1K_USE_TX_TIMERS
4346 if (pDesc->legacy.cmd.fIDE)
4347 {
4348 E1K_INC_ISTAT_CNT(pThis->uStatTxIDE);
4349 //if (pThis->fIntRaised)
4350 //{
4351 // /* Interrupt is already pending, no need for timers */
4352 // ICR |= ICR_TXDW;
4353 //}
4354 //else {
4355 /* Arm the timer to fire in TIVD usec (discard .024) */
4356 e1kArmTimer(pThis, pThis->CTX_SUFF(pTIDTimer), TIDV);
4357# ifndef E1K_NO_TAD
4358 /* If absolute timer delay is enabled and the timer is not running yet, arm it. */
4359 E1kLog2(("%s Checking if TAD timer is running\n",
4360 pThis->szPrf));
4361 if (TADV != 0 && !TMTimerIsActive(pThis->CTX_SUFF(pTADTimer)))
4362 e1kArmTimer(pThis, pThis->CTX_SUFF(pTADTimer), TADV);
4363# endif /* E1K_NO_TAD */
4364 }
4365 else
4366 {
4367 E1kLog2(("%s No IDE set, cancel TAD timer and raise interrupt\n",
4368 pThis->szPrf));
4369# ifndef E1K_NO_TAD
4370 /* Cancel both timers if armed and fire immediately. */
4371 e1kCancelTimer(pThis, pThis->CTX_SUFF(pTADTimer));
4372# endif /* E1K_NO_TAD */
4373#endif /* E1K_USE_TX_TIMERS */
4374 E1K_INC_ISTAT_CNT(pThis->uStatIntTx);
4375 e1kRaiseInterrupt(pThis, VERR_SEM_BUSY, ICR_TXDW);
4376#ifdef E1K_USE_TX_TIMERS
4377 }
4378#endif /* E1K_USE_TX_TIMERS */
4379 }
4380 }
4381 else
4382 {
4383 E1K_INC_ISTAT_CNT(pThis->uStatTxNoRS);
4384 }
4385}
4386
4387#ifndef E1K_WITH_TXD_CACHE
4388
4389/**
4390 * Process Transmit Descriptor.
4391 *
4392 * E1000 supports three types of transmit descriptors:
4393 * - legacy data descriptors of older format (context-less).
4394 * - data the same as legacy but providing new offloading capabilities.
4395 * - context sets up the context for following data descriptors.
4396 *
4397 * @param pThis The device state structure.
4398 * @param pDesc Pointer to descriptor union.
4399 * @param addr Physical address of descriptor in guest memory.
4400 * @param fOnWorkerThread Whether we're on a worker thread or an EMT.
4401 * @thread E1000_TX
4402 */
4403static int e1kXmitDesc(PE1KSTATE pThis, E1KTXDESC* pDesc, RTGCPHYS addr, bool fOnWorkerThread)
4404{
4405 int rc = VINF_SUCCESS;
4406 uint32_t cbVTag = 0;
4407
4408 e1kPrintTDesc(pThis, pDesc, "vvv");
4409
4410#ifdef E1K_USE_TX_TIMERS
4411 e1kCancelTimer(pThis, pThis->CTX_SUFF(pTIDTimer));
4412#endif /* E1K_USE_TX_TIMERS */
4413
4414 switch (e1kGetDescType(pDesc))
4415 {
4416 case E1K_DTYP_CONTEXT:
4417 if (pDesc->context.dw2.fTSE)
4418 {
4419 pThis->contextTSE = pDesc->context;
4420 pThis->u32PayRemain = pDesc->context.dw2.u20PAYLEN;
4421 pThis->u16HdrRemain = pDesc->context.dw3.u8HDRLEN;
4422 e1kSetupGsoCtx(&pThis->GsoCtx, &pDesc->context);
4423 STAM_COUNTER_INC(&pThis->StatTxDescCtxTSE);
4424 }
4425 else
4426 {
4427 pThis->contextNormal = pDesc->context;
4428 STAM_COUNTER_INC(&pThis->StatTxDescCtxNormal);
4429 }
4430 E1kLog2(("%s %s context updated: IP CSS=%02X, IP CSO=%02X, IP CSE=%04X"
4431 ", TU CSS=%02X, TU CSO=%02X, TU CSE=%04X\n", pThis->szPrf,
4432 pDesc->context.dw2.fTSE ? "TSE" : "Normal",
4433 pDesc->context.ip.u8CSS,
4434 pDesc->context.ip.u8CSO,
4435 pDesc->context.ip.u16CSE,
4436 pDesc->context.tu.u8CSS,
4437 pDesc->context.tu.u8CSO,
4438 pDesc->context.tu.u16CSE));
4439 E1K_INC_ISTAT_CNT(pThis->uStatDescCtx);
4440 e1kDescReport(pThis, pDesc, addr);
4441 break;
4442
4443 case E1K_DTYP_DATA:
4444 {
4445 if (pDesc->data.cmd.u20DTALEN == 0 || pDesc->data.u64BufAddr == 0)
4446 {
4447 E1kLog2(("% Empty data descriptor, skipped.\n", pThis->szPrf));
4448 /** @todo Same as legacy when !TSE. See below. */
4449 break;
4450 }
4451 STAM_COUNTER_INC(pDesc->data.cmd.fTSE?
4452 &pThis->StatTxDescTSEData:
4453 &pThis->StatTxDescData);
4454 STAM_PROFILE_ADV_START(&pThis->CTX_SUFF_Z(StatTransmit), a);
4455 E1K_INC_ISTAT_CNT(pThis->uStatDescDat);
4456
4457 /*
4458 * The last descriptor of non-TSE packet must contain VLE flag.
4459 * TSE packets have VLE flag in the first descriptor. The later
4460 * case is taken care of a bit later when cbVTag gets assigned.
4461 *
4462 * 1) pDesc->data.cmd.fEOP && !pDesc->data.cmd.fTSE
4463 */
4464 if (pDesc->data.cmd.fEOP && !pDesc->data.cmd.fTSE)
4465 {
4466 pThis->fVTag = pDesc->data.cmd.fVLE;
4467 pThis->u16VTagTCI = pDesc->data.dw3.u16Special;
4468 }
4469 /*
4470 * First fragment: Allocate new buffer and save the IXSM and TXSM
4471 * packet options as these are only valid in the first fragment.
4472 */
4473 if (pThis->u16TxPktLen == 0)
4474 {
4475 pThis->fIPcsum = pDesc->data.dw3.fIXSM;
4476 pThis->fTCPcsum = pDesc->data.dw3.fTXSM;
4477 E1kLog2(("%s Saving checksum flags:%s%s; \n", pThis->szPrf,
4478 pThis->fIPcsum ? " IP" : "",
4479 pThis->fTCPcsum ? " TCP/UDP" : ""));
4480 if (pDesc->data.cmd.fTSE)
4481 {
4482 /* 2) pDesc->data.cmd.fTSE && pThis->u16TxPktLen == 0 */
4483 pThis->fVTag = pDesc->data.cmd.fVLE;
4484 pThis->u16VTagTCI = pDesc->data.dw3.u16Special;
4485 cbVTag = pThis->fVTag ? 4 : 0;
4486 }
4487 else if (pDesc->data.cmd.fEOP)
4488 cbVTag = pDesc->data.cmd.fVLE ? 4 : 0;
4489 else
4490 cbVTag = 4;
4491 E1kLog3(("%s About to allocate TX buffer: cbVTag=%u\n", pThis->szPrf, cbVTag));
4492 if (e1kCanDoGso(pThis, &pThis->GsoCtx, &pDesc->data, &pThis->contextTSE))
4493 rc = e1kXmitAllocBuf(pThis, pThis->contextTSE.dw2.u20PAYLEN + pThis->contextTSE.dw3.u8HDRLEN + cbVTag,
4494 true /*fExactSize*/, true /*fGso*/);
4495 else if (pDesc->data.cmd.fTSE)
4496 rc = e1kXmitAllocBuf(pThis, pThis->contextTSE.dw3.u16MSS + pThis->contextTSE.dw3.u8HDRLEN + cbVTag,
4497 pDesc->data.cmd.fTSE /*fExactSize*/, false /*fGso*/);
4498 else
4499 rc = e1kXmitAllocBuf(pThis, pDesc->data.cmd.u20DTALEN + cbVTag,
4500 pDesc->data.cmd.fEOP /*fExactSize*/, false /*fGso*/);
4501
4502 /**
4503 * @todo: Perhaps it is not that simple for GSO packets! We may
4504 * need to unwind some changes.
4505 */
4506 if (RT_FAILURE(rc))
4507 {
4508 STAM_PROFILE_ADV_STOP(&pThis->CTX_SUFF_Z(StatTransmit), a);
4509 break;
4510 }
4511 /** @todo Is there any way to indicating errors other than collisions? Like
4512 * VERR_NET_DOWN. */
4513 }
4514
4515 /*
4516 * Add the descriptor data to the frame. If the frame is complete,
4517 * transmit it and reset the u16TxPktLen field.
4518 */
4519 if (e1kXmitIsGsoBuf(pThis->CTX_SUFF(pTxSg)))
4520 {
4521 STAM_COUNTER_INC(&pThis->StatTxPathGSO);
4522 bool fRc = e1kAddToFrame(pThis, pDesc->data.u64BufAddr, pDesc->data.cmd.u20DTALEN);
4523 if (pDesc->data.cmd.fEOP)
4524 {
4525 if ( fRc
4526 && pThis->CTX_SUFF(pTxSg)
4527 && pThis->CTX_SUFF(pTxSg)->cbUsed == (size_t)pThis->contextTSE.dw3.u8HDRLEN + pThis->contextTSE.dw2.u20PAYLEN)
4528 {
4529 e1kTransmitFrame(pThis, fOnWorkerThread);
4530 E1K_INC_CNT32(TSCTC);
4531 }
4532 else
4533 {
4534 if (fRc)
4535 E1kLog(("%s bad GSO/TSE %p or %u < %u\n" , pThis->szPrf,
4536 pThis->CTX_SUFF(pTxSg), pThis->CTX_SUFF(pTxSg) ? pThis->CTX_SUFF(pTxSg)->cbUsed : 0,
4537 pThis->contextTSE.dw3.u8HDRLEN + pThis->contextTSE.dw2.u20PAYLEN));
4538 e1kXmitFreeBuf(pThis);
4539 E1K_INC_CNT32(TSCTFC);
4540 }
4541 pThis->u16TxPktLen = 0;
4542 }
4543 }
4544 else if (!pDesc->data.cmd.fTSE)
4545 {
4546 STAM_COUNTER_INC(&pThis->StatTxPathRegular);
4547 bool fRc = e1kAddToFrame(pThis, pDesc->data.u64BufAddr, pDesc->data.cmd.u20DTALEN);
4548 if (pDesc->data.cmd.fEOP)
4549 {
4550 if (fRc && pThis->CTX_SUFF(pTxSg))
4551 {
4552 Assert(pThis->CTX_SUFF(pTxSg)->cSegs == 1);
4553 if (pThis->fIPcsum)
4554 e1kInsertChecksum(pThis, (uint8_t *)pThis->CTX_SUFF(pTxSg)->aSegs[0].pvSeg, pThis->u16TxPktLen,
4555 pThis->contextNormal.ip.u8CSO,
4556 pThis->contextNormal.ip.u8CSS,
4557 pThis->contextNormal.ip.u16CSE);
4558 if (pThis->fTCPcsum)
4559 e1kInsertChecksum(pThis, (uint8_t *)pThis->CTX_SUFF(pTxSg)->aSegs[0].pvSeg, pThis->u16TxPktLen,
4560 pThis->contextNormal.tu.u8CSO,
4561 pThis->contextNormal.tu.u8CSS,
4562 pThis->contextNormal.tu.u16CSE);
4563 e1kTransmitFrame(pThis, fOnWorkerThread);
4564 }
4565 else
4566 e1kXmitFreeBuf(pThis);
4567 pThis->u16TxPktLen = 0;
4568 }
4569 }
4570 else
4571 {
4572 STAM_COUNTER_INC(&pThis->StatTxPathFallback);
4573 e1kFallbackAddToFrame(pThis, pDesc, pDesc->data.cmd.u20DTALEN, fOnWorkerThread);
4574 }
4575
4576 e1kDescReport(pThis, pDesc, addr);
4577 STAM_PROFILE_ADV_STOP(&pThis->CTX_SUFF_Z(StatTransmit), a);
4578 break;
4579 }
4580
4581 case E1K_DTYP_LEGACY:
4582 if (pDesc->legacy.cmd.u16Length == 0 || pDesc->legacy.u64BufAddr == 0)
4583 {
4584 E1kLog(("%s Empty legacy descriptor, skipped.\n", pThis->szPrf));
4585 /** @todo 3.3.3, Length/Buffer Address: RS set -> write DD when processing. */
4586 break;
4587 }
4588 STAM_COUNTER_INC(&pThis->StatTxDescLegacy);
4589 STAM_PROFILE_ADV_START(&pThis->CTX_SUFF_Z(StatTransmit), a);
4590
4591 /* First fragment: allocate new buffer. */
4592 if (pThis->u16TxPktLen == 0)
4593 {
4594 if (pDesc->legacy.cmd.fEOP)
4595 cbVTag = pDesc->legacy.cmd.fVLE ? 4 : 0;
4596 else
4597 cbVTag = 4;
4598 E1kLog3(("%s About to allocate TX buffer: cbVTag=%u\n", pThis->szPrf, cbVTag));
4599 /** @todo reset status bits? */
4600 rc = e1kXmitAllocBuf(pThis, pDesc->legacy.cmd.u16Length + cbVTag, pDesc->legacy.cmd.fEOP, false /*fGso*/);
4601 if (RT_FAILURE(rc))
4602 {
4603 STAM_PROFILE_ADV_STOP(&pThis->CTX_SUFF_Z(StatTransmit), a);
4604 break;
4605 }
4606
4607 /** @todo Is there any way to indicating errors other than collisions? Like
4608 * VERR_NET_DOWN. */
4609 }
4610
4611 /* Add fragment to frame. */
4612 if (e1kAddToFrame(pThis, pDesc->data.u64BufAddr, pDesc->legacy.cmd.u16Length))
4613 {
4614 E1K_INC_ISTAT_CNT(pThis->uStatDescLeg);
4615
4616 /* Last fragment: Transmit and reset the packet storage counter. */
4617 if (pDesc->legacy.cmd.fEOP)
4618 {
4619 pThis->fVTag = pDesc->legacy.cmd.fVLE;
4620 pThis->u16VTagTCI = pDesc->legacy.dw3.u16Special;
4621 /** @todo Offload processing goes here. */
4622 e1kTransmitFrame(pThis, fOnWorkerThread);
4623 pThis->u16TxPktLen = 0;
4624 }
4625 }
4626 /* Last fragment + failure: free the buffer and reset the storage counter. */
4627 else if (pDesc->legacy.cmd.fEOP)
4628 {
4629 e1kXmitFreeBuf(pThis);
4630 pThis->u16TxPktLen = 0;
4631 }
4632
4633 e1kDescReport(pThis, pDesc, addr);
4634 STAM_PROFILE_ADV_STOP(&pThis->CTX_SUFF_Z(StatTransmit), a);
4635 break;
4636
4637 default:
4638 E1kLog(("%s ERROR Unsupported transmit descriptor type: 0x%04x\n",
4639 pThis->szPrf, e1kGetDescType(pDesc)));
4640 break;
4641 }
4642
4643 return rc;
4644}
4645
4646#else /* E1K_WITH_TXD_CACHE */
4647
4648/**
4649 * Process Transmit Descriptor.
4650 *
4651 * E1000 supports three types of transmit descriptors:
4652 * - legacy data descriptors of older format (context-less).
4653 * - data the same as legacy but providing new offloading capabilities.
4654 * - context sets up the context for following data descriptors.
4655 *
4656 * @param pThis The device state structure.
4657 * @param pDesc Pointer to descriptor union.
4658 * @param addr Physical address of descriptor in guest memory.
4659 * @param fOnWorkerThread Whether we're on a worker thread or an EMT.
4660 * @param cbPacketSize Size of the packet as previously computed.
4661 * @thread E1000_TX
4662 */
4663static int e1kXmitDesc(PE1KSTATE pThis, E1KTXDESC* pDesc, RTGCPHYS addr,
4664 bool fOnWorkerThread)
4665{
4666 int rc = VINF_SUCCESS;
4667 uint32_t cbVTag = 0;
4668
4669 e1kPrintTDesc(pThis, pDesc, "vvv");
4670
4671#ifdef E1K_USE_TX_TIMERS
4672 e1kCancelTimer(pThis, pThis->CTX_SUFF(pTIDTimer));
4673#endif /* E1K_USE_TX_TIMERS */
4674
4675 switch (e1kGetDescType(pDesc))
4676 {
4677 case E1K_DTYP_CONTEXT:
4678 /* The caller have already updated the context */
4679 E1K_INC_ISTAT_CNT(pThis->uStatDescCtx);
4680 e1kDescReport(pThis, pDesc, addr);
4681 break;
4682
4683 case E1K_DTYP_DATA:
4684 {
4685 STAM_COUNTER_INC(pDesc->data.cmd.fTSE?
4686 &pThis->StatTxDescTSEData:
4687 &pThis->StatTxDescData);
4688 E1K_INC_ISTAT_CNT(pThis->uStatDescDat);
4689 STAM_PROFILE_ADV_START(&pThis->CTX_SUFF_Z(StatTransmit), a);
4690 if (pDesc->data.cmd.u20DTALEN == 0 || pDesc->data.u64BufAddr == 0)
4691 {
4692 E1kLog2(("% Empty data descriptor, skipped.\n", pThis->szPrf));
4693 }
4694 else
4695 {
4696 /*
4697 * Add the descriptor data to the frame. If the frame is complete,
4698 * transmit it and reset the u16TxPktLen field.
4699 */
4700 if (e1kXmitIsGsoBuf(pThis->CTX_SUFF(pTxSg)))
4701 {
4702 STAM_COUNTER_INC(&pThis->StatTxPathGSO);
4703 bool fRc = e1kAddToFrame(pThis, pDesc->data.u64BufAddr, pDesc->data.cmd.u20DTALEN);
4704 if (pDesc->data.cmd.fEOP)
4705 {
4706 if ( fRc
4707 && pThis->CTX_SUFF(pTxSg)
4708 && pThis->CTX_SUFF(pTxSg)->cbUsed == (size_t)pThis->contextTSE.dw3.u8HDRLEN + pThis->contextTSE.dw2.u20PAYLEN)
4709 {
4710 e1kTransmitFrame(pThis, fOnWorkerThread);
4711 E1K_INC_CNT32(TSCTC);
4712 }
4713 else
4714 {
4715 if (fRc)
4716 E1kLog(("%s bad GSO/TSE %p or %u < %u\n" , pThis->szPrf,
4717 pThis->CTX_SUFF(pTxSg), pThis->CTX_SUFF(pTxSg) ? pThis->CTX_SUFF(pTxSg)->cbUsed : 0,
4718 pThis->contextTSE.dw3.u8HDRLEN + pThis->contextTSE.dw2.u20PAYLEN));
4719 e1kXmitFreeBuf(pThis);
4720 E1K_INC_CNT32(TSCTFC);
4721 }
4722 pThis->u16TxPktLen = 0;
4723 }
4724 }
4725 else if (!pDesc->data.cmd.fTSE)
4726 {
4727 STAM_COUNTER_INC(&pThis->StatTxPathRegular);
4728 bool fRc = e1kAddToFrame(pThis, pDesc->data.u64BufAddr, pDesc->data.cmd.u20DTALEN);
4729 if (pDesc->data.cmd.fEOP)
4730 {
4731 if (fRc && pThis->CTX_SUFF(pTxSg))
4732 {
4733 Assert(pThis->CTX_SUFF(pTxSg)->cSegs == 1);
4734 if (pThis->fIPcsum)
4735 e1kInsertChecksum(pThis, (uint8_t *)pThis->CTX_SUFF(pTxSg)->aSegs[0].pvSeg, pThis->u16TxPktLen,
4736 pThis->contextNormal.ip.u8CSO,
4737 pThis->contextNormal.ip.u8CSS,
4738 pThis->contextNormal.ip.u16CSE);
4739 if (pThis->fTCPcsum)
4740 e1kInsertChecksum(pThis, (uint8_t *)pThis->CTX_SUFF(pTxSg)->aSegs[0].pvSeg, pThis->u16TxPktLen,
4741 pThis->contextNormal.tu.u8CSO,
4742 pThis->contextNormal.tu.u8CSS,
4743 pThis->contextNormal.tu.u16CSE);
4744 e1kTransmitFrame(pThis, fOnWorkerThread);
4745 }
4746 else
4747 e1kXmitFreeBuf(pThis);
4748 pThis->u16TxPktLen = 0;
4749 }
4750 }
4751 else
4752 {
4753 STAM_COUNTER_INC(&pThis->StatTxPathFallback);
4754 rc = e1kFallbackAddToFrame(pThis, pDesc, fOnWorkerThread);
4755 }
4756 }
4757 e1kDescReport(pThis, pDesc, addr);
4758 STAM_PROFILE_ADV_STOP(&pThis->CTX_SUFF_Z(StatTransmit), a);
4759 break;
4760 }
4761
4762 case E1K_DTYP_LEGACY:
4763 STAM_COUNTER_INC(&pThis->StatTxDescLegacy);
4764 STAM_PROFILE_ADV_START(&pThis->CTX_SUFF_Z(StatTransmit), a);
4765 if (pDesc->legacy.cmd.u16Length == 0 || pDesc->legacy.u64BufAddr == 0)
4766 {
4767 E1kLog(("%s Empty legacy descriptor, skipped.\n", pThis->szPrf));
4768 }
4769 else
4770 {
4771 /* Add fragment to frame. */
4772 if (e1kAddToFrame(pThis, pDesc->data.u64BufAddr, pDesc->legacy.cmd.u16Length))
4773 {
4774 E1K_INC_ISTAT_CNT(pThis->uStatDescLeg);
4775
4776 /* Last fragment: Transmit and reset the packet storage counter. */
4777 if (pDesc->legacy.cmd.fEOP)
4778 {
4779 if (pDesc->legacy.cmd.fIC)
4780 {
4781 e1kInsertChecksum(pThis,
4782 (uint8_t *)pThis->CTX_SUFF(pTxSg)->aSegs[0].pvSeg,
4783 pThis->u16TxPktLen,
4784 pDesc->legacy.cmd.u8CSO,
4785 pDesc->legacy.dw3.u8CSS,
4786 0);
4787 }
4788 e1kTransmitFrame(pThis, fOnWorkerThread);
4789 pThis->u16TxPktLen = 0;
4790 }
4791 }
4792 /* Last fragment + failure: free the buffer and reset the storage counter. */
4793 else if (pDesc->legacy.cmd.fEOP)
4794 {
4795 e1kXmitFreeBuf(pThis);
4796 pThis->u16TxPktLen = 0;
4797 }
4798 }
4799 e1kDescReport(pThis, pDesc, addr);
4800 STAM_PROFILE_ADV_STOP(&pThis->CTX_SUFF_Z(StatTransmit), a);
4801 break;
4802
4803 default:
4804 E1kLog(("%s ERROR Unsupported transmit descriptor type: 0x%04x\n",
4805 pThis->szPrf, e1kGetDescType(pDesc)));
4806 break;
4807 }
4808
4809 return rc;
4810}
4811
4812DECLINLINE(void) e1kUpdateTxContext(PE1KSTATE pThis, E1KTXDESC* pDesc)
4813{
4814 if (pDesc->context.dw2.fTSE)
4815 {
4816 pThis->contextTSE = pDesc->context;
4817 pThis->u32PayRemain = pDesc->context.dw2.u20PAYLEN;
4818 pThis->u16HdrRemain = pDesc->context.dw3.u8HDRLEN;
4819 e1kSetupGsoCtx(&pThis->GsoCtx, &pDesc->context);
4820 STAM_COUNTER_INC(&pThis->StatTxDescCtxTSE);
4821 }
4822 else
4823 {
4824 pThis->contextNormal = pDesc->context;
4825 STAM_COUNTER_INC(&pThis->StatTxDescCtxNormal);
4826 }
4827 E1kLog2(("%s %s context updated: IP CSS=%02X, IP CSO=%02X, IP CSE=%04X"
4828 ", TU CSS=%02X, TU CSO=%02X, TU CSE=%04X\n", pThis->szPrf,
4829 pDesc->context.dw2.fTSE ? "TSE" : "Normal",
4830 pDesc->context.ip.u8CSS,
4831 pDesc->context.ip.u8CSO,
4832 pDesc->context.ip.u16CSE,
4833 pDesc->context.tu.u8CSS,
4834 pDesc->context.tu.u8CSO,
4835 pDesc->context.tu.u16CSE));
4836}
4837
4838static bool e1kLocateTxPacket(PE1KSTATE pThis)
4839{
4840 LogFlow(("%s e1kLocateTxPacket: ENTER cbTxAlloc=%d\n",
4841 pThis->szPrf, pThis->cbTxAlloc));
4842 /* Check if we have located the packet already. */
4843 if (pThis->cbTxAlloc)
4844 {
4845 LogFlow(("%s e1kLocateTxPacket: RET true cbTxAlloc=%d\n",
4846 pThis->szPrf, pThis->cbTxAlloc));
4847 return true;
4848 }
4849
4850 bool fTSE = false;
4851 uint32_t cbPacket = 0;
4852
4853 for (int i = pThis->iTxDCurrent; i < pThis->nTxDFetched; ++i)
4854 {
4855 E1KTXDESC *pDesc = &pThis->aTxDescriptors[i];
4856 switch (e1kGetDescType(pDesc))
4857 {
4858 case E1K_DTYP_CONTEXT:
4859 e1kUpdateTxContext(pThis, pDesc);
4860 continue;
4861 case E1K_DTYP_LEGACY:
4862 /* Skip empty descriptors. */
4863 if (!pDesc->legacy.u64BufAddr || !pDesc->legacy.cmd.u16Length)
4864 break;
4865 cbPacket += pDesc->legacy.cmd.u16Length;
4866 pThis->fGSO = false;
4867 break;
4868 case E1K_DTYP_DATA:
4869 /* Skip empty descriptors. */
4870 if (!pDesc->data.u64BufAddr || !pDesc->data.cmd.u20DTALEN)
4871 break;
4872 if (cbPacket == 0)
4873 {
4874 /*
4875 * The first fragment: save IXSM and TXSM options
4876 * as these are only valid in the first fragment.
4877 */
4878 pThis->fIPcsum = pDesc->data.dw3.fIXSM;
4879 pThis->fTCPcsum = pDesc->data.dw3.fTXSM;
4880 fTSE = pDesc->data.cmd.fTSE;
4881 /*
4882 * TSE descriptors have VLE bit properly set in
4883 * the first fragment.
4884 */
4885 if (fTSE)
4886 {
4887 pThis->fVTag = pDesc->data.cmd.fVLE;
4888 pThis->u16VTagTCI = pDesc->data.dw3.u16Special;
4889 }
4890 pThis->fGSO = e1kCanDoGso(pThis, &pThis->GsoCtx, &pDesc->data, &pThis->contextTSE);
4891 }
4892 cbPacket += pDesc->data.cmd.u20DTALEN;
4893 break;
4894 default:
4895 AssertMsgFailed(("Impossible descriptor type!"));
4896 }
4897 if (pDesc->legacy.cmd.fEOP)
4898 {
4899 /*
4900 * Non-TSE descriptors have VLE bit properly set in
4901 * the last fragment.
4902 */
4903 if (!fTSE)
4904 {
4905 pThis->fVTag = pDesc->data.cmd.fVLE;
4906 pThis->u16VTagTCI = pDesc->data.dw3.u16Special;
4907 }
4908 /*
4909 * Compute the required buffer size. If we cannot do GSO but still
4910 * have to do segmentation we allocate the first segment only.
4911 */
4912 pThis->cbTxAlloc = (!fTSE || pThis->fGSO) ?
4913 cbPacket :
4914 RT_MIN(cbPacket, pThis->contextTSE.dw3.u16MSS + pThis->contextTSE.dw3.u8HDRLEN);
4915 if (pThis->fVTag)
4916 pThis->cbTxAlloc += 4;
4917 LogFlow(("%s e1kLocateTxPacket: RET true cbTxAlloc=%d\n",
4918 pThis->szPrf, pThis->cbTxAlloc));
4919 return true;
4920 }
4921 }
4922
4923 if (cbPacket == 0 && pThis->nTxDFetched - pThis->iTxDCurrent > 0)
4924 {
4925 /* All descriptors were empty, we need to process them as a dummy packet */
4926 LogFlow(("%s e1kLocateTxPacket: RET true cbTxAlloc=%d, zero packet!\n",
4927 pThis->szPrf, pThis->cbTxAlloc));
4928 return true;
4929 }
4930 LogFlow(("%s e1kLocateTxPacket: RET false cbTxAlloc=%d\n",
4931 pThis->szPrf, pThis->cbTxAlloc));
4932 return false;
4933}
4934
4935static int e1kXmitPacket(PE1KSTATE pThis, bool fOnWorkerThread)
4936{
4937 int rc = VINF_SUCCESS;
4938
4939 LogFlow(("%s e1kXmitPacket: ENTER current=%d fetched=%d\n",
4940 pThis->szPrf, pThis->iTxDCurrent, pThis->nTxDFetched));
4941
4942 while (pThis->iTxDCurrent < pThis->nTxDFetched)
4943 {
4944 E1KTXDESC *pDesc = &pThis->aTxDescriptors[pThis->iTxDCurrent];
4945 E1kLog3(("%s About to process new TX descriptor at %08x%08x, TDLEN=%08x, TDH=%08x, TDT=%08x\n",
4946 pThis->szPrf, TDBAH, TDBAL + TDH * sizeof(E1KTXDESC), TDLEN, TDH, TDT));
4947 rc = e1kXmitDesc(pThis, pDesc, e1kDescAddr(TDBAH, TDBAL, TDH), fOnWorkerThread);
4948 if (RT_FAILURE(rc))
4949 break;
4950 if (++TDH * sizeof(E1KTXDESC) >= TDLEN)
4951 TDH = 0;
4952 uint32_t uLowThreshold = GET_BITS(TXDCTL, LWTHRESH)*8;
4953 if (uLowThreshold != 0 && e1kGetTxLen(pThis) <= uLowThreshold)
4954 {
4955 E1kLog2(("%s Low on transmit descriptors, raise ICR.TXD_LOW, len=%x thresh=%x\n",
4956 pThis->szPrf, e1kGetTxLen(pThis), GET_BITS(TXDCTL, LWTHRESH)*8));
4957 e1kRaiseInterrupt(pThis, VERR_SEM_BUSY, ICR_TXD_LOW);
4958 }
4959 ++pThis->iTxDCurrent;
4960 if (e1kGetDescType(pDesc) != E1K_DTYP_CONTEXT && pDesc->legacy.cmd.fEOP)
4961 break;
4962 }
4963
4964 LogFlow(("%s e1kXmitPacket: RET %Rrc current=%d fetched=%d\n",
4965 pThis->szPrf, rc, pThis->iTxDCurrent, pThis->nTxDFetched));
4966 return rc;
4967}
4968
4969#endif /* E1K_WITH_TXD_CACHE */
4970#ifndef E1K_WITH_TXD_CACHE
4971
4972/**
4973 * Transmit pending descriptors.
4974 *
4975 * @returns VBox status code. VERR_TRY_AGAIN is returned if we're busy.
4976 *
4977 * @param pThis The E1000 state.
4978 * @param fOnWorkerThread Whether we're on a worker thread or on an EMT.
4979 */
4980static int e1kXmitPending(PE1KSTATE pThis, bool fOnWorkerThread)
4981{
4982 int rc = VINF_SUCCESS;
4983
4984 /* Check if transmitter is enabled. */
4985 if (!(TCTL & TCTL_EN))
4986 return VINF_SUCCESS;
4987 /*
4988 * Grab the xmit lock of the driver as well as the E1K device state.
4989 */
4990 rc = e1kCsTxEnter(pThis, VERR_SEM_BUSY);
4991 if (RT_LIKELY(rc == VINF_SUCCESS))
4992 {
4993 PPDMINETWORKUP pDrv = pThis->CTX_SUFF(pDrv);
4994 if (pDrv)
4995 {
4996 rc = pDrv->pfnBeginXmit(pDrv, fOnWorkerThread);
4997 if (RT_FAILURE(rc))
4998 {
4999 e1kCsTxLeave(pThis);
5000 return rc;
5001 }
5002 }
5003 /*
5004 * Process all pending descriptors.
5005 * Note! Do not process descriptors in locked state
5006 */
5007 while (TDH != TDT && !pThis->fLocked)
5008 {
5009 E1KTXDESC desc;
5010 E1kLog3(("%s About to process new TX descriptor at %08x%08x, TDLEN=%08x, TDH=%08x, TDT=%08x\n",
5011 pThis->szPrf, TDBAH, TDBAL + TDH * sizeof(desc), TDLEN, TDH, TDT));
5012
5013 e1kLoadDesc(pThis, &desc, ((uint64_t)TDBAH << 32) + TDBAL + TDH * sizeof(desc));
5014 rc = e1kXmitDesc(pThis, &desc, e1kDescAddr(TDBAH, TDBAL, TDH), fOnWorkerThread);
5015 /* If we failed to transmit descriptor we will try it again later */
5016 if (RT_FAILURE(rc))
5017 break;
5018 if (++TDH * sizeof(desc) >= TDLEN)
5019 TDH = 0;
5020
5021 if (e1kGetTxLen(pThis) <= GET_BITS(TXDCTL, LWTHRESH)*8)
5022 {
5023 E1kLog2(("%s Low on transmit descriptors, raise ICR.TXD_LOW, len=%x thresh=%x\n",
5024 pThis->szPrf, e1kGetTxLen(pThis), GET_BITS(TXDCTL, LWTHRESH)*8));
5025 e1kRaiseInterrupt(pThis, VERR_SEM_BUSY, ICR_TXD_LOW);
5026 }
5027
5028 STAM_PROFILE_ADV_STOP(&pThis->CTX_SUFF_Z(StatTransmit), a);
5029 }
5030
5031 /// @todo: uncomment: pThis->uStatIntTXQE++;
5032 /// @todo: uncomment: e1kRaiseInterrupt(pThis, ICR_TXQE);
5033 /*
5034 * Release the lock.
5035 */
5036 if (pDrv)
5037 pDrv->pfnEndXmit(pDrv);
5038 e1kCsTxLeave(pThis);
5039 }
5040
5041 return rc;
5042}
5043
5044#else /* E1K_WITH_TXD_CACHE */
5045
5046static void e1kDumpTxDCache(PE1KSTATE pThis)
5047{
5048 unsigned i, cDescs = TDLEN / sizeof(E1KTXDESC);
5049 uint32_t tdh = TDH;
5050 LogRel(("-- Transmit Descriptors (%d total) --\n", cDescs));
5051 for (i = 0; i < cDescs; ++i)
5052 {
5053 E1KTXDESC desc;
5054 PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns), e1kDescAddr(TDBAH, TDBAL, i),
5055 &desc, sizeof(desc));
5056 if (i == tdh)
5057 LogRel((">>> "));
5058 LogRel(("%RGp: %R[e1ktxd]\n", e1kDescAddr(TDBAH, TDBAL, i), &desc));
5059 }
5060 LogRel(("-- Transmit Descriptors in Cache (at %d (TDH %d)/ fetched %d / max %d) --\n",
5061 pThis->iTxDCurrent, TDH, pThis->nTxDFetched, E1K_TXD_CACHE_SIZE));
5062 if (tdh > pThis->iTxDCurrent)
5063 tdh -= pThis->iTxDCurrent;
5064 else
5065 tdh = cDescs + tdh - pThis->iTxDCurrent;
5066 for (i = 0; i < pThis->nTxDFetched; ++i)
5067 {
5068 if (i == pThis->iTxDCurrent)
5069 LogRel((">>> "));
5070 LogRel(("%RGp: %R[e1ktxd]\n", e1kDescAddr(TDBAH, TDBAL, tdh++ % cDescs), &pThis->aTxDescriptors[i]));
5071 }
5072}
5073
5074/**
5075 * Transmit pending descriptors.
5076 *
5077 * @returns VBox status code. VERR_TRY_AGAIN is returned if we're busy.
5078 *
5079 * @param pThis The E1000 state.
5080 * @param fOnWorkerThread Whether we're on a worker thread or on an EMT.
5081 */
5082static int e1kXmitPending(PE1KSTATE pThis, bool fOnWorkerThread)
5083{
5084 int rc = VINF_SUCCESS;
5085
5086 /* Check if transmitter is enabled. */
5087 if (!(TCTL & TCTL_EN))
5088 return VINF_SUCCESS;
5089 /*
5090 * Grab the xmit lock of the driver as well as the E1K device state.
5091 */
5092 PPDMINETWORKUP pDrv = pThis->CTX_SUFF(pDrv);
5093 if (pDrv)
5094 {
5095 rc = pDrv->pfnBeginXmit(pDrv, fOnWorkerThread);
5096 if (RT_FAILURE(rc))
5097 return rc;
5098 }
5099
5100 /*
5101 * Process all pending descriptors.
5102 * Note! Do not process descriptors in locked state
5103 */
5104 rc = e1kCsTxEnter(pThis, VERR_SEM_BUSY);
5105 if (RT_LIKELY(rc == VINF_SUCCESS))
5106 {
5107 STAM_PROFILE_ADV_START(&pThis->CTX_SUFF_Z(StatTransmit), a);
5108 /*
5109 * fIncomplete is set whenever we try to fetch additional descriptors
5110 * for an incomplete packet. If fail to locate a complete packet on
5111 * the next iteration we need to reset the cache or we risk to get
5112 * stuck in this loop forever.
5113 */
5114 bool fIncomplete = false;
5115 while (!pThis->fLocked && e1kTxDLazyLoad(pThis))
5116 {
5117 while (e1kLocateTxPacket(pThis))
5118 {
5119 fIncomplete = false;
5120 /* Found a complete packet, allocate it. */
5121 rc = e1kXmitAllocBuf(pThis, pThis->fGSO);
5122 /* If we're out of bandwidth we'll come back later. */
5123 if (RT_FAILURE(rc))
5124 goto out;
5125 /* Copy the packet to allocated buffer and send it. */
5126 rc = e1kXmitPacket(pThis, fOnWorkerThread);
5127 /* If we're out of bandwidth we'll come back later. */
5128 if (RT_FAILURE(rc))
5129 goto out;
5130 }
5131 uint8_t u8Remain = pThis->nTxDFetched - pThis->iTxDCurrent;
5132 if (RT_UNLIKELY(fIncomplete))
5133 {
5134 static bool fTxDCacheDumped = false;
5135 /*
5136 * The descriptor cache is full, but we were unable to find
5137 * a complete packet in it. Drop the cache and hope that
5138 * the guest driver can recover from network card error.
5139 */
5140 LogRel(("%s No complete packets in%s TxD cache! "
5141 "Fetched=%d, current=%d, TX len=%d.\n",
5142 pThis->szPrf,
5143 u8Remain == E1K_TXD_CACHE_SIZE ? " full" : "",
5144 pThis->nTxDFetched, pThis->iTxDCurrent,
5145 e1kGetTxLen(pThis)));
5146 if (!fTxDCacheDumped)
5147 {
5148 fTxDCacheDumped = true;
5149 e1kDumpTxDCache(pThis);
5150 }
5151 pThis->iTxDCurrent = pThis->nTxDFetched = 0;
5152 /*
5153 * Returning an error at this point means Guru in R0
5154 * (see @bugref{6428}).
5155 */
5156# ifdef IN_RING3
5157 rc = VERR_NET_INCOMPLETE_TX_PACKET;
5158# else /* !IN_RING3 */
5159 rc = VINF_IOM_R3_IOPORT_WRITE;
5160# endif /* !IN_RING3 */
5161 goto out;
5162 }
5163 if (u8Remain > 0)
5164 {
5165 Log4(("%s Incomplete packet at %d. Already fetched %d, "
5166 "%d more are available\n",
5167 pThis->szPrf, pThis->iTxDCurrent, u8Remain,
5168 e1kGetTxLen(pThis) - u8Remain));
5169
5170 /*
5171 * A packet was partially fetched. Move incomplete packet to
5172 * the beginning of cache buffer, then load more descriptors.
5173 */
5174 memmove(pThis->aTxDescriptors,
5175 &pThis->aTxDescriptors[pThis->iTxDCurrent],
5176 u8Remain * sizeof(E1KTXDESC));
5177 pThis->iTxDCurrent = 0;
5178 pThis->nTxDFetched = u8Remain;
5179 e1kTxDLoadMore(pThis);
5180 fIncomplete = true;
5181 }
5182 else
5183 pThis->nTxDFetched = 0;
5184 pThis->iTxDCurrent = 0;
5185 }
5186 if (!pThis->fLocked && GET_BITS(TXDCTL, LWTHRESH) == 0)
5187 {
5188 E1kLog2(("%s Out of transmit descriptors, raise ICR.TXD_LOW\n",
5189 pThis->szPrf));
5190 e1kRaiseInterrupt(pThis, VERR_SEM_BUSY, ICR_TXD_LOW);
5191 }
5192out:
5193 STAM_PROFILE_ADV_STOP(&pThis->CTX_SUFF_Z(StatTransmit), a);
5194
5195 /// @todo: uncomment: pThis->uStatIntTXQE++;
5196 /// @todo: uncomment: e1kRaiseInterrupt(pThis, ICR_TXQE);
5197
5198 e1kCsTxLeave(pThis);
5199 }
5200
5201
5202 /*
5203 * Release the lock.
5204 */
5205 if (pDrv)
5206 pDrv->pfnEndXmit(pDrv);
5207 return rc;
5208}
5209
5210#endif /* E1K_WITH_TXD_CACHE */
5211#ifdef IN_RING3
5212
5213/**
5214 * @interface_method_impl{PDMINETWORKDOWN,pfnXmitPending}
5215 */
5216static DECLCALLBACK(void) e1kR3NetworkDown_XmitPending(PPDMINETWORKDOWN pInterface)
5217{
5218 PE1KSTATE pThis = RT_FROM_MEMBER(pInterface, E1KSTATE, INetworkDown);
5219 /* Resume suspended transmission */
5220 STATUS &= ~STATUS_TXOFF;
5221 e1kXmitPending(pThis, true /*fOnWorkerThread*/);
5222}
5223
5224/**
5225 * Callback for consuming from transmit queue. It gets called in R3 whenever
5226 * we enqueue something in R0/GC.
5227 *
5228 * @returns true
5229 * @param pDevIns Pointer to device instance structure.
5230 * @param pItem Pointer to the element being dequeued (not used).
5231 * @thread ???
5232 */
5233static DECLCALLBACK(bool) e1kTxQueueConsumer(PPDMDEVINS pDevIns, PPDMQUEUEITEMCORE pItem)
5234{
5235 NOREF(pItem);
5236 PE1KSTATE pThis = PDMINS_2_DATA(pDevIns, PE1KSTATE);
5237 E1kLog2(("%s e1kTxQueueConsumer:\n", pThis->szPrf));
5238
5239 int rc = e1kXmitPending(pThis, false /*fOnWorkerThread*/);
5240 AssertMsg(RT_SUCCESS(rc) || rc == VERR_TRY_AGAIN, ("%Rrc\n", rc));
5241
5242 return true;
5243}
5244
5245/**
5246 * Handler for the wakeup signaller queue.
5247 */
5248static DECLCALLBACK(bool) e1kCanRxQueueConsumer(PPDMDEVINS pDevIns, PPDMQUEUEITEMCORE pItem)
5249{
5250 e1kWakeupReceive(pDevIns);
5251 return true;
5252}
5253
5254#endif /* IN_RING3 */
5255
5256/**
5257 * Write handler for Transmit Descriptor Tail register.
5258 *
5259 * @param pThis The device state structure.
5260 * @param offset Register offset in memory-mapped frame.
5261 * @param index Register index in register array.
5262 * @param value The value to store.
5263 * @param mask Used to implement partial writes (8 and 16-bit).
5264 * @thread EMT
5265 */
5266static int e1kRegWriteTDT(PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t value)
5267{
5268 int rc = e1kRegWriteDefault(pThis, offset, index, value);
5269
5270 /* All descriptors starting with head and not including tail belong to us. */
5271 /* Process them. */
5272 E1kLog2(("%s e1kRegWriteTDT: TDBAL=%08x, TDBAH=%08x, TDLEN=%08x, TDH=%08x, TDT=%08x\n",
5273 pThis->szPrf, TDBAL, TDBAH, TDLEN, TDH, TDT));
5274
5275 /* Ignore TDT writes when the link is down. */
5276 if (TDH != TDT && (STATUS & STATUS_LU))
5277 {
5278 Log5(("E1000: TDT write: TDH=%08x, TDT=%08x, %d descriptors to process\n", TDH, TDT, e1kGetTxLen(pThis)));
5279 E1kLog(("%s e1kRegWriteTDT: %d descriptors to process\n",
5280 pThis->szPrf, e1kGetTxLen(pThis)));
5281
5282 /* Transmit pending packets if possible, defer it if we cannot do it
5283 in the current context. */
5284#ifdef E1K_TX_DELAY
5285 rc = e1kCsTxEnter(pThis, VERR_SEM_BUSY);
5286 if (RT_LIKELY(rc == VINF_SUCCESS))
5287 {
5288 if (!TMTimerIsActive(pThis->CTX_SUFF(pTXDTimer)))
5289 {
5290#ifdef E1K_INT_STATS
5291 pThis->u64ArmedAt = RTTimeNanoTS();
5292#endif
5293 e1kArmTimer(pThis, pThis->CTX_SUFF(pTXDTimer), E1K_TX_DELAY);
5294 }
5295 E1K_INC_ISTAT_CNT(pThis->uStatTxDelayed);
5296 e1kCsTxLeave(pThis);
5297 return rc;
5298 }
5299 /* We failed to enter the TX critical section -- transmit as usual. */
5300#endif /* E1K_TX_DELAY */
5301#ifndef IN_RING3
5302 if (!pThis->CTX_SUFF(pDrv))
5303 {
5304 PPDMQUEUEITEMCORE pItem = PDMQueueAlloc(pThis->CTX_SUFF(pTxQueue));
5305 if (RT_UNLIKELY(pItem))
5306 PDMQueueInsert(pThis->CTX_SUFF(pTxQueue), pItem);
5307 }
5308 else
5309#endif
5310 {
5311 rc = e1kXmitPending(pThis, false /*fOnWorkerThread*/);
5312 if (rc == VERR_TRY_AGAIN)
5313 rc = VINF_SUCCESS;
5314 else if (rc == VERR_SEM_BUSY)
5315 rc = VINF_IOM_R3_IOPORT_WRITE;
5316 AssertRC(rc);
5317 }
5318 }
5319
5320 return rc;
5321}
5322
5323/**
5324 * Write handler for Multicast Table Array registers.
5325 *
5326 * @param pThis The device state structure.
5327 * @param offset Register offset in memory-mapped frame.
5328 * @param index Register index in register array.
5329 * @param value The value to store.
5330 * @thread EMT
5331 */
5332static int e1kRegWriteMTA(PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t value)
5333{
5334 AssertReturn(offset - g_aE1kRegMap[index].offset < sizeof(pThis->auMTA), VERR_DEV_IO_ERROR);
5335 pThis->auMTA[(offset - g_aE1kRegMap[index].offset)/sizeof(pThis->auMTA[0])] = value;
5336
5337 return VINF_SUCCESS;
5338}
5339
5340/**
5341 * Read handler for Multicast Table Array registers.
5342 *
5343 * @returns VBox status code.
5344 *
5345 * @param pThis The device state structure.
5346 * @param offset Register offset in memory-mapped frame.
5347 * @param index Register index in register array.
5348 * @thread EMT
5349 */
5350static int e1kRegReadMTA(PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t *pu32Value)
5351{
5352 AssertReturn(offset - g_aE1kRegMap[index].offset< sizeof(pThis->auMTA), VERR_DEV_IO_ERROR);
5353 *pu32Value = pThis->auMTA[(offset - g_aE1kRegMap[index].offset)/sizeof(pThis->auMTA[0])];
5354
5355 return VINF_SUCCESS;
5356}
5357
5358/**
5359 * Write handler for Receive Address registers.
5360 *
5361 * @param pThis The device state structure.
5362 * @param offset Register offset in memory-mapped frame.
5363 * @param index Register index in register array.
5364 * @param value The value to store.
5365 * @thread EMT
5366 */
5367static int e1kRegWriteRA(PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t value)
5368{
5369 AssertReturn(offset - g_aE1kRegMap[index].offset < sizeof(pThis->aRecAddr.au32), VERR_DEV_IO_ERROR);
5370 pThis->aRecAddr.au32[(offset - g_aE1kRegMap[index].offset)/sizeof(pThis->aRecAddr.au32[0])] = value;
5371
5372 return VINF_SUCCESS;
5373}
5374
5375/**
5376 * Read handler for Receive Address registers.
5377 *
5378 * @returns VBox status code.
5379 *
5380 * @param pThis The device state structure.
5381 * @param offset Register offset in memory-mapped frame.
5382 * @param index Register index in register array.
5383 * @thread EMT
5384 */
5385static int e1kRegReadRA(PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t *pu32Value)
5386{
5387 AssertReturn(offset - g_aE1kRegMap[index].offset< sizeof(pThis->aRecAddr.au32), VERR_DEV_IO_ERROR);
5388 *pu32Value = pThis->aRecAddr.au32[(offset - g_aE1kRegMap[index].offset)/sizeof(pThis->aRecAddr.au32[0])];
5389
5390 return VINF_SUCCESS;
5391}
5392
5393/**
5394 * Write handler for VLAN Filter Table Array registers.
5395 *
5396 * @param pThis The device state structure.
5397 * @param offset Register offset in memory-mapped frame.
5398 * @param index Register index in register array.
5399 * @param value The value to store.
5400 * @thread EMT
5401 */
5402static int e1kRegWriteVFTA(PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t value)
5403{
5404 AssertReturn(offset - g_aE1kRegMap[index].offset < sizeof(pThis->auVFTA), VINF_SUCCESS);
5405 pThis->auVFTA[(offset - g_aE1kRegMap[index].offset)/sizeof(pThis->auVFTA[0])] = value;
5406
5407 return VINF_SUCCESS;
5408}
5409
5410/**
5411 * Read handler for VLAN Filter Table Array registers.
5412 *
5413 * @returns VBox status code.
5414 *
5415 * @param pThis The device state structure.
5416 * @param offset Register offset in memory-mapped frame.
5417 * @param index Register index in register array.
5418 * @thread EMT
5419 */
5420static int e1kRegReadVFTA(PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t *pu32Value)
5421{
5422 AssertReturn(offset - g_aE1kRegMap[index].offset< sizeof(pThis->auVFTA), VERR_DEV_IO_ERROR);
5423 *pu32Value = pThis->auVFTA[(offset - g_aE1kRegMap[index].offset)/sizeof(pThis->auVFTA[0])];
5424
5425 return VINF_SUCCESS;
5426}
5427
5428/**
5429 * Read handler for unimplemented registers.
5430 *
5431 * Merely reports reads from unimplemented registers.
5432 *
5433 * @returns VBox status code.
5434 *
5435 * @param pThis The device state structure.
5436 * @param offset Register offset in memory-mapped frame.
5437 * @param index Register index in register array.
5438 * @thread EMT
5439 */
5440static int e1kRegReadUnimplemented(PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t *pu32Value)
5441{
5442 E1kLog(("%s At %08X read (00000000) attempt from unimplemented register %s (%s)\n",
5443 pThis->szPrf, offset, g_aE1kRegMap[index].abbrev, g_aE1kRegMap[index].name));
5444 *pu32Value = 0;
5445
5446 return VINF_SUCCESS;
5447}
5448
5449/**
5450 * Default register read handler with automatic clear operation.
5451 *
5452 * Retrieves the value of register from register array in device state structure.
5453 * Then resets all bits.
5454 *
5455 * @remarks The 'mask' parameter is simply ignored as masking and shifting is
5456 * done in the caller.
5457 *
5458 * @returns VBox status code.
5459 *
5460 * @param pThis The device state structure.
5461 * @param offset Register offset in memory-mapped frame.
5462 * @param index Register index in register array.
5463 * @thread EMT
5464 */
5465static int e1kRegReadAutoClear(PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t *pu32Value)
5466{
5467 AssertReturn(index < E1K_NUM_OF_32BIT_REGS, VERR_DEV_IO_ERROR);
5468 int rc = e1kRegReadDefault(pThis, offset, index, pu32Value);
5469 pThis->auRegs[index] = 0;
5470
5471 return rc;
5472}
5473
5474/**
5475 * Default register read handler.
5476 *
5477 * Retrieves the value of register from register array in device state structure.
5478 * Bits corresponding to 0s in 'readable' mask will always read as 0s.
5479 *
5480 * @remarks The 'mask' parameter is simply ignored as masking and shifting is
5481 * done in the caller.
5482 *
5483 * @returns VBox status code.
5484 *
5485 * @param pThis The device state structure.
5486 * @param offset Register offset in memory-mapped frame.
5487 * @param index Register index in register array.
5488 * @thread EMT
5489 */
5490static int e1kRegReadDefault(PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t *pu32Value)
5491{
5492 AssertReturn(index < E1K_NUM_OF_32BIT_REGS, VERR_DEV_IO_ERROR);
5493 *pu32Value = pThis->auRegs[index] & g_aE1kRegMap[index].readable;
5494
5495 return VINF_SUCCESS;
5496}
5497
5498/**
5499 * Write handler for unimplemented registers.
5500 *
5501 * Merely reports writes to unimplemented registers.
5502 *
5503 * @param pThis The device state structure.
5504 * @param offset Register offset in memory-mapped frame.
5505 * @param index Register index in register array.
5506 * @param value The value to store.
5507 * @thread EMT
5508 */
5509
5510 static int e1kRegWriteUnimplemented(PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t value)
5511{
5512 E1kLog(("%s At %08X write attempt (%08X) to unimplemented register %s (%s)\n",
5513 pThis->szPrf, offset, value, g_aE1kRegMap[index].abbrev, g_aE1kRegMap[index].name));
5514
5515 return VINF_SUCCESS;
5516}
5517
5518/**
5519 * Default register write handler.
5520 *
5521 * Stores the value to the register array in device state structure. Only bits
5522 * corresponding to 1s both in 'writable' and 'mask' will be stored.
5523 *
5524 * @returns VBox status code.
5525 *
5526 * @param pThis The device state structure.
5527 * @param offset Register offset in memory-mapped frame.
5528 * @param index Register index in register array.
5529 * @param value The value to store.
5530 * @param mask Used to implement partial writes (8 and 16-bit).
5531 * @thread EMT
5532 */
5533
5534static int e1kRegWriteDefault(PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t value)
5535{
5536 AssertReturn(index < E1K_NUM_OF_32BIT_REGS, VERR_DEV_IO_ERROR);
5537 pThis->auRegs[index] = (value & g_aE1kRegMap[index].writable)
5538 | (pThis->auRegs[index] & ~g_aE1kRegMap[index].writable);
5539
5540 return VINF_SUCCESS;
5541}
5542
5543/**
5544 * Search register table for matching register.
5545 *
5546 * @returns Index in the register table or -1 if not found.
5547 *
5548 * @param pThis The device state structure.
5549 * @param offReg Register offset in memory-mapped region.
5550 * @thread EMT
5551 */
5552static int e1kRegLookup(PE1KSTATE pThis, uint32_t offReg)
5553{
5554#if 0
5555 int index;
5556
5557 for (index = 0; index < E1K_NUM_OF_REGS; index++)
5558 {
5559 if (g_aE1kRegMap[index].offset <= offReg && offReg < g_aE1kRegMap[index].offset + g_aE1kRegMap[index].size)
5560 {
5561 return index;
5562 }
5563 }
5564#else
5565 int iStart = 0;
5566 int iEnd = E1K_NUM_OF_BINARY_SEARCHABLE;
5567 for (;;)
5568 {
5569 int i = (iEnd - iStart) / 2 + iStart;
5570 uint32_t offCur = g_aE1kRegMap[i].offset;
5571 if (offReg < offCur)
5572 {
5573 if (i == iStart)
5574 break;
5575 iEnd = i;
5576 }
5577 else if (offReg >= offCur + g_aE1kRegMap[i].size)
5578 {
5579 i++;
5580 if (i == iEnd)
5581 break;
5582 iStart = i;
5583 }
5584 else
5585 return i;
5586 Assert(iEnd > iStart);
5587 }
5588
5589 for (unsigned i = E1K_NUM_OF_BINARY_SEARCHABLE; i < RT_ELEMENTS(g_aE1kRegMap); i++)
5590 if (offReg - g_aE1kRegMap[i].offset < g_aE1kRegMap[i].size)
5591 return i;
5592
5593# ifdef VBOX_STRICT
5594 for (unsigned i = 0; i < RT_ELEMENTS(g_aE1kRegMap); i++)
5595 Assert(offReg - g_aE1kRegMap[i].offset >= g_aE1kRegMap[i].size);
5596# endif
5597
5598#endif
5599
5600 return -1;
5601}
5602
5603/**
5604 * Handle unaligned register read operation.
5605 *
5606 * Looks up and calls appropriate handler.
5607 *
5608 * @returns VBox status code.
5609 *
5610 * @param pThis The device state structure.
5611 * @param offReg Register offset in memory-mapped frame.
5612 * @param pv Where to store the result.
5613 * @param cb Number of bytes to read.
5614 * @thread EMT
5615 * @remarks IOM takes care of unaligned and small reads via MMIO. For I/O port
5616 * accesses we have to take care of that ourselves.
5617 */
5618static int e1kRegReadUnaligned(PE1KSTATE pThis, uint32_t offReg, void *pv, uint32_t cb)
5619{
5620 uint32_t u32 = 0;
5621 uint32_t shift;
5622 int rc = VINF_SUCCESS;
5623 int index = e1kRegLookup(pThis, offReg);
5624#ifdef DEBUG
5625 char buf[9];
5626#endif
5627
5628 /*
5629 * From the spec:
5630 * For registers that should be accessed as 32-bit double words, partial writes (less than a 32-bit
5631 * double word) is ignored. Partial reads return all 32 bits of data regardless of the byte enables.
5632 */
5633
5634 /*
5635 * To be able to read bytes and short word we convert them to properly
5636 * shifted 32-bit words and masks. The idea is to keep register-specific
5637 * handlers simple. Most accesses will be 32-bit anyway.
5638 */
5639 uint32_t mask;
5640 switch (cb)
5641 {
5642 case 4: mask = 0xFFFFFFFF; break;
5643 case 2: mask = 0x0000FFFF; break;
5644 case 1: mask = 0x000000FF; break;
5645 default:
5646 return PDMDevHlpDBGFStop(pThis->CTX_SUFF(pDevIns), RT_SRC_POS,
5647 "unsupported op size: offset=%#10x cb=%#10x\n", offReg, cb);
5648 }
5649 if (index != -1)
5650 {
5651 if (g_aE1kRegMap[index].readable)
5652 {
5653 /* Make the mask correspond to the bits we are about to read. */
5654 shift = (offReg - g_aE1kRegMap[index].offset) % sizeof(uint32_t) * 8;
5655 mask <<= shift;
5656 if (!mask)
5657 return PDMDevHlpDBGFStop(pThis->CTX_SUFF(pDevIns), RT_SRC_POS, "Zero mask: offset=%#10x cb=%#10x\n", offReg, cb);
5658 /*
5659 * Read it. Pass the mask so the handler knows what has to be read.
5660 * Mask out irrelevant bits.
5661 */
5662 //rc = e1kCsEnter(pThis, VERR_SEM_BUSY, RT_SRC_POS);
5663 if (RT_UNLIKELY(rc != VINF_SUCCESS))
5664 return rc;
5665 //pThis->fDelayInts = false;
5666 //pThis->iStatIntLost += pThis->iStatIntLostOne;
5667 //pThis->iStatIntLostOne = 0;
5668 rc = g_aE1kRegMap[index].pfnRead(pThis, offReg & 0xFFFFFFFC, index, &u32);
5669 u32 &= mask;
5670 //e1kCsLeave(pThis);
5671 E1kLog2(("%s At %08X read %s from %s (%s)\n",
5672 pThis->szPrf, offReg, e1kU32toHex(u32, mask, buf), g_aE1kRegMap[index].abbrev, g_aE1kRegMap[index].name));
5673 Log6(("%s At %08X read %s from %s (%s) [UNALIGNED]\n",
5674 pThis->szPrf, offReg, e1kU32toHex(u32, mask, buf), g_aE1kRegMap[index].abbrev, g_aE1kRegMap[index].name));
5675 /* Shift back the result. */
5676 u32 >>= shift;
5677 }
5678 else
5679 E1kLog(("%s At %08X read (%s) attempt from write-only register %s (%s)\n",
5680 pThis->szPrf, offReg, e1kU32toHex(u32, mask, buf), g_aE1kRegMap[index].abbrev, g_aE1kRegMap[index].name));
5681 if (IOM_SUCCESS(rc))
5682 STAM_COUNTER_INC(&pThis->aStatRegReads[index]);
5683 }
5684 else
5685 E1kLog(("%s At %08X read (%s) attempt from non-existing register\n",
5686 pThis->szPrf, offReg, e1kU32toHex(u32, mask, buf)));
5687
5688 memcpy(pv, &u32, cb);
5689 return rc;
5690}
5691
5692/**
5693 * Handle 4 byte aligned and sized read operation.
5694 *
5695 * Looks up and calls appropriate handler.
5696 *
5697 * @returns VBox status code.
5698 *
5699 * @param pThis The device state structure.
5700 * @param offReg Register offset in memory-mapped frame.
5701 * @param pu32 Where to store the result.
5702 * @thread EMT
5703 */
5704static int e1kRegReadAlignedU32(PE1KSTATE pThis, uint32_t offReg, uint32_t *pu32)
5705{
5706 Assert(!(offReg & 3));
5707
5708 /*
5709 * Lookup the register and check that it's readable.
5710 */
5711 int rc = VINF_SUCCESS;
5712 int idxReg = e1kRegLookup(pThis, offReg);
5713 if (RT_LIKELY(idxReg != -1))
5714 {
5715 if (RT_UNLIKELY(g_aE1kRegMap[idxReg].readable))
5716 {
5717 /*
5718 * Read it. Pass the mask so the handler knows what has to be read.
5719 * Mask out irrelevant bits.
5720 */
5721 //rc = e1kCsEnter(pThis, VERR_SEM_BUSY, RT_SRC_POS);
5722 //if (RT_UNLIKELY(rc != VINF_SUCCESS))
5723 // return rc;
5724 //pThis->fDelayInts = false;
5725 //pThis->iStatIntLost += pThis->iStatIntLostOne;
5726 //pThis->iStatIntLostOne = 0;
5727 rc = g_aE1kRegMap[idxReg].pfnRead(pThis, offReg & 0xFFFFFFFC, idxReg, pu32);
5728 //e1kCsLeave(pThis);
5729 Log6(("%s At %08X read %08X from %s (%s)\n",
5730 pThis->szPrf, offReg, *pu32, g_aE1kRegMap[idxReg].abbrev, g_aE1kRegMap[idxReg].name));
5731 if (IOM_SUCCESS(rc))
5732 STAM_COUNTER_INC(&pThis->aStatRegReads[idxReg]);
5733 }
5734 else
5735 E1kLog(("%s At %08X read (%s) attempt from non-existing register\n", pThis->szPrf, offReg));
5736 }
5737 else
5738 E1kLog(("%s At %08X read attempt from non-existing register\n", pThis->szPrf, offReg));
5739 return rc;
5740}
5741
5742/**
5743 * Handle 4 byte sized and aligned register write operation.
5744 *
5745 * Looks up and calls appropriate handler.
5746 *
5747 * @returns VBox status code.
5748 *
5749 * @param pThis The device state structure.
5750 * @param offReg Register offset in memory-mapped frame.
5751 * @param u32Value The value to write.
5752 * @thread EMT
5753 */
5754static int e1kRegWriteAlignedU32(PE1KSTATE pThis, uint32_t offReg, uint32_t u32Value)
5755{
5756 int rc = VINF_SUCCESS;
5757 int index = e1kRegLookup(pThis, offReg);
5758 if (RT_LIKELY(index != -1))
5759 {
5760 if (RT_LIKELY(g_aE1kRegMap[index].writable))
5761 {
5762 /*
5763 * Write it. Pass the mask so the handler knows what has to be written.
5764 * Mask out irrelevant bits.
5765 */
5766 Log6(("%s At %08X write %08X to %s (%s)\n",
5767 pThis->szPrf, offReg, u32Value, g_aE1kRegMap[index].abbrev, g_aE1kRegMap[index].name));
5768 //rc = e1kCsEnter(pThis, VERR_SEM_BUSY, RT_SRC_POS);
5769 //if (RT_UNLIKELY(rc != VINF_SUCCESS))
5770 // return rc;
5771 //pThis->fDelayInts = false;
5772 //pThis->iStatIntLost += pThis->iStatIntLostOne;
5773 //pThis->iStatIntLostOne = 0;
5774 rc = g_aE1kRegMap[index].pfnWrite(pThis, offReg, index, u32Value);
5775 //e1kCsLeave(pThis);
5776 }
5777 else
5778 E1kLog(("%s At %08X write attempt (%08X) to read-only register %s (%s)\n",
5779 pThis->szPrf, offReg, u32Value, g_aE1kRegMap[index].abbrev, g_aE1kRegMap[index].name));
5780 if (IOM_SUCCESS(rc))
5781 STAM_COUNTER_INC(&pThis->aStatRegWrites[index]);
5782 }
5783 else
5784 E1kLog(("%s At %08X write attempt (%08X) to non-existing register\n",
5785 pThis->szPrf, offReg, u32Value));
5786 return rc;
5787}
5788
5789
5790/* -=-=-=-=- MMIO and I/O Port Callbacks -=-=-=-=- */
5791
5792/**
5793 * @callback_method_impl{FNIOMMMIOREAD}
5794 */
5795PDMBOTHCBDECL(int) e1kMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
5796{
5797 NOREF(pvUser);
5798 PE1KSTATE pThis = PDMINS_2_DATA(pDevIns, PE1KSTATE);
5799 STAM_PROFILE_ADV_START(&pThis->CTX_SUFF_Z(StatMMIORead), a);
5800
5801 uint32_t offReg = GCPhysAddr - pThis->addrMMReg;
5802 Assert(offReg < E1K_MM_SIZE);
5803 Assert(cb == 4);
5804 Assert(!(GCPhysAddr & 3));
5805
5806 int rc = e1kRegReadAlignedU32(pThis, offReg, (uint32_t *)pv);
5807
5808 STAM_PROFILE_ADV_STOP(&pThis->CTX_SUFF_Z(StatMMIORead), a);
5809 return rc;
5810}
5811
5812/**
5813 * @callback_method_impl{FNIOMMMIOWRITE}
5814 */
5815PDMBOTHCBDECL(int) e1kMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void const *pv, unsigned cb)
5816{
5817 NOREF(pvUser);
5818 PE1KSTATE pThis = PDMINS_2_DATA(pDevIns, PE1KSTATE);
5819 STAM_PROFILE_ADV_START(&pThis->CTX_SUFF_Z(StatMMIOWrite), a);
5820
5821 uint32_t offReg = GCPhysAddr - pThis->addrMMReg;
5822 Assert(offReg < E1K_MM_SIZE);
5823 Assert(cb == 4);
5824 Assert(!(GCPhysAddr & 3));
5825
5826 int rc = e1kRegWriteAlignedU32(pThis, offReg, *(uint32_t const *)pv);
5827
5828 STAM_PROFILE_ADV_STOP(&pThis->CTX_SUFF_Z(StatMMIOWrite), a);
5829 return rc;
5830}
5831
5832/**
5833 * @callback_method_impl{FNIOMIOPORTIN}
5834 */
5835PDMBOTHCBDECL(int) e1kIOPortIn(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT uPort, uint32_t *pu32, unsigned cb)
5836{
5837 PE1KSTATE pThis = PDMINS_2_DATA(pDevIns, PE1KSTATE);
5838 int rc;
5839 STAM_PROFILE_ADV_START(&pThis->CTX_SUFF_Z(StatIORead), a);
5840
5841 uPort -= pThis->IOPortBase;
5842 if (RT_LIKELY(cb == 4))
5843 switch (uPort)
5844 {
5845 case 0x00: /* IOADDR */
5846 *pu32 = pThis->uSelectedReg;
5847 E1kLog2(("%s e1kIOPortIn: IOADDR(0), selecting register %#010x, val=%#010x\n", pThis->szPrf, pThis->uSelectedReg, *pu32));
5848 rc = VINF_SUCCESS;
5849 break;
5850
5851 case 0x04: /* IODATA */
5852 if (!(pThis->uSelectedReg & 3))
5853 rc = e1kRegReadAlignedU32(pThis, pThis->uSelectedReg, pu32);
5854 else /** @todo r=bird: I wouldn't be surprised if this unaligned branch wasn't necessary. */
5855 rc = e1kRegReadUnaligned(pThis, pThis->uSelectedReg, pu32, cb);
5856 if (rc == VINF_IOM_R3_MMIO_READ)
5857 rc = VINF_IOM_R3_IOPORT_READ;
5858 E1kLog2(("%s e1kIOPortIn: IODATA(4), reading from selected register %#010x, val=%#010x\n", pThis->szPrf, pThis->uSelectedReg, *pu32));
5859 break;
5860
5861 default:
5862 E1kLog(("%s e1kIOPortIn: invalid port %#010x\n", pThis->szPrf, uPort));
5863 //rc = VERR_IOM_IOPORT_UNUSED; /* Why not? */
5864 rc = VINF_SUCCESS;
5865 }
5866 else
5867 {
5868 E1kLog(("%s e1kIOPortIn: invalid op size: uPort=%RTiop cb=%08x", pThis->szPrf, uPort, cb));
5869 rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "%s e1kIOPortIn: invalid op size: uPort=%RTiop cb=%08x\n", pThis->szPrf, uPort, cb);
5870 }
5871 STAM_PROFILE_ADV_STOP(&pThis->CTX_SUFF_Z(StatIORead), a);
5872 return rc;
5873}
5874
5875
5876/**
5877 * @callback_method_impl{FNIOMIOPORTOUT}
5878 */
5879PDMBOTHCBDECL(int) e1kIOPortOut(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT uPort, uint32_t u32, unsigned cb)
5880{
5881 PE1KSTATE pThis = PDMINS_2_DATA(pDevIns, PE1KSTATE);
5882 int rc;
5883 STAM_PROFILE_ADV_START(&pThis->CTX_SUFF_Z(StatIOWrite), a);
5884
5885 E1kLog2(("%s e1kIOPortOut: uPort=%RTiop value=%08x\n", pThis->szPrf, uPort, u32));
5886 if (RT_LIKELY(cb == 4))
5887 {
5888 uPort -= pThis->IOPortBase;
5889 switch (uPort)
5890 {
5891 case 0x00: /* IOADDR */
5892 pThis->uSelectedReg = u32;
5893 E1kLog2(("%s e1kIOPortOut: IOADDR(0), selected register %08x\n", pThis->szPrf, pThis->uSelectedReg));
5894 rc = VINF_SUCCESS;
5895 break;
5896
5897 case 0x04: /* IODATA */
5898 E1kLog2(("%s e1kIOPortOut: IODATA(4), writing to selected register %#010x, value=%#010x\n", pThis->szPrf, pThis->uSelectedReg, u32));
5899 if (RT_LIKELY(!(pThis->uSelectedReg & 3)))
5900 {
5901 rc = e1kRegWriteAlignedU32(pThis, pThis->uSelectedReg, u32);
5902 if (rc == VINF_IOM_R3_MMIO_WRITE)
5903 rc = VINF_IOM_R3_IOPORT_WRITE;
5904 }
5905 else
5906 rc = PDMDevHlpDBGFStop(pThis->CTX_SUFF(pDevIns), RT_SRC_POS,
5907 "Spec violation: misaligned offset: %#10x, ignored.\n", pThis->uSelectedReg);
5908 break;
5909
5910 default:
5911 E1kLog(("%s e1kIOPortOut: invalid port %#010x\n", pThis->szPrf, uPort));
5912 rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "invalid port %#010x\n", uPort);
5913 }
5914 }
5915 else
5916 {
5917 E1kLog(("%s e1kIOPortOut: invalid op size: uPort=%RTiop cb=%08x\n", pThis->szPrf, uPort, cb));
5918 rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "invalid op size: uPort=%RTiop cb=%#x\n", pThis->szPrf, uPort, cb);
5919 }
5920
5921 STAM_PROFILE_ADV_STOP(&pThis->CTX_SUFF_Z(StatIOWrite), a);
5922 return rc;
5923}
5924
5925#ifdef IN_RING3
5926
5927/**
5928 * Dump complete device state to log.
5929 *
5930 * @param pThis Pointer to device state.
5931 */
5932static void e1kDumpState(PE1KSTATE pThis)
5933{
5934 for (int i = 0; i < E1K_NUM_OF_32BIT_REGS; ++i)
5935 {
5936 E1kLog2(("%s %8.8s = %08x\n", pThis->szPrf,
5937 g_aE1kRegMap[i].abbrev, pThis->auRegs[i]));
5938 }
5939# ifdef E1K_INT_STATS
5940 LogRel(("%s Interrupt attempts: %d\n", pThis->szPrf, pThis->uStatIntTry));
5941 LogRel(("%s Interrupts raised : %d\n", pThis->szPrf, pThis->uStatInt));
5942 LogRel(("%s Interrupts lowered: %d\n", pThis->szPrf, pThis->uStatIntLower));
5943 LogRel(("%s Interrupts delayed: %d\n", pThis->szPrf, pThis->uStatIntDly));
5944 LogRel(("%s Disabled delayed: %d\n", pThis->szPrf, pThis->uStatDisDly));
5945 LogRel(("%s Interrupts skipped: %d\n", pThis->szPrf, pThis->uStatIntSkip));
5946 LogRel(("%s Masked interrupts : %d\n", pThis->szPrf, pThis->uStatIntMasked));
5947 LogRel(("%s Early interrupts : %d\n", pThis->szPrf, pThis->uStatIntEarly));
5948 LogRel(("%s Late interrupts : %d\n", pThis->szPrf, pThis->uStatIntLate));
5949 LogRel(("%s Lost interrupts : %d\n", pThis->szPrf, pThis->iStatIntLost));
5950 LogRel(("%s Interrupts by RX : %d\n", pThis->szPrf, pThis->uStatIntRx));
5951 LogRel(("%s Interrupts by TX : %d\n", pThis->szPrf, pThis->uStatIntTx));
5952 LogRel(("%s Interrupts by ICS : %d\n", pThis->szPrf, pThis->uStatIntICS));
5953 LogRel(("%s Interrupts by RDTR: %d\n", pThis->szPrf, pThis->uStatIntRDTR));
5954 LogRel(("%s Interrupts by RDMT: %d\n", pThis->szPrf, pThis->uStatIntRXDMT0));
5955 LogRel(("%s Interrupts by TXQE: %d\n", pThis->szPrf, pThis->uStatIntTXQE));
5956 LogRel(("%s TX int delay asked: %d\n", pThis->szPrf, pThis->uStatTxIDE));
5957 LogRel(("%s TX delayed: %d\n", pThis->szPrf, pThis->uStatTxDelayed));
5958 LogRel(("%s TX delay expired: %d\n", pThis->szPrf, pThis->uStatTxDelayExp));
5959 LogRel(("%s TX no report asked: %d\n", pThis->szPrf, pThis->uStatTxNoRS));
5960 LogRel(("%s TX abs timer expd : %d\n", pThis->szPrf, pThis->uStatTAD));
5961 LogRel(("%s TX int timer expd : %d\n", pThis->szPrf, pThis->uStatTID));
5962 LogRel(("%s RX abs timer expd : %d\n", pThis->szPrf, pThis->uStatRAD));
5963 LogRel(("%s RX int timer expd : %d\n", pThis->szPrf, pThis->uStatRID));
5964 LogRel(("%s TX CTX descriptors: %d\n", pThis->szPrf, pThis->uStatDescCtx));
5965 LogRel(("%s TX DAT descriptors: %d\n", pThis->szPrf, pThis->uStatDescDat));
5966 LogRel(("%s TX LEG descriptors: %d\n", pThis->szPrf, pThis->uStatDescLeg));
5967 LogRel(("%s Received frames : %d\n", pThis->szPrf, pThis->uStatRxFrm));
5968 LogRel(("%s Transmitted frames: %d\n", pThis->szPrf, pThis->uStatTxFrm));
5969 LogRel(("%s TX frames up to 1514: %d\n", pThis->szPrf, pThis->uStatTx1514));
5970 LogRel(("%s TX frames up to 2962: %d\n", pThis->szPrf, pThis->uStatTx2962));
5971 LogRel(("%s TX frames up to 4410: %d\n", pThis->szPrf, pThis->uStatTx4410));
5972 LogRel(("%s TX frames up to 5858: %d\n", pThis->szPrf, pThis->uStatTx5858));
5973 LogRel(("%s TX frames up to 7306: %d\n", pThis->szPrf, pThis->uStatTx7306));
5974 LogRel(("%s TX frames up to 8754: %d\n", pThis->szPrf, pThis->uStatTx8754));
5975 LogRel(("%s TX frames up to 16384: %d\n", pThis->szPrf, pThis->uStatTx16384));
5976 LogRel(("%s TX frames up to 32768: %d\n", pThis->szPrf, pThis->uStatTx32768));
5977 LogRel(("%s Larger TX frames : %d\n", pThis->szPrf, pThis->uStatTxLarge));
5978 LogRel(("%s Max TX Delay : %lld\n", pThis->szPrf, pThis->uStatMaxTxDelay));
5979# endif /* E1K_INT_STATS */
5980}
5981
5982/**
5983 * @callback_method_impl{FNPCIIOREGIONMAP}
5984 */
5985static DECLCALLBACK(int) e1kMap(PPCIDEVICE pPciDev, int iRegion, RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
5986{
5987 PE1KSTATE pThis = PDMINS_2_DATA(pPciDev->pDevIns, E1KSTATE*);
5988 int rc;
5989
5990 switch (enmType)
5991 {
5992 case PCI_ADDRESS_SPACE_IO:
5993 pThis->IOPortBase = (RTIOPORT)GCPhysAddress;
5994 rc = PDMDevHlpIOPortRegister(pPciDev->pDevIns, pThis->IOPortBase, cb, NULL /*pvUser*/,
5995 e1kIOPortOut, e1kIOPortIn, NULL, NULL, "E1000");
5996 if (pThis->fR0Enabled && RT_SUCCESS(rc))
5997 rc = PDMDevHlpIOPortRegisterR0(pPciDev->pDevIns, pThis->IOPortBase, cb, NIL_RTR0PTR /*pvUser*/,
5998 "e1kIOPortOut", "e1kIOPortIn", NULL, NULL, "E1000");
5999 if (pThis->fRCEnabled && RT_SUCCESS(rc))
6000 rc = PDMDevHlpIOPortRegisterRC(pPciDev->pDevIns, pThis->IOPortBase, cb, NIL_RTRCPTR /*pvUser*/,
6001 "e1kIOPortOut", "e1kIOPortIn", NULL, NULL, "E1000");
6002 break;
6003
6004 case PCI_ADDRESS_SPACE_MEM:
6005 /*
6006 * From the spec:
6007 * For registers that should be accessed as 32-bit double words,
6008 * partial writes (less than a 32-bit double word) is ignored.
6009 * Partial reads return all 32 bits of data regardless of the
6010 * byte enables.
6011 */
6012 pThis->addrMMReg = GCPhysAddress; Assert(!(GCPhysAddress & 7));
6013 rc = PDMDevHlpMMIORegister(pPciDev->pDevIns, GCPhysAddress, cb, NULL /*pvUser*/,
6014 IOMMMIO_FLAGS_READ_DWORD | IOMMMIO_FLAGS_WRITE_ONLY_DWORD,
6015 e1kMMIOWrite, e1kMMIORead, "E1000");
6016 if (pThis->fR0Enabled && RT_SUCCESS(rc))
6017 rc = PDMDevHlpMMIORegisterR0(pPciDev->pDevIns, GCPhysAddress, cb, NIL_RTR0PTR /*pvUser*/,
6018 "e1kMMIOWrite", "e1kMMIORead");
6019 if (pThis->fRCEnabled && RT_SUCCESS(rc))
6020 rc = PDMDevHlpMMIORegisterRC(pPciDev->pDevIns, GCPhysAddress, cb, NIL_RTRCPTR /*pvUser*/,
6021 "e1kMMIOWrite", "e1kMMIORead");
6022 break;
6023
6024 default:
6025 /* We should never get here */
6026 AssertMsgFailed(("Invalid PCI address space param in map callback"));
6027 rc = VERR_INTERNAL_ERROR;
6028 break;
6029 }
6030 return rc;
6031}
6032
6033
6034/* -=-=-=-=- PDMINETWORKDOWN -=-=-=-=- */
6035
6036/**
6037 * Check if the device can receive data now.
6038 * This must be called before the pfnRecieve() method is called.
6039 *
6040 * @returns Number of bytes the device can receive.
6041 * @param pInterface Pointer to the interface structure containing the called function pointer.
6042 * @thread EMT
6043 */
6044static int e1kCanReceive(PE1KSTATE pThis)
6045{
6046#ifndef E1K_WITH_RXD_CACHE
6047 size_t cb;
6048
6049 if (RT_UNLIKELY(e1kCsRxEnter(pThis, VERR_SEM_BUSY) != VINF_SUCCESS))
6050 return VERR_NET_NO_BUFFER_SPACE;
6051
6052 if (RT_UNLIKELY(RDLEN == sizeof(E1KRXDESC)))
6053 {
6054 E1KRXDESC desc;
6055 PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns), e1kDescAddr(RDBAH, RDBAL, RDH),
6056 &desc, sizeof(desc));
6057 if (desc.status.fDD)
6058 cb = 0;
6059 else
6060 cb = pThis->u16RxBSize;
6061 }
6062 else if (RDH < RDT)
6063 cb = (RDT - RDH) * pThis->u16RxBSize;
6064 else if (RDH > RDT)
6065 cb = (RDLEN/sizeof(E1KRXDESC) - RDH + RDT) * pThis->u16RxBSize;
6066 else
6067 {
6068 cb = 0;
6069 E1kLogRel(("E1000: OUT of RX descriptors!\n"));
6070 }
6071 E1kLog2(("%s e1kCanReceive: at exit RDH=%d RDT=%d RDLEN=%d u16RxBSize=%d cb=%lu\n",
6072 pThis->szPrf, RDH, RDT, RDLEN, pThis->u16RxBSize, cb));
6073
6074 e1kCsRxLeave(pThis);
6075 return cb > 0 ? VINF_SUCCESS : VERR_NET_NO_BUFFER_SPACE;
6076#else /* E1K_WITH_RXD_CACHE */
6077 int rc = VINF_SUCCESS;
6078
6079 if (RT_UNLIKELY(e1kCsRxEnter(pThis, VERR_SEM_BUSY) != VINF_SUCCESS))
6080 return VERR_NET_NO_BUFFER_SPACE;
6081
6082 if (RT_UNLIKELY(RDLEN == sizeof(E1KRXDESC)))
6083 {
6084 E1KRXDESC desc;
6085 PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns), e1kDescAddr(RDBAH, RDBAL, RDH),
6086 &desc, sizeof(desc));
6087 if (desc.status.fDD)
6088 rc = VERR_NET_NO_BUFFER_SPACE;
6089 }
6090 else if (e1kRxDIsCacheEmpty(pThis) && RDH == RDT)
6091 {
6092 /* Cache is empty, so is the RX ring. */
6093 rc = VERR_NET_NO_BUFFER_SPACE;
6094 }
6095 E1kLog2(("%s e1kCanReceive: at exit in_cache=%d RDH=%d RDT=%d RDLEN=%d"
6096 " u16RxBSize=%d rc=%Rrc\n", pThis->szPrf,
6097 e1kRxDInCache(pThis), RDH, RDT, RDLEN, pThis->u16RxBSize, rc));
6098
6099 e1kCsRxLeave(pThis);
6100 return rc;
6101#endif /* E1K_WITH_RXD_CACHE */
6102}
6103
6104/**
6105 * @interface_method_impl{PDMINETWORKDOWN,pfnWaitReceiveAvail}
6106 */
6107static DECLCALLBACK(int) e1kR3NetworkDown_WaitReceiveAvail(PPDMINETWORKDOWN pInterface, RTMSINTERVAL cMillies)
6108{
6109 PE1KSTATE pThis = RT_FROM_MEMBER(pInterface, E1KSTATE, INetworkDown);
6110 int rc = e1kCanReceive(pThis);
6111
6112 if (RT_SUCCESS(rc))
6113 return VINF_SUCCESS;
6114 if (RT_UNLIKELY(cMillies == 0))
6115 return VERR_NET_NO_BUFFER_SPACE;
6116
6117 rc = VERR_INTERRUPTED;
6118 ASMAtomicXchgBool(&pThis->fMaybeOutOfSpace, true);
6119 STAM_PROFILE_START(&pThis->StatRxOverflow, a);
6120 VMSTATE enmVMState;
6121 while (RT_LIKELY( (enmVMState = PDMDevHlpVMState(pThis->CTX_SUFF(pDevIns))) == VMSTATE_RUNNING
6122 || enmVMState == VMSTATE_RUNNING_LS))
6123 {
6124 int rc2 = e1kCanReceive(pThis);
6125 if (RT_SUCCESS(rc2))
6126 {
6127 rc = VINF_SUCCESS;
6128 break;
6129 }
6130 E1kLogRel(("E1000 e1kR3NetworkDown_WaitReceiveAvail: waiting cMillies=%u...\n", cMillies));
6131 E1kLog(("%s e1kR3NetworkDown_WaitReceiveAvail: waiting cMillies=%u...\n", pThis->szPrf, cMillies));
6132 RTSemEventWait(pThis->hEventMoreRxDescAvail, cMillies);
6133 }
6134 STAM_PROFILE_STOP(&pThis->StatRxOverflow, a);
6135 ASMAtomicXchgBool(&pThis->fMaybeOutOfSpace, false);
6136
6137 return rc;
6138}
6139
6140
6141/**
6142 * Matches the packet addresses against Receive Address table. Looks for
6143 * exact matches only.
6144 *
6145 * @returns true if address matches.
6146 * @param pThis Pointer to the state structure.
6147 * @param pvBuf The ethernet packet.
6148 * @param cb Number of bytes available in the packet.
6149 * @thread EMT
6150 */
6151static bool e1kPerfectMatch(PE1KSTATE pThis, const void *pvBuf)
6152{
6153 for (unsigned i = 0; i < RT_ELEMENTS(pThis->aRecAddr.array); i++)
6154 {
6155 E1KRAELEM* ra = pThis->aRecAddr.array + i;
6156
6157 /* Valid address? */
6158 if (ra->ctl & RA_CTL_AV)
6159 {
6160 Assert((ra->ctl & RA_CTL_AS) < 2);
6161 //unsigned char *pAddr = (unsigned char*)pvBuf + sizeof(ra->addr)*(ra->ctl & RA_CTL_AS);
6162 //E1kLog3(("%s Matching %02x:%02x:%02x:%02x:%02x:%02x against %02x:%02x:%02x:%02x:%02x:%02x...\n",
6163 // pThis->szPrf, pAddr[0], pAddr[1], pAddr[2], pAddr[3], pAddr[4], pAddr[5],
6164 // ra->addr[0], ra->addr[1], ra->addr[2], ra->addr[3], ra->addr[4], ra->addr[5]));
6165 /*
6166 * Address Select:
6167 * 00b = Destination address
6168 * 01b = Source address
6169 * 10b = Reserved
6170 * 11b = Reserved
6171 * Since ethernet header is (DA, SA, len) we can use address
6172 * select as index.
6173 */
6174 if (memcmp((char*)pvBuf + sizeof(ra->addr)*(ra->ctl & RA_CTL_AS),
6175 ra->addr, sizeof(ra->addr)) == 0)
6176 return true;
6177 }
6178 }
6179
6180 return false;
6181}
6182
6183/**
6184 * Matches the packet addresses against Multicast Table Array.
6185 *
6186 * @remarks This is imperfect match since it matches not exact address but
6187 * a subset of addresses.
6188 *
6189 * @returns true if address matches.
6190 * @param pThis Pointer to the state structure.
6191 * @param pvBuf The ethernet packet.
6192 * @param cb Number of bytes available in the packet.
6193 * @thread EMT
6194 */
6195static bool e1kImperfectMatch(PE1KSTATE pThis, const void *pvBuf)
6196{
6197 /* Get bits 32..47 of destination address */
6198 uint16_t u16Bit = ((uint16_t*)pvBuf)[2];
6199
6200 unsigned offset = GET_BITS(RCTL, MO);
6201 /*
6202 * offset means:
6203 * 00b = bits 36..47
6204 * 01b = bits 35..46
6205 * 10b = bits 34..45
6206 * 11b = bits 32..43
6207 */
6208 if (offset < 3)
6209 u16Bit = u16Bit >> (4 - offset);
6210 return ASMBitTest(pThis->auMTA, u16Bit & 0xFFF);
6211}
6212
6213/**
6214 * Determines if the packet is to be delivered to upper layer.
6215 *
6216 * The following filters supported:
6217 * - Exact Unicast/Multicast
6218 * - Promiscuous Unicast/Multicast
6219 * - Multicast
6220 * - VLAN
6221 *
6222 * @returns true if packet is intended for this node.
6223 * @param pThis Pointer to the state structure.
6224 * @param pvBuf The ethernet packet.
6225 * @param cb Number of bytes available in the packet.
6226 * @param pStatus Bit field to store status bits.
6227 * @thread EMT
6228 */
6229static bool e1kAddressFilter(PE1KSTATE pThis, const void *pvBuf, size_t cb, E1KRXDST *pStatus)
6230{
6231 Assert(cb > 14);
6232 /* Assume that we fail to pass exact filter. */
6233 pStatus->fPIF = false;
6234 pStatus->fVP = false;
6235 /* Discard oversized packets */
6236 if (cb > E1K_MAX_RX_PKT_SIZE)
6237 {
6238 E1kLog(("%s ERROR: Incoming packet is too big, cb=%d > max=%d\n",
6239 pThis->szPrf, cb, E1K_MAX_RX_PKT_SIZE));
6240 E1K_INC_CNT32(ROC);
6241 return false;
6242 }
6243 else if (!(RCTL & RCTL_LPE) && cb > 1522)
6244 {
6245 /* When long packet reception is disabled packets over 1522 are discarded */
6246 E1kLog(("%s Discarding incoming packet (LPE=0), cb=%d\n",
6247 pThis->szPrf, cb));
6248 E1K_INC_CNT32(ROC);
6249 return false;
6250 }
6251
6252 uint16_t *u16Ptr = (uint16_t*)pvBuf;
6253 /* Compare TPID with VLAN Ether Type */
6254 if (RT_BE2H_U16(u16Ptr[6]) == VET)
6255 {
6256 pStatus->fVP = true;
6257 /* Is VLAN filtering enabled? */
6258 if (RCTL & RCTL_VFE)
6259 {
6260 /* It is 802.1q packet indeed, let's filter by VID */
6261 if (RCTL & RCTL_CFIEN)
6262 {
6263 E1kLog3(("%s VLAN filter: VLAN=%d CFI=%d RCTL_CFI=%d\n", pThis->szPrf,
6264 E1K_SPEC_VLAN(RT_BE2H_U16(u16Ptr[7])),
6265 E1K_SPEC_CFI(RT_BE2H_U16(u16Ptr[7])),
6266 !!(RCTL & RCTL_CFI)));
6267 if (E1K_SPEC_CFI(RT_BE2H_U16(u16Ptr[7])) != !!(RCTL & RCTL_CFI))
6268 {
6269 E1kLog2(("%s Packet filter: CFIs do not match in packet and RCTL (%d!=%d)\n",
6270 pThis->szPrf, E1K_SPEC_CFI(RT_BE2H_U16(u16Ptr[7])), !!(RCTL & RCTL_CFI)));
6271 return false;
6272 }
6273 }
6274 else
6275 E1kLog3(("%s VLAN filter: VLAN=%d\n", pThis->szPrf,
6276 E1K_SPEC_VLAN(RT_BE2H_U16(u16Ptr[7]))));
6277 if (!ASMBitTest(pThis->auVFTA, E1K_SPEC_VLAN(RT_BE2H_U16(u16Ptr[7]))))
6278 {
6279 E1kLog2(("%s Packet filter: no VLAN match (id=%d)\n",
6280 pThis->szPrf, E1K_SPEC_VLAN(RT_BE2H_U16(u16Ptr[7]))));
6281 return false;
6282 }
6283 }
6284 }
6285 /* Broadcast filtering */
6286 if (e1kIsBroadcast(pvBuf) && (RCTL & RCTL_BAM))
6287 return true;
6288 E1kLog2(("%s Packet filter: not a broadcast\n", pThis->szPrf));
6289 if (e1kIsMulticast(pvBuf))
6290 {
6291 /* Is multicast promiscuous enabled? */
6292 if (RCTL & RCTL_MPE)
6293 return true;
6294 E1kLog2(("%s Packet filter: no promiscuous multicast\n", pThis->szPrf));
6295 /* Try perfect matches first */
6296 if (e1kPerfectMatch(pThis, pvBuf))
6297 {
6298 pStatus->fPIF = true;
6299 return true;
6300 }
6301 E1kLog2(("%s Packet filter: no perfect match\n", pThis->szPrf));
6302 if (e1kImperfectMatch(pThis, pvBuf))
6303 return true;
6304 E1kLog2(("%s Packet filter: no imperfect match\n", pThis->szPrf));
6305 }
6306 else {
6307 /* Is unicast promiscuous enabled? */
6308 if (RCTL & RCTL_UPE)
6309 return true;
6310 E1kLog2(("%s Packet filter: no promiscuous unicast\n", pThis->szPrf));
6311 if (e1kPerfectMatch(pThis, pvBuf))
6312 {
6313 pStatus->fPIF = true;
6314 return true;
6315 }
6316 E1kLog2(("%s Packet filter: no perfect match\n", pThis->szPrf));
6317 }
6318 E1kLog2(("%s Packet filter: packet discarded\n", pThis->szPrf));
6319 return false;
6320}
6321
6322/**
6323 * @interface_method_impl{PDMINETWORKDOWN,pfnReceive}
6324 */
6325static DECLCALLBACK(int) e1kR3NetworkDown_Receive(PPDMINETWORKDOWN pInterface, const void *pvBuf, size_t cb)
6326{
6327 PE1KSTATE pThis = RT_FROM_MEMBER(pInterface, E1KSTATE, INetworkDown);
6328 int rc = VINF_SUCCESS;
6329
6330 /*
6331 * Drop packets if the VM is not running yet/anymore.
6332 */
6333 VMSTATE enmVMState = PDMDevHlpVMState(STATE_TO_DEVINS(pThis));
6334 if ( enmVMState != VMSTATE_RUNNING
6335 && enmVMState != VMSTATE_RUNNING_LS)
6336 {
6337 E1kLog(("%s Dropping incoming packet as VM is not running.\n", pThis->szPrf));
6338 return VINF_SUCCESS;
6339 }
6340
6341 /* Discard incoming packets in locked state */
6342 if (!(RCTL & RCTL_EN) || pThis->fLocked || !(STATUS & STATUS_LU))
6343 {
6344 E1kLog(("%s Dropping incoming packet as receive operation is disabled.\n", pThis->szPrf));
6345 return VINF_SUCCESS;
6346 }
6347
6348 STAM_PROFILE_ADV_START(&pThis->StatReceive, a);
6349
6350 //if (!e1kCsEnter(pThis, RT_SRC_POS))
6351 // return VERR_PERMISSION_DENIED;
6352
6353 e1kPacketDump(pThis, (const uint8_t*)pvBuf, cb, "<-- Incoming");
6354
6355 /* Update stats */
6356 if (RT_LIKELY(e1kCsEnter(pThis, VERR_SEM_BUSY) == VINF_SUCCESS))
6357 {
6358 E1K_INC_CNT32(TPR);
6359 E1K_ADD_CNT64(TORL, TORH, cb < 64? 64 : cb);
6360 e1kCsLeave(pThis);
6361 }
6362 STAM_PROFILE_ADV_START(&pThis->StatReceiveFilter, a);
6363 E1KRXDST status;
6364 RT_ZERO(status);
6365 bool fPassed = e1kAddressFilter(pThis, pvBuf, cb, &status);
6366 STAM_PROFILE_ADV_STOP(&pThis->StatReceiveFilter, a);
6367 if (fPassed)
6368 {
6369 rc = e1kHandleRxPacket(pThis, pvBuf, cb, status);
6370 }
6371 //e1kCsLeave(pThis);
6372 STAM_PROFILE_ADV_STOP(&pThis->StatReceive, a);
6373
6374 return rc;
6375}
6376
6377
6378/* -=-=-=-=- PDMILEDPORTS -=-=-=-=- */
6379
6380/**
6381 * @interface_method_impl{PDMILEDPORTS,pfnQueryStatusLed}
6382 */
6383static DECLCALLBACK(int) e1kR3QueryStatusLed(PPDMILEDPORTS pInterface, unsigned iLUN, PPDMLED *ppLed)
6384{
6385 PE1KSTATE pThis = RT_FROM_MEMBER(pInterface, E1KSTATE, ILeds);
6386 int rc = VERR_PDM_LUN_NOT_FOUND;
6387
6388 if (iLUN == 0)
6389 {
6390 *ppLed = &pThis->led;
6391 rc = VINF_SUCCESS;
6392 }
6393 return rc;
6394}
6395
6396
6397/* -=-=-=-=- PDMINETWORKCONFIG -=-=-=-=- */
6398
6399/**
6400 * @interface_method_impl{PDMINETWORKCONFIG,pfnGetMac}
6401 */
6402static DECLCALLBACK(int) e1kR3GetMac(PPDMINETWORKCONFIG pInterface, PRTMAC pMac)
6403{
6404 PE1KSTATE pThis = RT_FROM_MEMBER(pInterface, E1KSTATE, INetworkConfig);
6405 pThis->eeprom.getMac(pMac);
6406 return VINF_SUCCESS;
6407}
6408
6409/**
6410 * @interface_method_impl{PDMINETWORKCONFIG,pfnGetLinkState}
6411 */
6412static DECLCALLBACK(PDMNETWORKLINKSTATE) e1kR3GetLinkState(PPDMINETWORKCONFIG pInterface)
6413{
6414 PE1KSTATE pThis = RT_FROM_MEMBER(pInterface, E1KSTATE, INetworkConfig);
6415 if (STATUS & STATUS_LU)
6416 return PDMNETWORKLINKSTATE_UP;
6417 return PDMNETWORKLINKSTATE_DOWN;
6418}
6419
6420/**
6421 * @interface_method_impl{PDMINETWORKCONFIG,pfnSetLinkState}
6422 */
6423static DECLCALLBACK(int) e1kR3SetLinkState(PPDMINETWORKCONFIG pInterface, PDMNETWORKLINKSTATE enmState)
6424{
6425 PE1KSTATE pThis = RT_FROM_MEMBER(pInterface, E1KSTATE, INetworkConfig);
6426 bool fOldUp = !!(STATUS & STATUS_LU);
6427 bool fNewUp = enmState == PDMNETWORKLINKSTATE_UP || enmState == PDMNETWORKLINKSTATE_DOWN_RESUME;
6428
6429 /* old state was connected but STATUS not yet written by guest */
6430 if ( fNewUp != fOldUp
6431 || (!fNewUp && pThis->fCableConnected)
6432 || (pThis->fCableConnected && enmState == PDMNETWORKLINKSTATE_DOWN_RESUME))
6433 {
6434 if (fNewUp)
6435 {
6436 E1kLog(("%s Link will be up in approximately %d secs\n",
6437 pThis->szPrf, pThis->cMsLinkUpDelay / 1000));
6438 pThis->fCableConnected = true;
6439 STATUS &= ~STATUS_LU;
6440 Phy::setLinkStatus(&pThis->phy, false);
6441 e1kRaiseInterrupt(pThis, VERR_SEM_BUSY, ICR_LSC);
6442 /* Restore the link back in 5 seconds (by default). */
6443 e1kBringLinkUpDelayed(pThis);
6444 }
6445 else
6446 {
6447 E1kLog(("%s Link is down\n", pThis->szPrf));
6448 pThis->fCableConnected = false;
6449 STATUS &= ~STATUS_LU;
6450 Phy::setLinkStatus(&pThis->phy, false);
6451 e1kRaiseInterrupt(pThis, VERR_SEM_BUSY, ICR_LSC);
6452 }
6453
6454 if (pThis->pDrvR3)
6455 {
6456 /*
6457 * Send a UP link state to the driver below if the network adapter is only
6458 * temproarily disconnected due to resume event.
6459 */
6460 if (enmState == PDMNETWORKLINKSTATE_DOWN_RESUME)
6461 pThis->pDrvR3->pfnNotifyLinkChanged(pThis->pDrvR3, PDMNETWORKLINKSTATE_UP);
6462 else
6463 pThis->pDrvR3->pfnNotifyLinkChanged(pThis->pDrvR3, enmState);
6464 }
6465 }
6466 return VINF_SUCCESS;
6467}
6468
6469
6470/* -=-=-=-=- PDMIBASE -=-=-=-=- */
6471
6472/**
6473 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
6474 */
6475static DECLCALLBACK(void *) e1kR3QueryInterface(struct PDMIBASE *pInterface, const char *pszIID)
6476{
6477 PE1KSTATE pThis = RT_FROM_MEMBER(pInterface, E1KSTATE, IBase);
6478 Assert(&pThis->IBase == pInterface);
6479
6480 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase);
6481 PDMIBASE_RETURN_INTERFACE(pszIID, PDMINETWORKDOWN, &pThis->INetworkDown);
6482 PDMIBASE_RETURN_INTERFACE(pszIID, PDMINETWORKCONFIG, &pThis->INetworkConfig);
6483 PDMIBASE_RETURN_INTERFACE(pszIID, PDMILEDPORTS, &pThis->ILeds);
6484 return NULL;
6485}
6486
6487
6488/* -=-=-=-=- Saved State -=-=-=-=- */
6489
6490/**
6491 * Saves the configuration.
6492 *
6493 * @param pThis The E1K state.
6494 * @param pSSM The handle to the saved state.
6495 */
6496static void e1kSaveConfig(PE1KSTATE pThis, PSSMHANDLE pSSM)
6497{
6498 SSMR3PutMem(pSSM, &pThis->macConfigured, sizeof(pThis->macConfigured));
6499 SSMR3PutU32(pSSM, pThis->eChip);
6500}
6501
6502/**
6503 * @callback_method_impl{FNSSMDEVLIVEEXEC,Save basic configuration.}
6504 */
6505static DECLCALLBACK(int) e1kLiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
6506{
6507 PE1KSTATE pThis = PDMINS_2_DATA(pDevIns, E1KSTATE*);
6508 e1kSaveConfig(pThis, pSSM);
6509 return VINF_SSM_DONT_CALL_AGAIN;
6510}
6511
6512/**
6513 * @callback_method_impl{FNSSMDEVSAVEPREP,Synchronize.}
6514 */
6515static DECLCALLBACK(int) e1kSavePrep(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
6516{
6517 PE1KSTATE pThis = PDMINS_2_DATA(pDevIns, E1KSTATE*);
6518
6519 int rc = e1kCsEnter(pThis, VERR_SEM_BUSY);
6520 if (RT_UNLIKELY(rc != VINF_SUCCESS))
6521 return rc;
6522 e1kCsLeave(pThis);
6523 return VINF_SUCCESS;
6524#if 0
6525 /* 1) Prevent all threads from modifying the state and memory */
6526 //pThis->fLocked = true;
6527 /* 2) Cancel all timers */
6528#ifdef E1K_TX_DELAY
6529 e1kCancelTimer(pThis, pThis->CTX_SUFF(pTXDTimer));
6530#endif /* E1K_TX_DELAY */
6531#ifdef E1K_USE_TX_TIMERS
6532 e1kCancelTimer(pThis, pThis->CTX_SUFF(pTIDTimer));
6533#ifndef E1K_NO_TAD
6534 e1kCancelTimer(pThis, pThis->CTX_SUFF(pTADTimer));
6535#endif /* E1K_NO_TAD */
6536#endif /* E1K_USE_TX_TIMERS */
6537#ifdef E1K_USE_RX_TIMERS
6538 e1kCancelTimer(pThis, pThis->CTX_SUFF(pRIDTimer));
6539 e1kCancelTimer(pThis, pThis->CTX_SUFF(pRADTimer));
6540#endif /* E1K_USE_RX_TIMERS */
6541 e1kCancelTimer(pThis, pThis->CTX_SUFF(pIntTimer));
6542 /* 3) Did I forget anything? */
6543 E1kLog(("%s Locked\n", pThis->szPrf));
6544 return VINF_SUCCESS;
6545#endif
6546}
6547
6548/**
6549 * @callback_method_impl{FNSSMDEVSAVEEXEC}
6550 */
6551static DECLCALLBACK(int) e1kSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
6552{
6553 PE1KSTATE pThis = PDMINS_2_DATA(pDevIns, E1KSTATE*);
6554
6555 e1kSaveConfig(pThis, pSSM);
6556 pThis->eeprom.save(pSSM);
6557 e1kDumpState(pThis);
6558 SSMR3PutMem(pSSM, pThis->auRegs, sizeof(pThis->auRegs));
6559 SSMR3PutBool(pSSM, pThis->fIntRaised);
6560 Phy::saveState(pSSM, &pThis->phy);
6561 SSMR3PutU32(pSSM, pThis->uSelectedReg);
6562 SSMR3PutMem(pSSM, pThis->auMTA, sizeof(pThis->auMTA));
6563 SSMR3PutMem(pSSM, &pThis->aRecAddr, sizeof(pThis->aRecAddr));
6564 SSMR3PutMem(pSSM, pThis->auVFTA, sizeof(pThis->auVFTA));
6565 SSMR3PutU64(pSSM, pThis->u64AckedAt);
6566 SSMR3PutU16(pSSM, pThis->u16RxBSize);
6567 //SSMR3PutBool(pSSM, pThis->fDelayInts);
6568 //SSMR3PutBool(pSSM, pThis->fIntMaskUsed);
6569 SSMR3PutU16(pSSM, pThis->u16TxPktLen);
6570/** @todo State wrt to the TSE buffer is incomplete, so little point in
6571 * saving this actually. */
6572 SSMR3PutMem(pSSM, pThis->aTxPacketFallback, pThis->u16TxPktLen);
6573 SSMR3PutBool(pSSM, pThis->fIPcsum);
6574 SSMR3PutBool(pSSM, pThis->fTCPcsum);
6575 SSMR3PutMem(pSSM, &pThis->contextTSE, sizeof(pThis->contextTSE));
6576 SSMR3PutMem(pSSM, &pThis->contextNormal, sizeof(pThis->contextNormal));
6577 SSMR3PutBool(pSSM, pThis->fVTag);
6578 SSMR3PutU16(pSSM, pThis->u16VTagTCI);
6579#ifdef E1K_WITH_TXD_CACHE
6580#if 0
6581 SSMR3PutU8(pSSM, pThis->nTxDFetched);
6582 SSMR3PutMem(pSSM, pThis->aTxDescriptors,
6583 pThis->nTxDFetched * sizeof(pThis->aTxDescriptors[0]));
6584#else
6585 /*
6586 * There is no point in storing TX descriptor cache entries as we can simply
6587 * fetch them again. Moreover, normally the cache is always empty when we
6588 * save the state. Store zero entries for compatibility.
6589 */
6590 SSMR3PutU8(pSSM, 0);
6591#endif
6592#endif /* E1K_WITH_TXD_CACHE */
6593/**@todo GSO requires some more state here. */
6594 E1kLog(("%s State has been saved\n", pThis->szPrf));
6595 return VINF_SUCCESS;
6596}
6597
6598#if 0
6599/**
6600 * @callback_method_impl{FNSSMDEVSAVEDONE}
6601 */
6602static DECLCALLBACK(int) e1kSaveDone(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
6603{
6604 PE1KSTATE pThis = PDMINS_2_DATA(pDevIns, E1KSTATE*);
6605
6606 /* If VM is being powered off unlocking will result in assertions in PGM */
6607 if (PDMDevHlpGetVM(pDevIns)->enmVMState == VMSTATE_RUNNING)
6608 pThis->fLocked = false;
6609 else
6610 E1kLog(("%s VM is not running -- remain locked\n", pThis->szPrf));
6611 E1kLog(("%s Unlocked\n", pThis->szPrf));
6612 return VINF_SUCCESS;
6613}
6614#endif
6615
6616/**
6617 * @callback_method_impl{FNSSMDEVLOADPREP,Synchronize.}
6618 */
6619static DECLCALLBACK(int) e1kLoadPrep(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
6620{
6621 PE1KSTATE pThis = PDMINS_2_DATA(pDevIns, E1KSTATE*);
6622
6623 int rc = e1kCsEnter(pThis, VERR_SEM_BUSY);
6624 if (RT_UNLIKELY(rc != VINF_SUCCESS))
6625 return rc;
6626 e1kCsLeave(pThis);
6627 return VINF_SUCCESS;
6628}
6629
6630/**
6631 * @callback_method_impl{FNSSMDEVLOADEXEC}
6632 */
6633static DECLCALLBACK(int) e1kLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
6634{
6635 PE1KSTATE pThis = PDMINS_2_DATA(pDevIns, E1KSTATE*);
6636 int rc;
6637
6638 if ( uVersion != E1K_SAVEDSTATE_VERSION
6639#ifdef E1K_WITH_TXD_CACHE
6640 && uVersion != E1K_SAVEDSTATE_VERSION_VBOX_42_VTAG
6641#endif /* E1K_WITH_TXD_CACHE */
6642 && uVersion != E1K_SAVEDSTATE_VERSION_VBOX_41
6643 && uVersion != E1K_SAVEDSTATE_VERSION_VBOX_30)
6644 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
6645
6646 if ( uVersion > E1K_SAVEDSTATE_VERSION_VBOX_30
6647 || uPass != SSM_PASS_FINAL)
6648 {
6649 /* config checks */
6650 RTMAC macConfigured;
6651 rc = SSMR3GetMem(pSSM, &macConfigured, sizeof(macConfigured));
6652 AssertRCReturn(rc, rc);
6653 if ( memcmp(&macConfigured, &pThis->macConfigured, sizeof(macConfigured))
6654 && (uPass == 0 || !PDMDevHlpVMTeleportedAndNotFullyResumedYet(pDevIns)) )
6655 LogRel(("%s: The mac address differs: config=%RTmac saved=%RTmac\n", pThis->szPrf, &pThis->macConfigured, &macConfigured));
6656
6657 E1KCHIP eChip;
6658 rc = SSMR3GetU32(pSSM, &eChip);
6659 AssertRCReturn(rc, rc);
6660 if (eChip != pThis->eChip)
6661 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("The chip type differs: config=%u saved=%u"), pThis->eChip, eChip);
6662 }
6663
6664 if (uPass == SSM_PASS_FINAL)
6665 {
6666 if (uVersion > E1K_SAVEDSTATE_VERSION_VBOX_30)
6667 {
6668 rc = pThis->eeprom.load(pSSM);
6669 AssertRCReturn(rc, rc);
6670 }
6671 /* the state */
6672 SSMR3GetMem(pSSM, &pThis->auRegs, sizeof(pThis->auRegs));
6673 SSMR3GetBool(pSSM, &pThis->fIntRaised);
6674 /** @todo: PHY could be made a separate device with its own versioning */
6675 Phy::loadState(pSSM, &pThis->phy);
6676 SSMR3GetU32(pSSM, &pThis->uSelectedReg);
6677 SSMR3GetMem(pSSM, &pThis->auMTA, sizeof(pThis->auMTA));
6678 SSMR3GetMem(pSSM, &pThis->aRecAddr, sizeof(pThis->aRecAddr));
6679 SSMR3GetMem(pSSM, &pThis->auVFTA, sizeof(pThis->auVFTA));
6680 SSMR3GetU64(pSSM, &pThis->u64AckedAt);
6681 SSMR3GetU16(pSSM, &pThis->u16RxBSize);
6682 //SSMR3GetBool(pSSM, pThis->fDelayInts);
6683 //SSMR3GetBool(pSSM, pThis->fIntMaskUsed);
6684 SSMR3GetU16(pSSM, &pThis->u16TxPktLen);
6685 SSMR3GetMem(pSSM, &pThis->aTxPacketFallback[0], pThis->u16TxPktLen);
6686 SSMR3GetBool(pSSM, &pThis->fIPcsum);
6687 SSMR3GetBool(pSSM, &pThis->fTCPcsum);
6688 SSMR3GetMem(pSSM, &pThis->contextTSE, sizeof(pThis->contextTSE));
6689 rc = SSMR3GetMem(pSSM, &pThis->contextNormal, sizeof(pThis->contextNormal));
6690 AssertRCReturn(rc, rc);
6691 if (uVersion > E1K_SAVEDSTATE_VERSION_VBOX_41)
6692 {
6693 SSMR3GetBool(pSSM, &pThis->fVTag);
6694 rc = SSMR3GetU16(pSSM, &pThis->u16VTagTCI);
6695 AssertRCReturn(rc, rc);
6696 }
6697 else
6698 {
6699 pThis->fVTag = false;
6700 pThis->u16VTagTCI = 0;
6701 }
6702#ifdef E1K_WITH_TXD_CACHE
6703 if (uVersion > E1K_SAVEDSTATE_VERSION_VBOX_42_VTAG)
6704 {
6705 rc = SSMR3GetU8(pSSM, &pThis->nTxDFetched);
6706 AssertRCReturn(rc, rc);
6707 if (pThis->nTxDFetched)
6708 SSMR3GetMem(pSSM, pThis->aTxDescriptors,
6709 pThis->nTxDFetched * sizeof(pThis->aTxDescriptors[0]));
6710 }
6711 else
6712 pThis->nTxDFetched = 0;
6713 /*
6714 * @todo: Perhaps we should not store TXD cache as the entries can be
6715 * simply fetched again from guest's memory. Or can't they?
6716 */
6717#endif /* E1K_WITH_TXD_CACHE */
6718#ifdef E1K_WITH_RXD_CACHE
6719 /*
6720 * There is no point in storing the RX descriptor cache in the saved
6721 * state, we just need to make sure it is empty.
6722 */
6723 pThis->iRxDCurrent = pThis->nRxDFetched = 0;
6724#endif /* E1K_WITH_RXD_CACHE */
6725 /* derived state */
6726 e1kSetupGsoCtx(&pThis->GsoCtx, &pThis->contextTSE);
6727
6728 E1kLog(("%s State has been restored\n", pThis->szPrf));
6729 e1kDumpState(pThis);
6730 }
6731 return VINF_SUCCESS;
6732}
6733
6734/**
6735 * @callback_method_impl{FNSSMDEVLOADDONE, Link status adjustments after loading.}
6736 */
6737static DECLCALLBACK(int) e1kLoadDone(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
6738{
6739 PE1KSTATE pThis = PDMINS_2_DATA(pDevIns, E1KSTATE*);
6740
6741 /* Update promiscuous mode */
6742 if (pThis->pDrvR3)
6743 pThis->pDrvR3->pfnSetPromiscuousMode(pThis->pDrvR3,
6744 !!(RCTL & (RCTL_UPE | RCTL_MPE)));
6745
6746 /*
6747 * Force the link down here, since PDMNETWORKLINKSTATE_DOWN_RESUME is never
6748 * passed to us. We go through all this stuff if the link was up and we
6749 * wasn't teleported.
6750 */
6751 if ( (STATUS & STATUS_LU)
6752 && !PDMDevHlpVMTeleportedAndNotFullyResumedYet(pDevIns)
6753 && pThis->cMsLinkUpDelay)
6754 {
6755 E1kLog(("%s Link is down temporarily\n", pThis->szPrf));
6756 STATUS &= ~STATUS_LU;
6757 Phy::setLinkStatus(&pThis->phy, false);
6758 e1kRaiseInterrupt(pThis, VERR_SEM_BUSY, ICR_LSC);
6759 /* Restore the link back in five seconds (default). */
6760 e1kBringLinkUpDelayed(pThis);
6761 }
6762 return VINF_SUCCESS;
6763}
6764
6765
6766
6767/* -=-=-=-=- Debug Info + Log Types -=-=-=-=- */
6768
6769/**
6770 * @callback_method_impl{FNRTSTRFORMATTYPE}
6771 */
6772static DECLCALLBACK(size_t) e1kFmtRxDesc(PFNRTSTROUTPUT pfnOutput,
6773 void *pvArgOutput,
6774 const char *pszType,
6775 void const *pvValue,
6776 int cchWidth,
6777 int cchPrecision,
6778 unsigned fFlags,
6779 void *pvUser)
6780{
6781 AssertReturn(strcmp(pszType, "e1krxd") == 0, 0);
6782 E1KRXDESC* pDesc = (E1KRXDESC*)pvValue;
6783 if (!pDesc)
6784 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "NULL_RXD");
6785
6786 size_t cbPrintf = 0;
6787 cbPrintf += RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "Address=%16LX Length=%04X Csum=%04X\n",
6788 pDesc->u64BufAddr, pDesc->u16Length, pDesc->u16Checksum);
6789 cbPrintf += RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, " STA: %s %s %s %s %s %s %s ERR: %s %s %s %s SPECIAL: %s VLAN=%03x PRI=%x",
6790 pDesc->status.fPIF ? "PIF" : "pif",
6791 pDesc->status.fIPCS ? "IPCS" : "ipcs",
6792 pDesc->status.fTCPCS ? "TCPCS" : "tcpcs",
6793 pDesc->status.fVP ? "VP" : "vp",
6794 pDesc->status.fIXSM ? "IXSM" : "ixsm",
6795 pDesc->status.fEOP ? "EOP" : "eop",
6796 pDesc->status.fDD ? "DD" : "dd",
6797 pDesc->status.fRXE ? "RXE" : "rxe",
6798 pDesc->status.fIPE ? "IPE" : "ipe",
6799 pDesc->status.fTCPE ? "TCPE" : "tcpe",
6800 pDesc->status.fCE ? "CE" : "ce",
6801 E1K_SPEC_CFI(pDesc->status.u16Special) ? "CFI" :"cfi",
6802 E1K_SPEC_VLAN(pDesc->status.u16Special),
6803 E1K_SPEC_PRI(pDesc->status.u16Special));
6804 return cbPrintf;
6805}
6806
6807/**
6808 * @callback_method_impl{FNRTSTRFORMATTYPE}
6809 */
6810static DECLCALLBACK(size_t) e1kFmtTxDesc(PFNRTSTROUTPUT pfnOutput,
6811 void *pvArgOutput,
6812 const char *pszType,
6813 void const *pvValue,
6814 int cchWidth,
6815 int cchPrecision,
6816 unsigned fFlags,
6817 void *pvUser)
6818{
6819 AssertReturn(strcmp(pszType, "e1ktxd") == 0, 0);
6820 E1KTXDESC* pDesc = (E1KTXDESC*)pvValue;
6821 if (!pDesc)
6822 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "NULL_TXD");
6823
6824 size_t cbPrintf = 0;
6825 switch (e1kGetDescType(pDesc))
6826 {
6827 case E1K_DTYP_CONTEXT:
6828 cbPrintf += RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "Type=Context\n"
6829 " IPCSS=%02X IPCSO=%02X IPCSE=%04X TUCSS=%02X TUCSO=%02X TUCSE=%04X\n"
6830 " TUCMD:%s%s%s %s %s PAYLEN=%04x HDRLEN=%04x MSS=%04x STA: %s",
6831 pDesc->context.ip.u8CSS, pDesc->context.ip.u8CSO, pDesc->context.ip.u16CSE,
6832 pDesc->context.tu.u8CSS, pDesc->context.tu.u8CSO, pDesc->context.tu.u16CSE,
6833 pDesc->context.dw2.fIDE ? " IDE":"",
6834 pDesc->context.dw2.fRS ? " RS" :"",
6835 pDesc->context.dw2.fTSE ? " TSE":"",
6836 pDesc->context.dw2.fIP ? "IPv4":"IPv6",
6837 pDesc->context.dw2.fTCP ? "TCP":"UDP",
6838 pDesc->context.dw2.u20PAYLEN,
6839 pDesc->context.dw3.u8HDRLEN,
6840 pDesc->context.dw3.u16MSS,
6841 pDesc->context.dw3.fDD?"DD":"");
6842 break;
6843 case E1K_DTYP_DATA:
6844 cbPrintf += RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "Type=Data Address=%16LX DTALEN=%05X\n"
6845 " DCMD:%s%s%s%s%s%s%s STA:%s%s%s POPTS:%s%s SPECIAL:%s VLAN=%03x PRI=%x",
6846 pDesc->data.u64BufAddr,
6847 pDesc->data.cmd.u20DTALEN,
6848 pDesc->data.cmd.fIDE ? " IDE" :"",
6849 pDesc->data.cmd.fVLE ? " VLE" :"",
6850 pDesc->data.cmd.fRPS ? " RPS" :"",
6851 pDesc->data.cmd.fRS ? " RS" :"",
6852 pDesc->data.cmd.fTSE ? " TSE" :"",
6853 pDesc->data.cmd.fIFCS? " IFCS":"",
6854 pDesc->data.cmd.fEOP ? " EOP" :"",
6855 pDesc->data.dw3.fDD ? " DD" :"",
6856 pDesc->data.dw3.fEC ? " EC" :"",
6857 pDesc->data.dw3.fLC ? " LC" :"",
6858 pDesc->data.dw3.fTXSM? " TXSM":"",
6859 pDesc->data.dw3.fIXSM? " IXSM":"",
6860 E1K_SPEC_CFI(pDesc->data.dw3.u16Special) ? "CFI" :"cfi",
6861 E1K_SPEC_VLAN(pDesc->data.dw3.u16Special),
6862 E1K_SPEC_PRI(pDesc->data.dw3.u16Special));
6863 break;
6864 case E1K_DTYP_LEGACY:
6865 cbPrintf += RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "Type=Legacy Address=%16LX DTALEN=%05X\n"
6866 " CMD:%s%s%s%s%s%s%s STA:%s%s%s CSO=%02x CSS=%02x SPECIAL:%s VLAN=%03x PRI=%x",
6867 pDesc->data.u64BufAddr,
6868 pDesc->legacy.cmd.u16Length,
6869 pDesc->legacy.cmd.fIDE ? " IDE" :"",
6870 pDesc->legacy.cmd.fVLE ? " VLE" :"",
6871 pDesc->legacy.cmd.fRPS ? " RPS" :"",
6872 pDesc->legacy.cmd.fRS ? " RS" :"",
6873 pDesc->legacy.cmd.fIC ? " IC" :"",
6874 pDesc->legacy.cmd.fIFCS? " IFCS":"",
6875 pDesc->legacy.cmd.fEOP ? " EOP" :"",
6876 pDesc->legacy.dw3.fDD ? " DD" :"",
6877 pDesc->legacy.dw3.fEC ? " EC" :"",
6878 pDesc->legacy.dw3.fLC ? " LC" :"",
6879 pDesc->legacy.cmd.u8CSO,
6880 pDesc->legacy.dw3.u8CSS,
6881 E1K_SPEC_CFI(pDesc->legacy.dw3.u16Special) ? "CFI" :"cfi",
6882 E1K_SPEC_VLAN(pDesc->legacy.dw3.u16Special),
6883 E1K_SPEC_PRI(pDesc->legacy.dw3.u16Special));
6884 break;
6885 default:
6886 cbPrintf += RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "Invalid Transmit Descriptor");
6887 break;
6888 }
6889
6890 return cbPrintf;
6891}
6892
6893/** Initializes debug helpers (logging format types). */
6894static int e1kInitDebugHelpers(void)
6895{
6896 int rc = VINF_SUCCESS;
6897 static bool s_fHelpersRegistered = false;
6898 if (!s_fHelpersRegistered)
6899 {
6900 s_fHelpersRegistered = true;
6901 rc = RTStrFormatTypeRegister("e1krxd", e1kFmtRxDesc, NULL);
6902 AssertRCReturn(rc, rc);
6903 rc = RTStrFormatTypeRegister("e1ktxd", e1kFmtTxDesc, NULL);
6904 AssertRCReturn(rc, rc);
6905 }
6906 return rc;
6907}
6908
6909/**
6910 * Status info callback.
6911 *
6912 * @param pDevIns The device instance.
6913 * @param pHlp The output helpers.
6914 * @param pszArgs The arguments.
6915 */
6916static DECLCALLBACK(void) e1kInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
6917{
6918 PE1KSTATE pThis = PDMINS_2_DATA(pDevIns, E1KSTATE*);
6919 unsigned i;
6920 // bool fRcvRing = false;
6921 // bool fXmtRing = false;
6922
6923 /*
6924 * Parse args.
6925 if (pszArgs)
6926 {
6927 fRcvRing = strstr(pszArgs, "verbose") || strstr(pszArgs, "rcv");
6928 fXmtRing = strstr(pszArgs, "verbose") || strstr(pszArgs, "xmt");
6929 }
6930 */
6931
6932 /*
6933 * Show info.
6934 */
6935 pHlp->pfnPrintf(pHlp, "E1000 #%d: port=%RTiop mmio=%RGp mac-cfg=%RTmac %s%s%s\n",
6936 pDevIns->iInstance, pThis->IOPortBase, pThis->addrMMReg,
6937 &pThis->macConfigured, g_Chips[pThis->eChip].pcszName,
6938 pThis->fRCEnabled ? " GC" : "", pThis->fR0Enabled ? " R0" : "");
6939
6940 e1kCsEnter(pThis, VERR_INTERNAL_ERROR); /* Not sure why but PCNet does it */
6941
6942 for (i = 0; i < E1K_NUM_OF_32BIT_REGS; ++i)
6943 pHlp->pfnPrintf(pHlp, "%8.8s = %08x\n", g_aE1kRegMap[i].abbrev, pThis->auRegs[i]);
6944
6945 for (i = 0; i < RT_ELEMENTS(pThis->aRecAddr.array); i++)
6946 {
6947 E1KRAELEM* ra = pThis->aRecAddr.array + i;
6948 if (ra->ctl & RA_CTL_AV)
6949 {
6950 const char *pcszTmp;
6951 switch (ra->ctl & RA_CTL_AS)
6952 {
6953 case 0: pcszTmp = "DST"; break;
6954 case 1: pcszTmp = "SRC"; break;
6955 default: pcszTmp = "reserved";
6956 }
6957 pHlp->pfnPrintf(pHlp, "RA%02d: %s %RTmac\n", i, pcszTmp, ra->addr);
6958 }
6959 }
6960 unsigned cDescs = RDLEN / sizeof(E1KRXDESC);
6961 uint32_t rdh = RDH;
6962 pHlp->pfnPrintf(pHlp, "\n-- Receive Descriptors (%d total) --\n", cDescs);
6963 for (i = 0; i < cDescs; ++i)
6964 {
6965 E1KRXDESC desc;
6966 PDMDevHlpPhysRead(pDevIns, e1kDescAddr(RDBAH, RDBAL, i),
6967 &desc, sizeof(desc));
6968 if (i == rdh)
6969 pHlp->pfnPrintf(pHlp, ">>> ");
6970 pHlp->pfnPrintf(pHlp, "%RGp: %R[e1krxd]\n", e1kDescAddr(RDBAH, RDBAL, i), &desc);
6971 }
6972#ifdef E1K_WITH_RXD_CACHE
6973 pHlp->pfnPrintf(pHlp, "\n-- Receive Descriptors in Cache (at %d (RDH %d)/ fetched %d / max %d) --\n",
6974 pThis->iRxDCurrent, RDH, pThis->nRxDFetched, E1K_RXD_CACHE_SIZE);
6975 if (rdh > pThis->iRxDCurrent)
6976 rdh -= pThis->iRxDCurrent;
6977 else
6978 rdh = cDescs + rdh - pThis->iRxDCurrent;
6979 for (i = 0; i < pThis->nRxDFetched; ++i)
6980 {
6981 if (i == pThis->iRxDCurrent)
6982 pHlp->pfnPrintf(pHlp, ">>> ");
6983 pHlp->pfnPrintf(pHlp, "%RGp: %R[e1krxd]\n",
6984 e1kDescAddr(RDBAH, RDBAL, rdh++ % cDescs),
6985 &pThis->aRxDescriptors[i]);
6986 }
6987#endif /* E1K_WITH_RXD_CACHE */
6988
6989 cDescs = TDLEN / sizeof(E1KTXDESC);
6990 uint32_t tdh = TDH;
6991 pHlp->pfnPrintf(pHlp, "\n-- Transmit Descriptors (%d total) --\n", cDescs);
6992 for (i = 0; i < cDescs; ++i)
6993 {
6994 E1KTXDESC desc;
6995 PDMDevHlpPhysRead(pDevIns, e1kDescAddr(TDBAH, TDBAL, i),
6996 &desc, sizeof(desc));
6997 if (i == tdh)
6998 pHlp->pfnPrintf(pHlp, ">>> ");
6999 pHlp->pfnPrintf(pHlp, "%RGp: %R[e1ktxd]\n", e1kDescAddr(TDBAH, TDBAL, i), &desc);
7000 }
7001#ifdef E1K_WITH_TXD_CACHE
7002 pHlp->pfnPrintf(pHlp, "\n-- Transmit Descriptors in Cache (at %d (TDH %d)/ fetched %d / max %d) --\n",
7003 pThis->iTxDCurrent, TDH, pThis->nTxDFetched, E1K_TXD_CACHE_SIZE);
7004 if (tdh > pThis->iTxDCurrent)
7005 tdh -= pThis->iTxDCurrent;
7006 else
7007 tdh = cDescs + tdh - pThis->iTxDCurrent;
7008 for (i = 0; i < pThis->nTxDFetched; ++i)
7009 {
7010 if (i == pThis->iTxDCurrent)
7011 pHlp->pfnPrintf(pHlp, ">>> ");
7012 pHlp->pfnPrintf(pHlp, "%RGp: %R[e1ktxd]\n",
7013 e1kDescAddr(TDBAH, TDBAL, tdh++ % cDescs),
7014 &pThis->aTxDescriptors[i]);
7015 }
7016#endif /* E1K_WITH_TXD_CACHE */
7017
7018
7019#ifdef E1K_INT_STATS
7020 pHlp->pfnPrintf(pHlp, "Interrupt attempts: %d\n", pThis->uStatIntTry);
7021 pHlp->pfnPrintf(pHlp, "Interrupts raised : %d\n", pThis->uStatInt);
7022 pHlp->pfnPrintf(pHlp, "Interrupts lowered: %d\n", pThis->uStatIntLower);
7023 pHlp->pfnPrintf(pHlp, "Interrupts delayed: %d\n", pThis->uStatIntDly);
7024 pHlp->pfnPrintf(pHlp, "Disabled delayed: %d\n", pThis->uStatDisDly);
7025 pHlp->pfnPrintf(pHlp, "Interrupts skipped: %d\n", pThis->uStatIntSkip);
7026 pHlp->pfnPrintf(pHlp, "Masked interrupts : %d\n", pThis->uStatIntMasked);
7027 pHlp->pfnPrintf(pHlp, "Early interrupts : %d\n", pThis->uStatIntEarly);
7028 pHlp->pfnPrintf(pHlp, "Late interrupts : %d\n", pThis->uStatIntLate);
7029 pHlp->pfnPrintf(pHlp, "Lost interrupts : %d\n", pThis->iStatIntLost);
7030 pHlp->pfnPrintf(pHlp, "Interrupts by RX : %d\n", pThis->uStatIntRx);
7031 pHlp->pfnPrintf(pHlp, "Interrupts by TX : %d\n", pThis->uStatIntTx);
7032 pHlp->pfnPrintf(pHlp, "Interrupts by ICS : %d\n", pThis->uStatIntICS);
7033 pHlp->pfnPrintf(pHlp, "Interrupts by RDTR: %d\n", pThis->uStatIntRDTR);
7034 pHlp->pfnPrintf(pHlp, "Interrupts by RDMT: %d\n", pThis->uStatIntRXDMT0);
7035 pHlp->pfnPrintf(pHlp, "Interrupts by TXQE: %d\n", pThis->uStatIntTXQE);
7036 pHlp->pfnPrintf(pHlp, "TX int delay asked: %d\n", pThis->uStatTxIDE);
7037 pHlp->pfnPrintf(pHlp, "TX delayed: %d\n", pThis->uStatTxDelayed);
7038 pHlp->pfnPrintf(pHlp, "TX delayed expired: %d\n", pThis->uStatTxDelayExp);
7039 pHlp->pfnPrintf(pHlp, "TX no report asked: %d\n", pThis->uStatTxNoRS);
7040 pHlp->pfnPrintf(pHlp, "TX abs timer expd : %d\n", pThis->uStatTAD);
7041 pHlp->pfnPrintf(pHlp, "TX int timer expd : %d\n", pThis->uStatTID);
7042 pHlp->pfnPrintf(pHlp, "RX abs timer expd : %d\n", pThis->uStatRAD);
7043 pHlp->pfnPrintf(pHlp, "RX int timer expd : %d\n", pThis->uStatRID);
7044 pHlp->pfnPrintf(pHlp, "TX CTX descriptors: %d\n", pThis->uStatDescCtx);
7045 pHlp->pfnPrintf(pHlp, "TX DAT descriptors: %d\n", pThis->uStatDescDat);
7046 pHlp->pfnPrintf(pHlp, "TX LEG descriptors: %d\n", pThis->uStatDescLeg);
7047 pHlp->pfnPrintf(pHlp, "Received frames : %d\n", pThis->uStatRxFrm);
7048 pHlp->pfnPrintf(pHlp, "Transmitted frames: %d\n", pThis->uStatTxFrm);
7049 pHlp->pfnPrintf(pHlp, "TX frames up to 1514: %d\n", pThis->uStatTx1514);
7050 pHlp->pfnPrintf(pHlp, "TX frames up to 2962: %d\n", pThis->uStatTx2962);
7051 pHlp->pfnPrintf(pHlp, "TX frames up to 4410: %d\n", pThis->uStatTx4410);
7052 pHlp->pfnPrintf(pHlp, "TX frames up to 5858: %d\n", pThis->uStatTx5858);
7053 pHlp->pfnPrintf(pHlp, "TX frames up to 7306: %d\n", pThis->uStatTx7306);
7054 pHlp->pfnPrintf(pHlp, "TX frames up to 8754: %d\n", pThis->uStatTx8754);
7055 pHlp->pfnPrintf(pHlp, "TX frames up to 16384: %d\n", pThis->uStatTx16384);
7056 pHlp->pfnPrintf(pHlp, "TX frames up to 32768: %d\n", pThis->uStatTx32768);
7057 pHlp->pfnPrintf(pHlp, "Larger TX frames : %d\n", pThis->uStatTxLarge);
7058#endif /* E1K_INT_STATS */
7059
7060 e1kCsLeave(pThis);
7061}
7062
7063
7064
7065/* -=-=-=-=- PDMDEVREG -=-=-=-=- */
7066
7067/**
7068 * Detach notification.
7069 *
7070 * One port on the network card has been disconnected from the network.
7071 *
7072 * @param pDevIns The device instance.
7073 * @param iLUN The logical unit which is being detached.
7074 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
7075 */
7076static DECLCALLBACK(void) e1kR3Detach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
7077{
7078 PE1KSTATE pThis = PDMINS_2_DATA(pDevIns, E1KSTATE*);
7079 Log(("%s e1kR3Detach:\n", pThis->szPrf));
7080
7081 AssertLogRelReturnVoid(iLUN == 0);
7082
7083 PDMCritSectEnter(&pThis->cs, VERR_SEM_BUSY);
7084
7085 /** @todo: r=pritesh still need to check if i missed
7086 * to clean something in this function
7087 */
7088
7089 /*
7090 * Zero some important members.
7091 */
7092 pThis->pDrvBase = NULL;
7093 pThis->pDrvR3 = NULL;
7094 pThis->pDrvR0 = NIL_RTR0PTR;
7095 pThis->pDrvRC = NIL_RTRCPTR;
7096
7097 PDMCritSectLeave(&pThis->cs);
7098}
7099
7100/**
7101 * Attach the Network attachment.
7102 *
7103 * One port on the network card has been connected to a network.
7104 *
7105 * @returns VBox status code.
7106 * @param pDevIns The device instance.
7107 * @param iLUN The logical unit which is being attached.
7108 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
7109 *
7110 * @remarks This code path is not used during construction.
7111 */
7112static DECLCALLBACK(int) e1kR3Attach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
7113{
7114 PE1KSTATE pThis = PDMINS_2_DATA(pDevIns, E1KSTATE*);
7115 LogFlow(("%s e1kR3Attach:\n", pThis->szPrf));
7116
7117 AssertLogRelReturn(iLUN == 0, VERR_PDM_NO_SUCH_LUN);
7118
7119 PDMCritSectEnter(&pThis->cs, VERR_SEM_BUSY);
7120
7121 /*
7122 * Attach the driver.
7123 */
7124 int rc = PDMDevHlpDriverAttach(pDevIns, 0, &pThis->IBase, &pThis->pDrvBase, "Network Port");
7125 if (RT_SUCCESS(rc))
7126 {
7127 if (rc == VINF_NAT_DNS)
7128 {
7129#ifdef RT_OS_LINUX
7130 PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "NoDNSforNAT",
7131 N_("A Domain Name Server (DNS) for NAT networking could not be determined. Please check your /etc/resolv.conf for <tt>nameserver</tt> entries. Either add one manually (<i>man resolv.conf</i>) or ensure that your host is correctly connected to an ISP. If you ignore this warning the guest will not be able to perform nameserver lookups and it will probably observe delays if trying so"));
7132#else
7133 PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "NoDNSforNAT",
7134 N_("A Domain Name Server (DNS) for NAT networking could not be determined. Ensure that your host is correctly connected to an ISP. If you ignore this warning the guest will not be able to perform nameserver lookups and it will probably observe delays if trying so"));
7135#endif
7136 }
7137 pThis->pDrvR3 = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMINETWORKUP);
7138 AssertMsgStmt(pThis->pDrvR3, ("Failed to obtain the PDMINETWORKUP interface!\n"),
7139 rc = VERR_PDM_MISSING_INTERFACE_BELOW);
7140 if (RT_SUCCESS(rc))
7141 {
7142 PPDMIBASER0 pBaseR0 = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMIBASER0);
7143 pThis->pDrvR0 = pBaseR0 ? pBaseR0->pfnQueryInterface(pBaseR0, PDMINETWORKUP_IID) : NIL_RTR0PTR;
7144
7145 PPDMIBASERC pBaseRC = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMIBASERC);
7146 pThis->pDrvRC = pBaseRC ? pBaseRC->pfnQueryInterface(pBaseRC, PDMINETWORKUP_IID) : NIL_RTR0PTR;
7147 }
7148 }
7149 else if ( rc == VERR_PDM_NO_ATTACHED_DRIVER
7150 || rc == VERR_PDM_CFG_MISSING_DRIVER_NAME)
7151 {
7152 /* This should never happen because this function is not called
7153 * if there is no driver to attach! */
7154 Log(("%s No attached driver!\n", pThis->szPrf));
7155 }
7156
7157 /*
7158 * Temporary set the link down if it was up so that the guest
7159 * will know that we have change the configuration of the
7160 * network card
7161 */
7162 if ((STATUS & STATUS_LU) && RT_SUCCESS(rc))
7163 {
7164 STATUS &= ~STATUS_LU;
7165 Phy::setLinkStatus(&pThis->phy, false);
7166 e1kRaiseInterrupt(pThis, VERR_SEM_BUSY, ICR_LSC);
7167 /* Restore the link back in 5 seconds (default). */
7168 e1kBringLinkUpDelayed(pThis);
7169 }
7170
7171 PDMCritSectLeave(&pThis->cs);
7172 return rc;
7173
7174}
7175
7176/**
7177 * @copydoc FNPDMDEVPOWEROFF
7178 */
7179static DECLCALLBACK(void) e1kR3PowerOff(PPDMDEVINS pDevIns)
7180{
7181 /* Poke thread waiting for buffer space. */
7182 e1kWakeupReceive(pDevIns);
7183}
7184
7185/**
7186 * @copydoc FNPDMDEVRESET
7187 */
7188static DECLCALLBACK(void) e1kR3Reset(PPDMDEVINS pDevIns)
7189{
7190 PE1KSTATE pThis = PDMINS_2_DATA(pDevIns, E1KSTATE*);
7191#ifdef E1K_TX_DELAY
7192 e1kCancelTimer(pThis, pThis->CTX_SUFF(pTXDTimer));
7193#endif /* E1K_TX_DELAY */
7194 e1kCancelTimer(pThis, pThis->CTX_SUFF(pIntTimer));
7195 e1kCancelTimer(pThis, pThis->CTX_SUFF(pLUTimer));
7196 e1kXmitFreeBuf(pThis);
7197 pThis->u16TxPktLen = 0;
7198 pThis->fIPcsum = false;
7199 pThis->fTCPcsum = false;
7200 pThis->fIntMaskUsed = false;
7201 pThis->fDelayInts = false;
7202 pThis->fLocked = false;
7203 pThis->u64AckedAt = 0;
7204 e1kHardReset(pThis);
7205}
7206
7207/**
7208 * @copydoc FNPDMDEVSUSPEND
7209 */
7210static DECLCALLBACK(void) e1kR3Suspend(PPDMDEVINS pDevIns)
7211{
7212 /* Poke thread waiting for buffer space. */
7213 e1kWakeupReceive(pDevIns);
7214}
7215
7216/**
7217 * Device relocation callback.
7218 *
7219 * When this callback is called the device instance data, and if the
7220 * device have a GC component, is being relocated, or/and the selectors
7221 * have been changed. The device must use the chance to perform the
7222 * necessary pointer relocations and data updates.
7223 *
7224 * Before the GC code is executed the first time, this function will be
7225 * called with a 0 delta so GC pointer calculations can be one in one place.
7226 *
7227 * @param pDevIns Pointer to the device instance.
7228 * @param offDelta The relocation delta relative to the old location.
7229 *
7230 * @remark A relocation CANNOT fail.
7231 */
7232static DECLCALLBACK(void) e1kR3Relocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
7233{
7234 PE1KSTATE pThis = PDMINS_2_DATA(pDevIns, E1KSTATE*);
7235 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
7236 pThis->pTxQueueRC = PDMQueueRCPtr(pThis->pTxQueueR3);
7237 pThis->pCanRxQueueRC = PDMQueueRCPtr(pThis->pCanRxQueueR3);
7238#ifdef E1K_USE_RX_TIMERS
7239 pThis->pRIDTimerRC = TMTimerRCPtr(pThis->pRIDTimerR3);
7240 pThis->pRADTimerRC = TMTimerRCPtr(pThis->pRADTimerR3);
7241#endif /* E1K_USE_RX_TIMERS */
7242#ifdef E1K_USE_TX_TIMERS
7243 pThis->pTIDTimerRC = TMTimerRCPtr(pThis->pTIDTimerR3);
7244# ifndef E1K_NO_TAD
7245 pThis->pTADTimerRC = TMTimerRCPtr(pThis->pTADTimerR3);
7246# endif /* E1K_NO_TAD */
7247#endif /* E1K_USE_TX_TIMERS */
7248#ifdef E1K_TX_DELAY
7249 pThis->pTXDTimerRC = TMTimerRCPtr(pThis->pTXDTimerR3);
7250#endif /* E1K_TX_DELAY */
7251 pThis->pIntTimerRC = TMTimerRCPtr(pThis->pIntTimerR3);
7252 pThis->pLUTimerRC = TMTimerRCPtr(pThis->pLUTimerR3);
7253}
7254
7255/**
7256 * Destruct a device instance.
7257 *
7258 * We need to free non-VM resources only.
7259 *
7260 * @returns VBox status.
7261 * @param pDevIns The device instance data.
7262 * @thread EMT
7263 */
7264static DECLCALLBACK(int) e1kR3Destruct(PPDMDEVINS pDevIns)
7265{
7266 PE1KSTATE pThis = PDMINS_2_DATA(pDevIns, E1KSTATE*);
7267 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
7268
7269 e1kDumpState(pThis);
7270 E1kLog(("%s Destroying instance\n", pThis->szPrf));
7271 if (PDMCritSectIsInitialized(&pThis->cs))
7272 {
7273 if (pThis->hEventMoreRxDescAvail != NIL_RTSEMEVENT)
7274 {
7275 RTSemEventSignal(pThis->hEventMoreRxDescAvail);
7276 RTSemEventDestroy(pThis->hEventMoreRxDescAvail);
7277 pThis->hEventMoreRxDescAvail = NIL_RTSEMEVENT;
7278 }
7279#ifdef E1K_WITH_TX_CS
7280 PDMR3CritSectDelete(&pThis->csTx);
7281#endif /* E1K_WITH_TX_CS */
7282 PDMR3CritSectDelete(&pThis->csRx);
7283 PDMR3CritSectDelete(&pThis->cs);
7284 }
7285 return VINF_SUCCESS;
7286}
7287
7288
7289/**
7290 * Set PCI configuration space registers.
7291 *
7292 * @param pci Reference to PCI device structure.
7293 * @thread EMT
7294 */
7295static DECLCALLBACK(void) e1kConfigurePciDev(PPCIDEVICE pPciDev, E1KCHIP eChip)
7296{
7297 Assert(eChip < RT_ELEMENTS(g_Chips));
7298 /* Configure PCI Device, assume 32-bit mode ******************************/
7299 PCIDevSetVendorId(pPciDev, g_Chips[eChip].uPCIVendorId);
7300 PCIDevSetDeviceId(pPciDev, g_Chips[eChip].uPCIDeviceId);
7301 PCIDevSetWord( pPciDev, VBOX_PCI_SUBSYSTEM_VENDOR_ID, g_Chips[eChip].uPCISubsystemVendorId);
7302 PCIDevSetWord( pPciDev, VBOX_PCI_SUBSYSTEM_ID, g_Chips[eChip].uPCISubsystemId);
7303
7304 PCIDevSetWord( pPciDev, VBOX_PCI_COMMAND, 0x0000);
7305 /* DEVSEL Timing (medium device), 66 MHz Capable, New capabilities */
7306 PCIDevSetWord( pPciDev, VBOX_PCI_STATUS,
7307 VBOX_PCI_STATUS_DEVSEL_MEDIUM | VBOX_PCI_STATUS_CAP_LIST | VBOX_PCI_STATUS_66MHZ);
7308 /* Stepping A2 */
7309 PCIDevSetByte( pPciDev, VBOX_PCI_REVISION_ID, 0x02);
7310 /* Ethernet adapter */
7311 PCIDevSetByte( pPciDev, VBOX_PCI_CLASS_PROG, 0x00);
7312 PCIDevSetWord( pPciDev, VBOX_PCI_CLASS_DEVICE, 0x0200);
7313 /* normal single function Ethernet controller */
7314 PCIDevSetByte( pPciDev, VBOX_PCI_HEADER_TYPE, 0x00);
7315 /* Memory Register Base Address */
7316 PCIDevSetDWord(pPciDev, VBOX_PCI_BASE_ADDRESS_0, 0x00000000);
7317 /* Memory Flash Base Address */
7318 PCIDevSetDWord(pPciDev, VBOX_PCI_BASE_ADDRESS_1, 0x00000000);
7319 /* IO Register Base Address */
7320 PCIDevSetDWord(pPciDev, VBOX_PCI_BASE_ADDRESS_2, 0x00000001);
7321 /* Expansion ROM Base Address */
7322 PCIDevSetDWord(pPciDev, VBOX_PCI_ROM_ADDRESS, 0x00000000);
7323 /* Capabilities Pointer */
7324 PCIDevSetByte( pPciDev, VBOX_PCI_CAPABILITY_LIST, 0xDC);
7325 /* Interrupt Pin: INTA# */
7326 PCIDevSetByte( pPciDev, VBOX_PCI_INTERRUPT_PIN, 0x01);
7327 /* Max_Lat/Min_Gnt: very high priority and time slice */
7328 PCIDevSetByte( pPciDev, VBOX_PCI_MIN_GNT, 0xFF);
7329 PCIDevSetByte( pPciDev, VBOX_PCI_MAX_LAT, 0x00);
7330
7331 /* PCI Power Management Registers ****************************************/
7332 /* Capability ID: PCI Power Management Registers */
7333 PCIDevSetByte( pPciDev, 0xDC, VBOX_PCI_CAP_ID_PM);
7334 /* Next Item Pointer: PCI-X */
7335 PCIDevSetByte( pPciDev, 0xDC + 1, 0xE4);
7336 /* Power Management Capabilities: PM disabled, DSI */
7337 PCIDevSetWord( pPciDev, 0xDC + 2,
7338 0x0002 | VBOX_PCI_PM_CAP_DSI);
7339 /* Power Management Control / Status Register: PM disabled */
7340 PCIDevSetWord( pPciDev, 0xDC + 4, 0x0000);
7341 /* PMCSR_BSE Bridge Support Extensions: Not supported */
7342 PCIDevSetByte( pPciDev, 0xDC + 6, 0x00);
7343 /* Data Register: PM disabled, always 0 */
7344 PCIDevSetByte( pPciDev, 0xDC + 7, 0x00);
7345
7346 /* PCI-X Configuration Registers *****************************************/
7347 /* Capability ID: PCI-X Configuration Registers */
7348 PCIDevSetByte( pPciDev, 0xE4, VBOX_PCI_CAP_ID_PCIX);
7349#ifdef E1K_WITH_MSI
7350 PCIDevSetByte( pPciDev, 0xE4 + 1, 0x80);
7351#else
7352 /* Next Item Pointer: None (Message Signalled Interrupts are disabled) */
7353 PCIDevSetByte( pPciDev, 0xE4 + 1, 0x00);
7354#endif
7355 /* PCI-X Command: Enable Relaxed Ordering */
7356 PCIDevSetWord( pPciDev, 0xE4 + 2, VBOX_PCI_X_CMD_ERO);
7357 /* PCI-X Status: 32-bit, 66MHz*/
7358 /** @todo is this value really correct? fff8 doesn't look like actual PCI address */
7359 PCIDevSetDWord(pPciDev, 0xE4 + 4, 0x0040FFF8);
7360}
7361
7362/**
7363 * @interface_method_impl{PDMDEVREG,pfnConstruct}
7364 */
7365static DECLCALLBACK(int) e1kR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
7366{
7367 PE1KSTATE pThis = PDMINS_2_DATA(pDevIns, E1KSTATE*);
7368 int rc;
7369 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
7370
7371 /*
7372 * Initialize the instance data (state).
7373 * Note! Caller has initialized it to ZERO already.
7374 */
7375 RTStrPrintf(pThis->szPrf, sizeof(pThis->szPrf), "E1000#%d", iInstance);
7376 E1kLog(("%s Constructing new instance sizeof(E1KRXDESC)=%d\n", pThis->szPrf, sizeof(E1KRXDESC)));
7377 pThis->hEventMoreRxDescAvail = NIL_RTSEMEVENT;
7378 pThis->pDevInsR3 = pDevIns;
7379 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
7380 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
7381 pThis->u16TxPktLen = 0;
7382 pThis->fIPcsum = false;
7383 pThis->fTCPcsum = false;
7384 pThis->fIntMaskUsed = false;
7385 pThis->fDelayInts = false;
7386 pThis->fLocked = false;
7387 pThis->u64AckedAt = 0;
7388 pThis->led.u32Magic = PDMLED_MAGIC;
7389 pThis->u32PktNo = 1;
7390
7391 /* Interfaces */
7392 pThis->IBase.pfnQueryInterface = e1kR3QueryInterface;
7393
7394 pThis->INetworkDown.pfnWaitReceiveAvail = e1kR3NetworkDown_WaitReceiveAvail;
7395 pThis->INetworkDown.pfnReceive = e1kR3NetworkDown_Receive;
7396 pThis->INetworkDown.pfnXmitPending = e1kR3NetworkDown_XmitPending;
7397
7398 pThis->ILeds.pfnQueryStatusLed = e1kR3QueryStatusLed;
7399
7400 pThis->INetworkConfig.pfnGetMac = e1kR3GetMac;
7401 pThis->INetworkConfig.pfnGetLinkState = e1kR3GetLinkState;
7402 pThis->INetworkConfig.pfnSetLinkState = e1kR3SetLinkState;
7403
7404 /*
7405 * Internal validations.
7406 */
7407 for (uint32_t iReg = 1; iReg < E1K_NUM_OF_BINARY_SEARCHABLE; iReg++)
7408 AssertLogRelMsgReturn( g_aE1kRegMap[iReg].offset > g_aE1kRegMap[iReg - 1].offset
7409 && g_aE1kRegMap[iReg].offset + g_aE1kRegMap[iReg].size
7410 >= g_aE1kRegMap[iReg - 1].offset + g_aE1kRegMap[iReg - 1].size,
7411 ("%s@%#xLB%#x vs %s@%#xLB%#x\n",
7412 g_aE1kRegMap[iReg].abbrev, g_aE1kRegMap[iReg].offset, g_aE1kRegMap[iReg].size,
7413 g_aE1kRegMap[iReg - 1].abbrev, g_aE1kRegMap[iReg - 1].offset, g_aE1kRegMap[iReg - 1].size),
7414 VERR_INTERNAL_ERROR_4);
7415
7416 /*
7417 * Validate configuration.
7418 */
7419 if (!CFGMR3AreValuesValid(pCfg, "MAC\0" "CableConnected\0" "AdapterType\0"
7420 "LineSpeed\0" "GCEnabled\0" "R0Enabled\0"
7421 "EthernetCRC\0" "GSOEnabled\0" "LinkUpDelay\0"))
7422 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
7423 N_("Invalid configuration for E1000 device"));
7424
7425 /** @todo: LineSpeed unused! */
7426
7427 pThis->fR0Enabled = true;
7428 pThis->fRCEnabled = true;
7429 pThis->fEthernetCRC = true;
7430 pThis->fGSOEnabled = true;
7431
7432 /* Get config params */
7433 rc = CFGMR3QueryBytes(pCfg, "MAC", pThis->macConfigured.au8, sizeof(pThis->macConfigured.au8));
7434 if (RT_FAILURE(rc))
7435 return PDMDEV_SET_ERROR(pDevIns, rc,
7436 N_("Configuration error: Failed to get MAC address"));
7437 rc = CFGMR3QueryBool(pCfg, "CableConnected", &pThis->fCableConnected);
7438 if (RT_FAILURE(rc))
7439 return PDMDEV_SET_ERROR(pDevIns, rc,
7440 N_("Configuration error: Failed to get the value of 'CableConnected'"));
7441 rc = CFGMR3QueryU32(pCfg, "AdapterType", (uint32_t*)&pThis->eChip);
7442 if (RT_FAILURE(rc))
7443 return PDMDEV_SET_ERROR(pDevIns, rc,
7444 N_("Configuration error: Failed to get the value of 'AdapterType'"));
7445 Assert(pThis->eChip <= E1K_CHIP_82545EM);
7446 rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &pThis->fRCEnabled, true);
7447 if (RT_FAILURE(rc))
7448 return PDMDEV_SET_ERROR(pDevIns, rc,
7449 N_("Configuration error: Failed to get the value of 'GCEnabled'"));
7450
7451 rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &pThis->fR0Enabled, true);
7452 if (RT_FAILURE(rc))
7453 return PDMDEV_SET_ERROR(pDevIns, rc,
7454 N_("Configuration error: Failed to get the value of 'R0Enabled'"));
7455
7456 rc = CFGMR3QueryBoolDef(pCfg, "EthernetCRC", &pThis->fEthernetCRC, true);
7457 if (RT_FAILURE(rc))
7458 return PDMDEV_SET_ERROR(pDevIns, rc,
7459 N_("Configuration error: Failed to get the value of 'EthernetCRC'"));
7460
7461 rc = CFGMR3QueryBoolDef(pCfg, "GSOEnabled", &pThis->fGSOEnabled, true);
7462 if (RT_FAILURE(rc))
7463 return PDMDEV_SET_ERROR(pDevIns, rc,
7464 N_("Configuration error: Failed to get the value of 'GSOEnabled'"));
7465
7466 rc = CFGMR3QueryU32Def(pCfg, "LinkUpDelay", (uint32_t*)&pThis->cMsLinkUpDelay, 5000); /* ms */
7467 if (RT_FAILURE(rc))
7468 return PDMDEV_SET_ERROR(pDevIns, rc,
7469 N_("Configuration error: Failed to get the value of 'LinkUpDelay'"));
7470 Assert(pThis->cMsLinkUpDelay <= 300000); /* less than 5 minutes */
7471 if (pThis->cMsLinkUpDelay > 5000)
7472 LogRel(("%s WARNING! Link up delay is set to %u seconds!\n", pThis->szPrf, pThis->cMsLinkUpDelay / 1000));
7473 else if (pThis->cMsLinkUpDelay == 0)
7474 LogRel(("%s WARNING! Link up delay is disabled!\n", pThis->szPrf));
7475
7476 E1kLog(("%s Chip=%s LinkUpDelay=%ums EthernetCRC=%s GSO=%s R0=%s GC=%s\n", pThis->szPrf,
7477 g_Chips[pThis->eChip].pcszName, pThis->cMsLinkUpDelay,
7478 pThis->fEthernetCRC ? "on" : "off",
7479 pThis->fGSOEnabled ? "enabled" : "disabled",
7480 pThis->fR0Enabled ? "enabled" : "disabled",
7481 pThis->fRCEnabled ? "enabled" : "disabled"));
7482
7483 /* Initialize the EEPROM. */
7484 pThis->eeprom.init(pThis->macConfigured);
7485
7486 /* Initialize internal PHY. */
7487 Phy::init(&pThis->phy, iInstance, pThis->eChip == E1K_CHIP_82543GC ? PHY_EPID_M881000 : PHY_EPID_M881011);
7488 Phy::setLinkStatus(&pThis->phy, pThis->fCableConnected);
7489
7490 /* Initialize critical sections. We do our own locking. */
7491 rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
7492 AssertRCReturn(rc, rc);
7493
7494 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->cs, RT_SRC_POS, "E1000#%d", iInstance);
7495 if (RT_FAILURE(rc))
7496 return rc;
7497 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->csRx, RT_SRC_POS, "E1000#%dRX", iInstance);
7498 if (RT_FAILURE(rc))
7499 return rc;
7500#ifdef E1K_WITH_TX_CS
7501 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->csTx, RT_SRC_POS, "E1000#%dTX", iInstance);
7502 if (RT_FAILURE(rc))
7503 return rc;
7504#endif /* E1K_WITH_TX_CS */
7505
7506 /* Saved state registration. */
7507 rc = PDMDevHlpSSMRegisterEx(pDevIns, E1K_SAVEDSTATE_VERSION, sizeof(E1KSTATE), NULL,
7508 NULL, e1kLiveExec, NULL,
7509 e1kSavePrep, e1kSaveExec, NULL,
7510 e1kLoadPrep, e1kLoadExec, e1kLoadDone);
7511 if (RT_FAILURE(rc))
7512 return rc;
7513
7514 /* Set PCI config registers and register ourselves with the PCI bus. */
7515 e1kConfigurePciDev(&pThis->pciDevice, pThis->eChip);
7516 rc = PDMDevHlpPCIRegister(pDevIns, &pThis->pciDevice);
7517 if (RT_FAILURE(rc))
7518 return rc;
7519
7520#ifdef E1K_WITH_MSI
7521 PDMMSIREG MsiReg;
7522 RT_ZERO(MsiReg);
7523 MsiReg.cMsiVectors = 1;
7524 MsiReg.iMsiCapOffset = 0x80;
7525 MsiReg.iMsiNextOffset = 0x0;
7526 MsiReg.fMsi64bit = false;
7527 rc = PDMDevHlpPCIRegisterMsi(pDevIns, &MsiReg);
7528 AssertRCReturn(rc, rc);
7529#endif
7530
7531
7532 /* Map our registers to memory space (region 0, see e1kConfigurePCI)*/
7533 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0, E1K_MM_SIZE, PCI_ADDRESS_SPACE_MEM, e1kMap);
7534 if (RT_FAILURE(rc))
7535 return rc;
7536 /* Map our registers to IO space (region 2, see e1kConfigurePCI) */
7537 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 2, E1K_IOPORT_SIZE, PCI_ADDRESS_SPACE_IO, e1kMap);
7538 if (RT_FAILURE(rc))
7539 return rc;
7540
7541 /* Create transmit queue */
7542 rc = PDMDevHlpQueueCreate(pDevIns, sizeof(PDMQUEUEITEMCORE), 1, 0,
7543 e1kTxQueueConsumer, true, "E1000-Xmit", &pThis->pTxQueueR3);
7544 if (RT_FAILURE(rc))
7545 return rc;
7546 pThis->pTxQueueR0 = PDMQueueR0Ptr(pThis->pTxQueueR3);
7547 pThis->pTxQueueRC = PDMQueueRCPtr(pThis->pTxQueueR3);
7548
7549 /* Create the RX notifier signaller. */
7550 rc = PDMDevHlpQueueCreate(pDevIns, sizeof(PDMQUEUEITEMCORE), 1, 0,
7551 e1kCanRxQueueConsumer, true, "E1000-Rcv", &pThis->pCanRxQueueR3);
7552 if (RT_FAILURE(rc))
7553 return rc;
7554 pThis->pCanRxQueueR0 = PDMQueueR0Ptr(pThis->pCanRxQueueR3);
7555 pThis->pCanRxQueueRC = PDMQueueRCPtr(pThis->pCanRxQueueR3);
7556
7557#ifdef E1K_TX_DELAY
7558 /* Create Transmit Delay Timer */
7559 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, e1kTxDelayTimer, pThis,
7560 TMTIMER_FLAGS_NO_CRIT_SECT,
7561 "E1000 Transmit Delay Timer", &pThis->pTXDTimerR3);
7562 if (RT_FAILURE(rc))
7563 return rc;
7564 pThis->pTXDTimerR0 = TMTimerR0Ptr(pThis->pTXDTimerR3);
7565 pThis->pTXDTimerRC = TMTimerRCPtr(pThis->pTXDTimerR3);
7566 TMR3TimerSetCritSect(pThis->pTXDTimerR3, &pThis->csTx);
7567#endif /* E1K_TX_DELAY */
7568
7569#ifdef E1K_USE_TX_TIMERS
7570 /* Create Transmit Interrupt Delay Timer */
7571 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, e1kTxIntDelayTimer, pThis,
7572 TMTIMER_FLAGS_NO_CRIT_SECT,
7573 "E1000 Transmit Interrupt Delay Timer", &pThis->pTIDTimerR3);
7574 if (RT_FAILURE(rc))
7575 return rc;
7576 pThis->pTIDTimerR0 = TMTimerR0Ptr(pThis->pTIDTimerR3);
7577 pThis->pTIDTimerRC = TMTimerRCPtr(pThis->pTIDTimerR3);
7578
7579# ifndef E1K_NO_TAD
7580 /* Create Transmit Absolute Delay Timer */
7581 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, e1kTxAbsDelayTimer, pThis,
7582 TMTIMER_FLAGS_NO_CRIT_SECT,
7583 "E1000 Transmit Absolute Delay Timer", &pThis->pTADTimerR3);
7584 if (RT_FAILURE(rc))
7585 return rc;
7586 pThis->pTADTimerR0 = TMTimerR0Ptr(pThis->pTADTimerR3);
7587 pThis->pTADTimerRC = TMTimerRCPtr(pThis->pTADTimerR3);
7588# endif /* E1K_NO_TAD */
7589#endif /* E1K_USE_TX_TIMERS */
7590
7591#ifdef E1K_USE_RX_TIMERS
7592 /* Create Receive Interrupt Delay Timer */
7593 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, e1kRxIntDelayTimer, pThis,
7594 TMTIMER_FLAGS_NO_CRIT_SECT,
7595 "E1000 Receive Interrupt Delay Timer", &pThis->pRIDTimerR3);
7596 if (RT_FAILURE(rc))
7597 return rc;
7598 pThis->pRIDTimerR0 = TMTimerR0Ptr(pThis->pRIDTimerR3);
7599 pThis->pRIDTimerRC = TMTimerRCPtr(pThis->pRIDTimerR3);
7600
7601 /* Create Receive Absolute Delay Timer */
7602 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, e1kRxAbsDelayTimer, pThis,
7603 TMTIMER_FLAGS_NO_CRIT_SECT,
7604 "E1000 Receive Absolute Delay Timer", &pThis->pRADTimerR3);
7605 if (RT_FAILURE(rc))
7606 return rc;
7607 pThis->pRADTimerR0 = TMTimerR0Ptr(pThis->pRADTimerR3);
7608 pThis->pRADTimerRC = TMTimerRCPtr(pThis->pRADTimerR3);
7609#endif /* E1K_USE_RX_TIMERS */
7610
7611 /* Create Late Interrupt Timer */
7612 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, e1kLateIntTimer, pThis,
7613 TMTIMER_FLAGS_NO_CRIT_SECT,
7614 "E1000 Late Interrupt Timer", &pThis->pIntTimerR3);
7615 if (RT_FAILURE(rc))
7616 return rc;
7617 pThis->pIntTimerR0 = TMTimerR0Ptr(pThis->pIntTimerR3);
7618 pThis->pIntTimerRC = TMTimerRCPtr(pThis->pIntTimerR3);
7619
7620 /* Create Link Up Timer */
7621 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, e1kLinkUpTimer, pThis,
7622 TMTIMER_FLAGS_NO_CRIT_SECT,
7623 "E1000 Link Up Timer", &pThis->pLUTimerR3);
7624 if (RT_FAILURE(rc))
7625 return rc;
7626 pThis->pLUTimerR0 = TMTimerR0Ptr(pThis->pLUTimerR3);
7627 pThis->pLUTimerRC = TMTimerRCPtr(pThis->pLUTimerR3);
7628
7629 /* Register the info item */
7630 char szTmp[20];
7631 RTStrPrintf(szTmp, sizeof(szTmp), "e1k%d", iInstance);
7632 PDMDevHlpDBGFInfoRegister(pDevIns, szTmp, "E1000 info.", e1kInfo);
7633
7634 /* Status driver */
7635 PPDMIBASE pBase;
7636 rc = PDMDevHlpDriverAttach(pDevIns, PDM_STATUS_LUN, &pThis->IBase, &pBase, "Status Port");
7637 if (RT_FAILURE(rc))
7638 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to attach the status LUN"));
7639 pThis->pLedsConnector = PDMIBASE_QUERY_INTERFACE(pBase, PDMILEDCONNECTORS);
7640
7641 /* Network driver */
7642 rc = PDMDevHlpDriverAttach(pDevIns, 0, &pThis->IBase, &pThis->pDrvBase, "Network Port");
7643 if (RT_SUCCESS(rc))
7644 {
7645 if (rc == VINF_NAT_DNS)
7646 PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "NoDNSforNAT",
7647 N_("A Domain Name Server (DNS) for NAT networking could not be determined. Ensure that your host is correctly connected to an ISP. If you ignore this warning the guest will not be able to perform nameserver lookups and it will probably observe delays if trying so"));
7648 pThis->pDrvR3 = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMINETWORKUP);
7649 AssertMsgReturn(pThis->pDrvR3, ("Failed to obtain the PDMINETWORKUP interface!\n"), VERR_PDM_MISSING_INTERFACE_BELOW);
7650
7651 pThis->pDrvR0 = PDMIBASER0_QUERY_INTERFACE(PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMIBASER0), PDMINETWORKUP);
7652 pThis->pDrvRC = PDMIBASERC_QUERY_INTERFACE(PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMIBASERC), PDMINETWORKUP);
7653 }
7654 else if ( rc == VERR_PDM_NO_ATTACHED_DRIVER
7655 || rc == VERR_PDM_CFG_MISSING_DRIVER_NAME)
7656 {
7657 /* No error! */
7658 E1kLog(("%s This adapter is not attached to any network!\n", pThis->szPrf));
7659 }
7660 else
7661 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to attach the network LUN"));
7662
7663 rc = RTSemEventCreate(&pThis->hEventMoreRxDescAvail);
7664 if (RT_FAILURE(rc))
7665 return rc;
7666
7667 rc = e1kInitDebugHelpers();
7668 if (RT_FAILURE(rc))
7669 return rc;
7670
7671 e1kHardReset(pThis);
7672
7673 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatReceiveBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Amount of data received", "/Public/Net/E1k%u/BytesReceived", iInstance);
7674 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatTransmitBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Amount of data transmitted", "/Public/Net/E1k%u/BytesTransmitted", iInstance);
7675
7676 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatReceiveBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Amount of data received", "/Devices/E1k%d/ReceiveBytes", iInstance);
7677 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatTransmitBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Amount of data transmitted", "/Devices/E1k%d/TransmitBytes", iInstance);
7678
7679#if defined(VBOX_WITH_STATISTICS)
7680 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatMMIOReadRZ, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling MMIO reads in RZ", "/Devices/E1k%d/MMIO/ReadRZ", iInstance);
7681 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatMMIOReadR3, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling MMIO reads in R3", "/Devices/E1k%d/MMIO/ReadR3", iInstance);
7682 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatMMIOWriteRZ, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling MMIO writes in RZ", "/Devices/E1k%d/MMIO/WriteRZ", iInstance);
7683 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatMMIOWriteR3, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling MMIO writes in R3", "/Devices/E1k%d/MMIO/WriteR3", iInstance);
7684 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatEEPROMRead, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling EEPROM reads", "/Devices/E1k%d/EEPROM/Read", iInstance);
7685 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatEEPROMWrite, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling EEPROM writes", "/Devices/E1k%d/EEPROM/Write", iInstance);
7686 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatIOReadRZ, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling IO reads in RZ", "/Devices/E1k%d/IO/ReadRZ", iInstance);
7687 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatIOReadR3, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling IO reads in R3", "/Devices/E1k%d/IO/ReadR3", iInstance);
7688 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatIOWriteRZ, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling IO writes in RZ", "/Devices/E1k%d/IO/WriteRZ", iInstance);
7689 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatIOWriteR3, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling IO writes in R3", "/Devices/E1k%d/IO/WriteR3", iInstance);
7690 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatLateIntTimer, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling late int timer", "/Devices/E1k%d/LateInt/Timer", iInstance);
7691 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatLateInts, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of late interrupts", "/Devices/E1k%d/LateInt/Occured", iInstance);
7692 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatIntsRaised, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of raised interrupts", "/Devices/E1k%d/Interrupts/Raised", iInstance);
7693 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatIntsPrevented, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of prevented interrupts", "/Devices/E1k%d/Interrupts/Prevented", iInstance);
7694 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatReceive, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling receive", "/Devices/E1k%d/Receive/Total", iInstance);
7695 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatReceiveCRC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling receive checksumming", "/Devices/E1k%d/Receive/CRC", iInstance);
7696 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatReceiveFilter, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling receive filtering", "/Devices/E1k%d/Receive/Filter", iInstance);
7697 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatReceiveStore, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling receive storing", "/Devices/E1k%d/Receive/Store", iInstance);
7698 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatRxOverflow, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_OCCURENCE, "Profiling RX overflows", "/Devices/E1k%d/RxOverflow", iInstance);
7699 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatRxOverflowWakeup, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of RX overflow wakeups", "/Devices/E1k%d/RxOverflowWakeup", iInstance);
7700 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatTransmitRZ, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling transmits in RZ", "/Devices/E1k%d/Transmit/TotalRZ", iInstance);
7701 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatTransmitR3, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling transmits in R3", "/Devices/E1k%d/Transmit/TotalR3", iInstance);
7702 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatTransmitSendRZ, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling send transmit in RZ", "/Devices/E1k%d/Transmit/SendRZ", iInstance);
7703 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatTransmitSendR3, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling send transmit in R3", "/Devices/E1k%d/Transmit/SendR3", iInstance);
7704
7705 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatTxDescCtxNormal, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of normal context descriptors","/Devices/E1k%d/TxDesc/ContexNormal", iInstance);
7706 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatTxDescCtxTSE, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of TSE context descriptors", "/Devices/E1k%d/TxDesc/ContextTSE", iInstance);
7707 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatTxDescData, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of TX data descriptors", "/Devices/E1k%d/TxDesc/Data", iInstance);
7708 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatTxDescLegacy, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of TX legacy descriptors", "/Devices/E1k%d/TxDesc/Legacy", iInstance);
7709 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatTxDescTSEData, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of TX TSE data descriptors", "/Devices/E1k%d/TxDesc/TSEData", iInstance);
7710 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatTxPathFallback, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Fallback TSE descriptor path", "/Devices/E1k%d/TxPath/Fallback", iInstance);
7711 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatTxPathGSO, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "GSO TSE descriptor path", "/Devices/E1k%d/TxPath/GSO", iInstance);
7712 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatTxPathRegular, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Regular descriptor path", "/Devices/E1k%d/TxPath/Normal", iInstance);
7713 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatPHYAccesses, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of PHY accesses", "/Devices/E1k%d/PHYAccesses", iInstance);
7714 for (unsigned iReg = 0; iReg < E1K_NUM_OF_REGS; iReg++)
7715 {
7716 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->aStatRegReads[iReg], STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
7717 g_aE1kRegMap[iReg].name, "/Devices/E1k%d/Regs/%s-Reads", iInstance, g_aE1kRegMap[iReg].abbrev);
7718 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->aStatRegWrites[iReg], STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
7719 g_aE1kRegMap[iReg].name, "/Devices/E1k%d/Regs/%s-Writes", iInstance, g_aE1kRegMap[iReg].abbrev);
7720 }
7721#endif /* VBOX_WITH_STATISTICS */
7722
7723#ifdef E1K_INT_STATS
7724 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->u64ArmedAt, STAMTYPE_U64, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "u64ArmedAt", "/Devices/E1k%d/u64ArmedAt", iInstance);
7725 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatMaxTxDelay, STAMTYPE_U64, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatMaxTxDelay", "/Devices/E1k%d/uStatMaxTxDelay", iInstance);
7726 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatInt, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatInt", "/Devices/E1k%d/uStatInt", iInstance);
7727 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatIntTry, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatIntTry", "/Devices/E1k%d/uStatIntTry", iInstance);
7728 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatIntLower, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatIntLower", "/Devices/E1k%d/uStatIntLower", iInstance);
7729 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatIntDly, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatIntDly", "/Devices/E1k%d/uStatIntDly", iInstance);
7730 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->iStatIntLost, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "iStatIntLost", "/Devices/E1k%d/iStatIntLost", iInstance);
7731 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->iStatIntLostOne, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "iStatIntLostOne", "/Devices/E1k%d/iStatIntLostOne", iInstance);
7732 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatDisDly, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatDisDly", "/Devices/E1k%d/uStatDisDly", iInstance);
7733 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatIntSkip, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatIntSkip", "/Devices/E1k%d/uStatIntSkip", iInstance);
7734 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatIntLate, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatIntLate", "/Devices/E1k%d/uStatIntLate", iInstance);
7735 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatIntMasked, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatIntMasked", "/Devices/E1k%d/uStatIntMasked", iInstance);
7736 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatIntEarly, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatIntEarly", "/Devices/E1k%d/uStatIntEarly", iInstance);
7737 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatIntRx, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatIntRx", "/Devices/E1k%d/uStatIntRx", iInstance);
7738 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatIntTx, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatIntTx", "/Devices/E1k%d/uStatIntTx", iInstance);
7739 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatIntICS, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatIntICS", "/Devices/E1k%d/uStatIntICS", iInstance);
7740 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatIntRDTR, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatIntRDTR", "/Devices/E1k%d/uStatIntRDTR", iInstance);
7741 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatIntRXDMT0, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatIntRXDMT0", "/Devices/E1k%d/uStatIntRXDMT0", iInstance);
7742 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatIntTXQE, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatIntTXQE", "/Devices/E1k%d/uStatIntTXQE", iInstance);
7743 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatTxNoRS, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatTxNoRS", "/Devices/E1k%d/uStatTxNoRS", iInstance);
7744 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatTxIDE, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatTxIDE", "/Devices/E1k%d/uStatTxIDE", iInstance);
7745 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatTxDelayed, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatTxDelayed", "/Devices/E1k%d/uStatTxDelayed", iInstance);
7746 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatTxDelayExp, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatTxDelayExp", "/Devices/E1k%d/uStatTxDelayExp", iInstance);
7747 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatTAD, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatTAD", "/Devices/E1k%d/uStatTAD", iInstance);
7748 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatTID, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatTID", "/Devices/E1k%d/uStatTID", iInstance);
7749 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatRAD, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatRAD", "/Devices/E1k%d/uStatRAD", iInstance);
7750 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatRID, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatRID", "/Devices/E1k%d/uStatRID", iInstance);
7751 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatRxFrm, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatRxFrm", "/Devices/E1k%d/uStatRxFrm", iInstance);
7752 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatTxFrm, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatTxFrm", "/Devices/E1k%d/uStatTxFrm", iInstance);
7753 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatDescCtx, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatDescCtx", "/Devices/E1k%d/uStatDescCtx", iInstance);
7754 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatDescDat, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatDescDat", "/Devices/E1k%d/uStatDescDat", iInstance);
7755 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatDescLeg, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatDescLeg", "/Devices/E1k%d/uStatDescLeg", iInstance);
7756 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatTx1514, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatTx1514", "/Devices/E1k%d/uStatTx1514", iInstance);
7757 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatTx2962, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatTx2962", "/Devices/E1k%d/uStatTx2962", iInstance);
7758 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatTx4410, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatTx4410", "/Devices/E1k%d/uStatTx4410", iInstance);
7759 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatTx5858, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatTx5858", "/Devices/E1k%d/uStatTx5858", iInstance);
7760 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatTx7306, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatTx7306", "/Devices/E1k%d/uStatTx7306", iInstance);
7761 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatTx8754, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatTx8754", "/Devices/E1k%d/uStatTx8754", iInstance);
7762 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatTx16384, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatTx16384", "/Devices/E1k%d/uStatTx16384", iInstance);
7763 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatTx32768, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatTx32768", "/Devices/E1k%d/uStatTx32768", iInstance);
7764 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatTxLarge, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatTxLarge", "/Devices/E1k%d/uStatTxLarge", iInstance);
7765#endif /* E1K_INT_STATS */
7766
7767 return VINF_SUCCESS;
7768}
7769
7770/**
7771 * The device registration structure.
7772 */
7773const PDMDEVREG g_DeviceE1000 =
7774{
7775 /* Structure version. PDM_DEVREG_VERSION defines the current version. */
7776 PDM_DEVREG_VERSION,
7777 /* Device name. */
7778 "e1000",
7779 /* Name of guest context module (no path).
7780 * Only evalutated if PDM_DEVREG_FLAGS_RC is set. */
7781 "VBoxDDGC.gc",
7782 /* Name of ring-0 module (no path).
7783 * Only evalutated if PDM_DEVREG_FLAGS_RC is set. */
7784 "VBoxDDR0.r0",
7785 /* The description of the device. The UTF-8 string pointed to shall, like this structure,
7786 * remain unchanged from registration till VM destruction. */
7787 "Intel PRO/1000 MT Desktop Ethernet.\n",
7788
7789 /* Flags, combination of the PDM_DEVREG_FLAGS_* \#defines. */
7790 PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
7791 /* Device class(es), combination of the PDM_DEVREG_CLASS_* \#defines. */
7792 PDM_DEVREG_CLASS_NETWORK,
7793 /* Maximum number of instances (per VM). */
7794 ~0U,
7795 /* Size of the instance data. */
7796 sizeof(E1KSTATE),
7797
7798 /* pfnConstruct */
7799 e1kR3Construct,
7800 /* pfnDestruct */
7801 e1kR3Destruct,
7802 /* pfnRelocate */
7803 e1kR3Relocate,
7804 /* pfnMemSetup */
7805 NULL,
7806 /* pfnPowerOn */
7807 NULL,
7808 /* pfnReset */
7809 e1kR3Reset,
7810 /* pfnSuspend */
7811 e1kR3Suspend,
7812 /* pfnResume */
7813 NULL,
7814 /* pfnAttach */
7815 e1kR3Attach,
7816 /* pfnDeatch */
7817 e1kR3Detach,
7818 /* pfnQueryInterface */
7819 NULL,
7820 /* pfnInitComplete */
7821 NULL,
7822 /* pfnPowerOff */
7823 e1kR3PowerOff,
7824 /* pfnSoftReset */
7825 NULL,
7826
7827 /* u32VersionEnd */
7828 PDM_DEVREG_VERSION
7829};
7830
7831#endif /* IN_RING3 */
7832#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette