VirtualBox

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

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

Devices/E1000: warning

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 316.2 KB
Line 
1/* $Id: DevE1000.cpp 49493 2013-11-15 10:13:23Z 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 if (pTimer == pThis->CTX_SUFF(pLUTimer))
1530 return "LinkUp";
1531 return "unknown";
1532}
1533
1534#endif /* DEBUG */
1535
1536/**
1537 * Arm a timer.
1538 *
1539 * @param pThis Pointer to the device state structure.
1540 * @param pTimer Pointer to the timer.
1541 * @param uExpireIn Expiration interval in microseconds.
1542 */
1543DECLINLINE(void) e1kArmTimer(PE1KSTATE pThis, PTMTIMER pTimer, uint32_t uExpireIn)
1544{
1545 if (pThis->fLocked)
1546 return;
1547
1548 E1kLog2(("%s Arming %s timer to fire in %d usec...\n",
1549 pThis->szPrf, e1kGetTimerName(pThis, pTimer), uExpireIn));
1550 TMTimerSetMicro(pTimer, uExpireIn);
1551}
1552
1553/**
1554 * Cancel a timer.
1555 *
1556 * @param pThis Pointer to the device state structure.
1557 * @param pTimer Pointer to the timer.
1558 */
1559DECLINLINE(void) e1kCancelTimer(PE1KSTATE pThis, PTMTIMER pTimer)
1560{
1561 E1kLog2(("%s Stopping %s timer...\n",
1562 pThis->szPrf, e1kGetTimerName(pThis, pTimer)));
1563 int rc = TMTimerStop(pTimer);
1564 if (RT_FAILURE(rc))
1565 {
1566 E1kLog2(("%s e1kCancelTimer: TMTimerStop() failed with %Rrc\n",
1567 pThis->szPrf, rc));
1568 }
1569}
1570
1571#define e1kCsEnter(ps, rc) PDMCritSectEnter(&ps->cs, rc)
1572#define e1kCsLeave(ps) PDMCritSectLeave(&ps->cs)
1573
1574#define e1kCsRxEnter(ps, rc) PDMCritSectEnter(&ps->csRx, rc)
1575#define e1kCsRxLeave(ps) PDMCritSectLeave(&ps->csRx)
1576#define e1kCsRxIsOwner(ps) PDMCritSectIsOwner(&ps->csRx)
1577
1578#ifndef E1K_WITH_TX_CS
1579# define e1kCsTxEnter(ps, rc) VINF_SUCCESS
1580# define e1kCsTxLeave(ps) do { } while (0)
1581#else /* E1K_WITH_TX_CS */
1582# define e1kCsTxEnter(ps, rc) PDMCritSectEnter(&ps->csTx, rc)
1583# define e1kCsTxLeave(ps) PDMCritSectLeave(&ps->csTx)
1584#endif /* E1K_WITH_TX_CS */
1585
1586#ifdef IN_RING3
1587
1588/**
1589 * Wakeup the RX thread.
1590 */
1591static void e1kWakeupReceive(PPDMDEVINS pDevIns)
1592{
1593 PE1KSTATE pThis = PDMINS_2_DATA(pDevIns, PE1KSTATE);
1594 if ( pThis->fMaybeOutOfSpace
1595 && pThis->hEventMoreRxDescAvail != NIL_RTSEMEVENT)
1596 {
1597 STAM_COUNTER_INC(&pThis->StatRxOverflowWakeup);
1598 E1kLog(("%s Waking up Out-of-RX-space semaphore\n", pThis->szPrf));
1599 RTSemEventSignal(pThis->hEventMoreRxDescAvail);
1600 }
1601}
1602
1603/**
1604 * Hardware reset. Revert all registers to initial values.
1605 *
1606 * @param pThis The device state structure.
1607 */
1608static void e1kHardReset(PE1KSTATE pThis)
1609{
1610 E1kLog(("%s Hard reset triggered\n", pThis->szPrf));
1611 memset(pThis->auRegs, 0, sizeof(pThis->auRegs));
1612 memset(pThis->aRecAddr.au32, 0, sizeof(pThis->aRecAddr.au32));
1613#ifdef E1K_INIT_RA0
1614 memcpy(pThis->aRecAddr.au32, pThis->macConfigured.au8,
1615 sizeof(pThis->macConfigured.au8));
1616 pThis->aRecAddr.array[0].ctl |= RA_CTL_AV;
1617#endif /* E1K_INIT_RA0 */
1618 STATUS = 0x0081; /* SPEED=10b (1000 Mb/s), FD=1b (Full Duplex) */
1619 EECD = 0x0100; /* EE_PRES=1b (EEPROM present) */
1620 CTRL = 0x0a09; /* FRCSPD=1b SPEED=10b LRST=1b FD=1b */
1621 TSPMT = 0x01000400;/* TSMT=0400h TSPBP=0100h */
1622 Assert(GET_BITS(RCTL, BSIZE) == 0);
1623 pThis->u16RxBSize = 2048;
1624
1625 /* Reset promiscuous mode */
1626 if (pThis->pDrvR3)
1627 pThis->pDrvR3->pfnSetPromiscuousMode(pThis->pDrvR3, false);
1628
1629#ifdef E1K_WITH_TXD_CACHE
1630 int rc = e1kCsTxEnter(pThis, VERR_SEM_BUSY);
1631 if (RT_LIKELY(rc == VINF_SUCCESS))
1632 {
1633 pThis->nTxDFetched = 0;
1634 pThis->iTxDCurrent = 0;
1635 pThis->fGSO = false;
1636 pThis->cbTxAlloc = 0;
1637 e1kCsTxLeave(pThis);
1638 }
1639#endif /* E1K_WITH_TXD_CACHE */
1640#ifdef E1K_WITH_RXD_CACHE
1641 if (RT_LIKELY(e1kCsRxEnter(pThis, VERR_SEM_BUSY) == VINF_SUCCESS))
1642 {
1643 pThis->iRxDCurrent = pThis->nRxDFetched = 0;
1644 e1kCsRxLeave(pThis);
1645 }
1646#endif /* E1K_WITH_RXD_CACHE */
1647}
1648
1649#endif /* IN_RING3 */
1650
1651/**
1652 * Compute Internet checksum.
1653 *
1654 * @remarks Refer to http://www.netfor2.com/checksum.html for short intro.
1655 *
1656 * @param pThis The device state structure.
1657 * @param cpPacket The packet.
1658 * @param cb The size of the packet.
1659 * @param cszText A string denoting direction of packet transfer.
1660 *
1661 * @return The 1's complement of the 1's complement sum.
1662 *
1663 * @thread E1000_TX
1664 */
1665static uint16_t e1kCSum16(const void *pvBuf, size_t cb)
1666{
1667 uint32_t csum = 0;
1668 uint16_t *pu16 = (uint16_t *)pvBuf;
1669
1670 while (cb > 1)
1671 {
1672 csum += *pu16++;
1673 cb -= 2;
1674 }
1675 if (cb)
1676 csum += *(uint8_t*)pu16;
1677 while (csum >> 16)
1678 csum = (csum >> 16) + (csum & 0xFFFF);
1679 return ~csum;
1680}
1681
1682/**
1683 * Dump a packet to debug log.
1684 *
1685 * @param pThis The device state structure.
1686 * @param cpPacket The packet.
1687 * @param cb The size of the packet.
1688 * @param cszText A string denoting direction of packet transfer.
1689 * @thread E1000_TX
1690 */
1691DECLINLINE(void) e1kPacketDump(PE1KSTATE pThis, const uint8_t *cpPacket, size_t cb, const char *cszText)
1692{
1693#ifdef DEBUG
1694 if (RT_LIKELY(e1kCsEnter(pThis, VERR_SEM_BUSY) == VINF_SUCCESS))
1695 {
1696 Log4(("%s --- %s packet #%d: %RTmac => %RTmac (%d bytes) ---\n",
1697 pThis->szPrf, cszText, ++pThis->u32PktNo, cpPacket+6, cpPacket, cb));
1698 if (ntohs(*(uint16_t*)(cpPacket+12)) == 0x86DD)
1699 {
1700 Log4(("%s --- IPv6: %RTnaipv6 => %RTnaipv6\n",
1701 pThis->szPrf, cpPacket+14+8, cpPacket+14+24));
1702 if (*(cpPacket+14+6) == 0x6)
1703 Log4(("%s --- TCP: seq=%x ack=%x\n", pThis->szPrf,
1704 ntohl(*(uint32_t*)(cpPacket+14+40+4)), ntohl(*(uint32_t*)(cpPacket+14+40+8))));
1705 }
1706 else if (ntohs(*(uint16_t*)(cpPacket+12)) == 0x800)
1707 {
1708 Log4(("%s --- IPv4: %RTnaipv4 => %RTnaipv4\n",
1709 pThis->szPrf, *(uint32_t*)(cpPacket+14+12), *(uint32_t*)(cpPacket+14+16)));
1710 if (*(cpPacket+14+6) == 0x6)
1711 Log4(("%s --- TCP: seq=%x ack=%x\n", pThis->szPrf,
1712 ntohl(*(uint32_t*)(cpPacket+14+20+4)), ntohl(*(uint32_t*)(cpPacket+14+20+8))));
1713 }
1714 E1kLog3(("%.*Rhxd\n", cb, cpPacket));
1715 e1kCsLeave(pThis);
1716 }
1717#else
1718 if (RT_LIKELY(e1kCsEnter(pThis, VERR_SEM_BUSY) == VINF_SUCCESS))
1719 {
1720 if (ntohs(*(uint16_t*)(cpPacket+12)) == 0x86DD)
1721 E1kLogRel(("E1000: %s packet #%d, %RTmac => %RTmac, %RTnaipv6 => %RTnaipv6, seq=%x ack=%x\n",
1722 cszText, ++pThis->u32PktNo, cpPacket+6, cpPacket, cpPacket+14+8, cpPacket+14+24,
1723 ntohl(*(uint32_t*)(cpPacket+14+40+4)), ntohl(*(uint32_t*)(cpPacket+14+40+8))));
1724 else
1725 E1kLogRel(("E1000: %s packet #%d, %RTmac => %RTmac, %RTnaipv4 => %RTnaipv4, seq=%x ack=%x\n",
1726 cszText, ++pThis->u32PktNo, cpPacket+6, cpPacket,
1727 *(uint32_t*)(cpPacket+14+12), *(uint32_t*)(cpPacket+14+16),
1728 ntohl(*(uint32_t*)(cpPacket+14+20+4)), ntohl(*(uint32_t*)(cpPacket+14+20+8))));
1729 e1kCsLeave(pThis);
1730 }
1731#endif
1732}
1733
1734/**
1735 * Determine the type of transmit descriptor.
1736 *
1737 * @returns Descriptor type. See E1K_DTYP_XXX defines.
1738 *
1739 * @param pDesc Pointer to descriptor union.
1740 * @thread E1000_TX
1741 */
1742DECLINLINE(int) e1kGetDescType(E1KTXDESC* pDesc)
1743{
1744 if (pDesc->legacy.cmd.fDEXT)
1745 return pDesc->context.dw2.u4DTYP;
1746 return E1K_DTYP_LEGACY;
1747}
1748
1749/**
1750 * Dump receive descriptor to debug log.
1751 *
1752 * @param pThis The device state structure.
1753 * @param pDesc Pointer to the descriptor.
1754 * @thread E1000_RX
1755 */
1756static void e1kPrintRDesc(PE1KSTATE pThis, E1KRXDESC* pDesc)
1757{
1758 E1kLog2(("%s <-- Receive Descriptor (%d bytes):\n", pThis->szPrf, pDesc->u16Length));
1759 E1kLog2((" Address=%16LX Length=%04X Csum=%04X\n",
1760 pDesc->u64BufAddr, pDesc->u16Length, pDesc->u16Checksum));
1761 E1kLog2((" STA: %s %s %s %s %s %s %s ERR: %s %s %s %s SPECIAL: %s VLAN=%03x PRI=%x\n",
1762 pDesc->status.fPIF ? "PIF" : "pif",
1763 pDesc->status.fIPCS ? "IPCS" : "ipcs",
1764 pDesc->status.fTCPCS ? "TCPCS" : "tcpcs",
1765 pDesc->status.fVP ? "VP" : "vp",
1766 pDesc->status.fIXSM ? "IXSM" : "ixsm",
1767 pDesc->status.fEOP ? "EOP" : "eop",
1768 pDesc->status.fDD ? "DD" : "dd",
1769 pDesc->status.fRXE ? "RXE" : "rxe",
1770 pDesc->status.fIPE ? "IPE" : "ipe",
1771 pDesc->status.fTCPE ? "TCPE" : "tcpe",
1772 pDesc->status.fCE ? "CE" : "ce",
1773 E1K_SPEC_CFI(pDesc->status.u16Special) ? "CFI" :"cfi",
1774 E1K_SPEC_VLAN(pDesc->status.u16Special),
1775 E1K_SPEC_PRI(pDesc->status.u16Special)));
1776}
1777
1778/**
1779 * Dump transmit descriptor to debug log.
1780 *
1781 * @param pThis The device state structure.
1782 * @param pDesc Pointer to descriptor union.
1783 * @param cszDir A string denoting direction of descriptor transfer
1784 * @thread E1000_TX
1785 */
1786static void e1kPrintTDesc(PE1KSTATE pThis, E1KTXDESC* pDesc, const char* cszDir,
1787 unsigned uLevel = RTLOGGRPFLAGS_LEVEL_2)
1788{
1789 /*
1790 * Unfortunately we cannot use our format handler here, we want R0 logging
1791 * as well.
1792 */
1793 switch (e1kGetDescType(pDesc))
1794 {
1795 case E1K_DTYP_CONTEXT:
1796 E1kLogX(uLevel, ("%s %s Context Transmit Descriptor %s\n",
1797 pThis->szPrf, cszDir, cszDir));
1798 E1kLogX(uLevel, (" IPCSS=%02X IPCSO=%02X IPCSE=%04X TUCSS=%02X TUCSO=%02X TUCSE=%04X\n",
1799 pDesc->context.ip.u8CSS, pDesc->context.ip.u8CSO, pDesc->context.ip.u16CSE,
1800 pDesc->context.tu.u8CSS, pDesc->context.tu.u8CSO, pDesc->context.tu.u16CSE));
1801 E1kLogX(uLevel, (" TUCMD:%s%s%s %s %s PAYLEN=%04x HDRLEN=%04x MSS=%04x STA: %s\n",
1802 pDesc->context.dw2.fIDE ? " IDE":"",
1803 pDesc->context.dw2.fRS ? " RS" :"",
1804 pDesc->context.dw2.fTSE ? " TSE":"",
1805 pDesc->context.dw2.fIP ? "IPv4":"IPv6",
1806 pDesc->context.dw2.fTCP ? "TCP":"UDP",
1807 pDesc->context.dw2.u20PAYLEN,
1808 pDesc->context.dw3.u8HDRLEN,
1809 pDesc->context.dw3.u16MSS,
1810 pDesc->context.dw3.fDD?"DD":""));
1811 break;
1812 case E1K_DTYP_DATA:
1813 E1kLogX(uLevel, ("%s %s Data Transmit Descriptor (%d bytes) %s\n",
1814 pThis->szPrf, cszDir, pDesc->data.cmd.u20DTALEN, cszDir));
1815 E1kLogX(uLevel, (" Address=%16LX DTALEN=%05X\n",
1816 pDesc->data.u64BufAddr,
1817 pDesc->data.cmd.u20DTALEN));
1818 E1kLogX(uLevel, (" DCMD:%s%s%s%s%s%s%s STA:%s%s%s POPTS:%s%s SPECIAL:%s VLAN=%03x PRI=%x\n",
1819 pDesc->data.cmd.fIDE ? " IDE" :"",
1820 pDesc->data.cmd.fVLE ? " VLE" :"",
1821 pDesc->data.cmd.fRPS ? " RPS" :"",
1822 pDesc->data.cmd.fRS ? " RS" :"",
1823 pDesc->data.cmd.fTSE ? " TSE" :"",
1824 pDesc->data.cmd.fIFCS? " IFCS":"",
1825 pDesc->data.cmd.fEOP ? " EOP" :"",
1826 pDesc->data.dw3.fDD ? " DD" :"",
1827 pDesc->data.dw3.fEC ? " EC" :"",
1828 pDesc->data.dw3.fLC ? " LC" :"",
1829 pDesc->data.dw3.fTXSM? " TXSM":"",
1830 pDesc->data.dw3.fIXSM? " IXSM":"",
1831 E1K_SPEC_CFI(pDesc->data.dw3.u16Special) ? "CFI" :"cfi",
1832 E1K_SPEC_VLAN(pDesc->data.dw3.u16Special),
1833 E1K_SPEC_PRI(pDesc->data.dw3.u16Special)));
1834 break;
1835 case E1K_DTYP_LEGACY:
1836 E1kLogX(uLevel, ("%s %s Legacy Transmit Descriptor (%d bytes) %s\n",
1837 pThis->szPrf, cszDir, pDesc->legacy.cmd.u16Length, cszDir));
1838 E1kLogX(uLevel, (" Address=%16LX DTALEN=%05X\n",
1839 pDesc->data.u64BufAddr,
1840 pDesc->legacy.cmd.u16Length));
1841 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",
1842 pDesc->legacy.cmd.fIDE ? " IDE" :"",
1843 pDesc->legacy.cmd.fVLE ? " VLE" :"",
1844 pDesc->legacy.cmd.fRPS ? " RPS" :"",
1845 pDesc->legacy.cmd.fRS ? " RS" :"",
1846 pDesc->legacy.cmd.fIC ? " IC" :"",
1847 pDesc->legacy.cmd.fIFCS? " IFCS":"",
1848 pDesc->legacy.cmd.fEOP ? " EOP" :"",
1849 pDesc->legacy.dw3.fDD ? " DD" :"",
1850 pDesc->legacy.dw3.fEC ? " EC" :"",
1851 pDesc->legacy.dw3.fLC ? " LC" :"",
1852 pDesc->legacy.cmd.u8CSO,
1853 pDesc->legacy.dw3.u8CSS,
1854 E1K_SPEC_CFI(pDesc->legacy.dw3.u16Special) ? "CFI" :"cfi",
1855 E1K_SPEC_VLAN(pDesc->legacy.dw3.u16Special),
1856 E1K_SPEC_PRI(pDesc->legacy.dw3.u16Special)));
1857 break;
1858 default:
1859 E1kLog(("%s %s Invalid Transmit Descriptor %s\n",
1860 pThis->szPrf, cszDir, cszDir));
1861 break;
1862 }
1863}
1864
1865/**
1866 * Raise interrupt if not masked.
1867 *
1868 * @param pThis The device state structure.
1869 */
1870static int e1kRaiseInterrupt(PE1KSTATE pThis, int rcBusy, uint32_t u32IntCause = 0)
1871{
1872 int rc = e1kCsEnter(pThis, rcBusy);
1873 if (RT_UNLIKELY(rc != VINF_SUCCESS))
1874 return rc;
1875
1876 E1K_INC_ISTAT_CNT(pThis->uStatIntTry);
1877 ICR |= u32IntCause;
1878 if (ICR & IMS)
1879 {
1880#if 0
1881 if (pThis->fDelayInts)
1882 {
1883 E1K_INC_ISTAT_CNT(pThis->uStatIntDly);
1884 pThis->iStatIntLostOne = 1;
1885 E1kLog2(("%s e1kRaiseInterrupt: Delayed. ICR=%08x\n",
1886 pThis->szPrf, ICR));
1887#define E1K_LOST_IRQ_THRSLD 20
1888//#define E1K_LOST_IRQ_THRSLD 200000000
1889 if (pThis->iStatIntLost >= E1K_LOST_IRQ_THRSLD)
1890 {
1891 E1kLog2(("%s WARNING! Disabling delayed interrupt logic: delayed=%d, delivered=%d\n",
1892 pThis->szPrf, pThis->uStatIntDly, pThis->uStatIntLate));
1893 pThis->fIntMaskUsed = false;
1894 pThis->uStatDisDly++;
1895 }
1896 }
1897 else
1898#endif
1899 if (pThis->fIntRaised)
1900 {
1901 E1K_INC_ISTAT_CNT(pThis->uStatIntSkip);
1902 E1kLog2(("%s e1kRaiseInterrupt: Already raised, skipped. ICR&IMS=%08x\n",
1903 pThis->szPrf, ICR & IMS));
1904 }
1905 else
1906 {
1907#ifdef E1K_ITR_ENABLED
1908 uint64_t tstamp = TMTimerGet(pThis->CTX_SUFF(pIntTimer));
1909 /* interrupts/sec = 1 / (256 * 10E-9 * ITR) */
1910 E1kLog2(("%s e1kRaiseInterrupt: tstamp - pThis->u64AckedAt = %d, ITR * 256 = %d\n",
1911 pThis->szPrf, (uint32_t)(tstamp - pThis->u64AckedAt), ITR * 256));
1912 //if (!!ITR && pThis->fIntMaskUsed && tstamp - pThis->u64AckedAt < ITR * 256)
1913 if (!!ITR && tstamp - pThis->u64AckedAt < ITR * 256 && !(ICR & ICR_RXT0))
1914 {
1915 E1K_INC_ISTAT_CNT(pThis->uStatIntEarly);
1916 E1kLog2(("%s e1kRaiseInterrupt: Too early to raise again: %d ns < %d ns.\n",
1917 pThis->szPrf, (uint32_t)(tstamp - pThis->u64AckedAt), ITR * 256));
1918 }
1919 else
1920#endif
1921 {
1922
1923 /* Since we are delivering the interrupt now
1924 * there is no need to do it later -- stop the timer.
1925 */
1926 TMTimerStop(pThis->CTX_SUFF(pIntTimer));
1927 E1K_INC_ISTAT_CNT(pThis->uStatInt);
1928 STAM_COUNTER_INC(&pThis->StatIntsRaised);
1929 /* Got at least one unmasked interrupt cause */
1930 pThis->fIntRaised = true;
1931 /* Raise(1) INTA(0) */
1932 E1kLogRel(("E1000: irq RAISED icr&mask=0x%x, icr=0x%x\n", ICR & IMS, ICR));
1933 PDMDevHlpPCISetIrq(pThis->CTX_SUFF(pDevIns), 0, 1);
1934 E1kLog(("%s e1kRaiseInterrupt: Raised. ICR&IMS=%08x\n",
1935 pThis->szPrf, ICR & IMS));
1936 }
1937 }
1938 }
1939 else
1940 {
1941 E1K_INC_ISTAT_CNT(pThis->uStatIntMasked);
1942 E1kLog2(("%s e1kRaiseInterrupt: Not raising, ICR=%08x, IMS=%08x\n",
1943 pThis->szPrf, ICR, IMS));
1944 }
1945 e1kCsLeave(pThis);
1946 return VINF_SUCCESS;
1947}
1948
1949/**
1950 * Compute the physical address of the descriptor.
1951 *
1952 * @returns the physical address of the descriptor.
1953 *
1954 * @param baseHigh High-order 32 bits of descriptor table address.
1955 * @param baseLow Low-order 32 bits of descriptor table address.
1956 * @param idxDesc The descriptor index in the table.
1957 */
1958DECLINLINE(RTGCPHYS) e1kDescAddr(uint32_t baseHigh, uint32_t baseLow, uint32_t idxDesc)
1959{
1960 AssertCompile(sizeof(E1KRXDESC) == sizeof(E1KTXDESC));
1961 return ((uint64_t)baseHigh << 32) + baseLow + idxDesc * sizeof(E1KRXDESC);
1962}
1963
1964/**
1965 * Advance the head pointer of the receive descriptor queue.
1966 *
1967 * @remarks RDH always points to the next available RX descriptor.
1968 *
1969 * @param pThis The device state structure.
1970 */
1971DECLINLINE(void) e1kAdvanceRDH(PE1KSTATE pThis)
1972{
1973 Assert(e1kCsRxIsOwner(pThis));
1974 //e1kCsEnter(pThis, RT_SRC_POS);
1975 if (++RDH * sizeof(E1KRXDESC) >= RDLEN)
1976 RDH = 0;
1977 /*
1978 * Compute current receive queue length and fire RXDMT0 interrupt
1979 * if we are low on receive buffers
1980 */
1981 uint32_t uRQueueLen = RDH>RDT ? RDLEN/sizeof(E1KRXDESC)-RDH+RDT : RDT-RDH;
1982 /*
1983 * The minimum threshold is controlled by RDMTS bits of RCTL:
1984 * 00 = 1/2 of RDLEN
1985 * 01 = 1/4 of RDLEN
1986 * 10 = 1/8 of RDLEN
1987 * 11 = reserved
1988 */
1989 uint32_t uMinRQThreshold = RDLEN / sizeof(E1KRXDESC) / (2 << GET_BITS(RCTL, RDMTS));
1990 if (uRQueueLen <= uMinRQThreshold)
1991 {
1992 E1kLogRel(("E1000: low on RX descriptors, RDH=%x RDT=%x len=%x threshold=%x\n", RDH, RDT, uRQueueLen, uMinRQThreshold));
1993 E1kLog2(("%s Low on RX descriptors, RDH=%x RDT=%x len=%x threshold=%x, raise an interrupt\n",
1994 pThis->szPrf, RDH, RDT, uRQueueLen, uMinRQThreshold));
1995 E1K_INC_ISTAT_CNT(pThis->uStatIntRXDMT0);
1996 e1kRaiseInterrupt(pThis, VERR_SEM_BUSY, ICR_RXDMT0);
1997 }
1998 E1kLog2(("%s e1kAdvanceRDH: at exit RDH=%x RDT=%x len=%x\n",
1999 pThis->szPrf, RDH, RDT, uRQueueLen));
2000 //e1kCsLeave(pThis);
2001}
2002
2003#ifdef E1K_WITH_RXD_CACHE
2004/**
2005 * Return the number of RX descriptor that belong to the hardware.
2006 *
2007 * @returns the number of available descriptors in RX ring.
2008 * @param pThis The device state structure.
2009 * @thread ???
2010 */
2011DECLINLINE(uint32_t) e1kGetRxLen(PE1KSTATE pThis)
2012{
2013 /**
2014 * Make sure RDT won't change during computation. EMT may modify RDT at
2015 * any moment.
2016 */
2017 uint32_t rdt = RDT;
2018 return (RDH > rdt ? RDLEN/sizeof(E1KRXDESC) : 0) + rdt - RDH;
2019}
2020
2021DECLINLINE(unsigned) e1kRxDInCache(PE1KSTATE pThis)
2022{
2023 return pThis->nRxDFetched > pThis->iRxDCurrent ?
2024 pThis->nRxDFetched - pThis->iRxDCurrent : 0;
2025}
2026
2027DECLINLINE(unsigned) e1kRxDIsCacheEmpty(PE1KSTATE pThis)
2028{
2029 return pThis->iRxDCurrent >= pThis->nRxDFetched;
2030}
2031
2032/**
2033 * Load receive descriptors from guest memory. The caller needs to be in Rx
2034 * critical section.
2035 *
2036 * We need two physical reads in case the tail wrapped around the end of RX
2037 * descriptor ring.
2038 *
2039 * @returns the actual number of descriptors fetched.
2040 * @param pThis The device state structure.
2041 * @param pDesc Pointer to descriptor union.
2042 * @param addr Physical address in guest context.
2043 * @thread EMT, RX
2044 */
2045DECLINLINE(unsigned) e1kRxDPrefetch(PE1KSTATE pThis)
2046{
2047 /* We've already loaded pThis->nRxDFetched descriptors past RDH. */
2048 unsigned nDescsAvailable = e1kGetRxLen(pThis) - e1kRxDInCache(pThis);
2049 unsigned nDescsToFetch = RT_MIN(nDescsAvailable, E1K_RXD_CACHE_SIZE - pThis->nRxDFetched);
2050 unsigned nDescsTotal = RDLEN / sizeof(E1KRXDESC);
2051 Assert(nDescsTotal != 0);
2052 if (nDescsTotal == 0)
2053 return 0;
2054 unsigned nFirstNotLoaded = (RDH + e1kRxDInCache(pThis)) % nDescsTotal;
2055 unsigned nDescsInSingleRead = RT_MIN(nDescsToFetch, nDescsTotal - nFirstNotLoaded);
2056 E1kLog3(("%s e1kRxDPrefetch: nDescsAvailable=%u nDescsToFetch=%u "
2057 "nDescsTotal=%u nFirstNotLoaded=0x%x nDescsInSingleRead=%u\n",
2058 pThis->szPrf, nDescsAvailable, nDescsToFetch, nDescsTotal,
2059 nFirstNotLoaded, nDescsInSingleRead));
2060 if (nDescsToFetch == 0)
2061 return 0;
2062 E1KRXDESC* pFirstEmptyDesc = &pThis->aRxDescriptors[pThis->nRxDFetched];
2063 PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns),
2064 ((uint64_t)RDBAH << 32) + RDBAL + nFirstNotLoaded * sizeof(E1KRXDESC),
2065 pFirstEmptyDesc, nDescsInSingleRead * sizeof(E1KRXDESC));
2066 // uint64_t addrBase = ((uint64_t)RDBAH << 32) + RDBAL;
2067 // unsigned i, j;
2068 // for (i = pThis->nRxDFetched; i < pThis->nRxDFetched + nDescsInSingleRead; ++i)
2069 // {
2070 // pThis->aRxDescAddr[i] = addrBase + (nFirstNotLoaded + i - pThis->nRxDFetched) * sizeof(E1KRXDESC);
2071 // E1kLog3(("%s aRxDescAddr[%d] = %p\n", pThis->szPrf, i, pThis->aRxDescAddr[i]));
2072 // }
2073 E1kLog3(("%s Fetched %u RX descriptors at %08x%08x(0x%x), RDLEN=%08x, RDH=%08x, RDT=%08x\n",
2074 pThis->szPrf, nDescsInSingleRead,
2075 RDBAH, RDBAL + RDH * sizeof(E1KRXDESC),
2076 nFirstNotLoaded, RDLEN, RDH, RDT));
2077 if (nDescsToFetch > nDescsInSingleRead)
2078 {
2079 PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns),
2080 ((uint64_t)RDBAH << 32) + RDBAL,
2081 pFirstEmptyDesc + nDescsInSingleRead,
2082 (nDescsToFetch - nDescsInSingleRead) * sizeof(E1KRXDESC));
2083 // Assert(i == pThis->nRxDFetched + nDescsInSingleRead);
2084 // for (j = 0; i < pThis->nRxDFetched + nDescsToFetch; ++i, ++j)
2085 // {
2086 // pThis->aRxDescAddr[i] = addrBase + j * sizeof(E1KRXDESC);
2087 // E1kLog3(("%s aRxDescAddr[%d] = %p\n", pThis->szPrf, i, pThis->aRxDescAddr[i]));
2088 // }
2089 E1kLog3(("%s Fetched %u RX descriptors at %08x%08x\n",
2090 pThis->szPrf, nDescsToFetch - nDescsInSingleRead,
2091 RDBAH, RDBAL));
2092 }
2093 pThis->nRxDFetched += nDescsToFetch;
2094 return nDescsToFetch;
2095}
2096
2097/**
2098 * Obtain the next RX descriptor from RXD cache, fetching descriptors from the
2099 * RX ring if the cache is empty.
2100 *
2101 * Note that we cannot advance the cache pointer (iRxDCurrent) yet as it will
2102 * go out of sync with RDH which will cause trouble when EMT checks if the
2103 * cache is empty to do pre-fetch @bugref(6217).
2104 *
2105 * @param pThis The device state structure.
2106 * @thread RX
2107 */
2108DECLINLINE(E1KRXDESC*) e1kRxDGet(PE1KSTATE pThis)
2109{
2110 Assert(e1kCsRxIsOwner(pThis));
2111 /* Check the cache first. */
2112 if (pThis->iRxDCurrent < pThis->nRxDFetched)
2113 return &pThis->aRxDescriptors[pThis->iRxDCurrent];
2114 /* Cache is empty, reset it and check if we can fetch more. */
2115 pThis->iRxDCurrent = pThis->nRxDFetched = 0;
2116 if (e1kRxDPrefetch(pThis))
2117 return &pThis->aRxDescriptors[pThis->iRxDCurrent];
2118 /* Out of Rx descriptors. */
2119 return NULL;
2120}
2121
2122/**
2123 * Return the RX descriptor obtained with e1kRxDGet() and advance the cache
2124 * pointer. The descriptor gets written back to the RXD ring.
2125 *
2126 * @param pThis The device state structure.
2127 * @param pDesc The descriptor being "returned" to the RX ring.
2128 * @thread RX
2129 */
2130DECLINLINE(void) e1kRxDPut(PE1KSTATE pThis, E1KRXDESC* pDesc)
2131{
2132 Assert(e1kCsRxIsOwner(pThis));
2133 pThis->iRxDCurrent++;
2134 // Assert(pDesc >= pThis->aRxDescriptors);
2135 // Assert(pDesc < pThis->aRxDescriptors + E1K_RXD_CACHE_SIZE);
2136 // uint64_t addr = e1kDescAddr(RDBAH, RDBAL, RDH);
2137 // uint32_t rdh = RDH;
2138 // Assert(pThis->aRxDescAddr[pDesc - pThis->aRxDescriptors] == addr);
2139 PDMDevHlpPCIPhysWrite(pThis->CTX_SUFF(pDevIns),
2140 e1kDescAddr(RDBAH, RDBAL, RDH),
2141 pDesc, sizeof(E1KRXDESC));
2142 e1kAdvanceRDH(pThis);
2143 e1kPrintRDesc(pThis, pDesc);
2144}
2145
2146/**
2147 * Store a fragment of received packet at the specifed address.
2148 *
2149 * @param pThis The device state structure.
2150 * @param pDesc The next available RX descriptor.
2151 * @param pvBuf The fragment.
2152 * @param cb The size of the fragment.
2153 */
2154static DECLCALLBACK(void) e1kStoreRxFragment(PE1KSTATE pThis, E1KRXDESC *pDesc, const void *pvBuf, size_t cb)
2155{
2156 STAM_PROFILE_ADV_START(&pThis->StatReceiveStore, a);
2157 E1kLog2(("%s e1kStoreRxFragment: store fragment of %04X at %016LX, EOP=%d\n",
2158 pThis->szPrf, cb, pDesc->u64BufAddr, pDesc->status.fEOP));
2159 PDMDevHlpPCIPhysWrite(pThis->CTX_SUFF(pDevIns), pDesc->u64BufAddr, pvBuf, cb);
2160 pDesc->u16Length = (uint16_t)cb; Assert(pDesc->u16Length == cb);
2161 STAM_PROFILE_ADV_STOP(&pThis->StatReceiveStore, a);
2162}
2163
2164#else /* !E1K_WITH_RXD_CACHE */
2165
2166/**
2167 * Store a fragment of received packet that fits into the next available RX
2168 * buffer.
2169 *
2170 * @remarks Trigger the RXT0 interrupt if it is the last fragment of the packet.
2171 *
2172 * @param pThis The device state structure.
2173 * @param pDesc The next available RX descriptor.
2174 * @param pvBuf The fragment.
2175 * @param cb The size of the fragment.
2176 */
2177static DECLCALLBACK(void) e1kStoreRxFragment(PE1KSTATE pThis, E1KRXDESC *pDesc, const void *pvBuf, size_t cb)
2178{
2179 STAM_PROFILE_ADV_START(&pThis->StatReceiveStore, a);
2180 E1kLog2(("%s e1kStoreRxFragment: store fragment of %04X at %016LX, EOP=%d\n", pThis->szPrf, cb, pDesc->u64BufAddr, pDesc->status.fEOP));
2181 PDMDevHlpPCIPhysWrite(pThis->CTX_SUFF(pDevIns), pDesc->u64BufAddr, pvBuf, cb);
2182 pDesc->u16Length = (uint16_t)cb; Assert(pDesc->u16Length == cb);
2183 /* Write back the descriptor */
2184 PDMDevHlpPCIPhysWrite(pThis->CTX_SUFF(pDevIns), e1kDescAddr(RDBAH, RDBAL, RDH), pDesc, sizeof(E1KRXDESC));
2185 e1kPrintRDesc(pThis, pDesc);
2186 E1kLogRel(("E1000: Wrote back RX desc, RDH=%x\n", RDH));
2187 /* Advance head */
2188 e1kAdvanceRDH(pThis);
2189 //E1kLog2(("%s e1kStoreRxFragment: EOP=%d RDTR=%08X RADV=%08X\n", pThis->szPrf, pDesc->fEOP, RDTR, RADV));
2190 if (pDesc->status.fEOP)
2191 {
2192 /* Complete packet has been stored -- it is time to let the guest know. */
2193#ifdef E1K_USE_RX_TIMERS
2194 if (RDTR)
2195 {
2196 /* Arm the timer to fire in RDTR usec (discard .024) */
2197 e1kArmTimer(pThis, pThis->CTX_SUFF(pRIDTimer), RDTR);
2198 /* If absolute timer delay is enabled and the timer is not running yet, arm it. */
2199 if (RADV != 0 && !TMTimerIsActive(pThis->CTX_SUFF(pRADTimer)))
2200 e1kArmTimer(pThis, pThis->CTX_SUFF(pRADTimer), RADV);
2201 }
2202 else
2203 {
2204#endif
2205 /* 0 delay means immediate interrupt */
2206 E1K_INC_ISTAT_CNT(pThis->uStatIntRx);
2207 e1kRaiseInterrupt(pThis, VERR_SEM_BUSY, ICR_RXT0);
2208#ifdef E1K_USE_RX_TIMERS
2209 }
2210#endif
2211 }
2212 STAM_PROFILE_ADV_STOP(&pThis->StatReceiveStore, a);
2213}
2214#endif /* !E1K_WITH_RXD_CACHE */
2215
2216/**
2217 * Returns true if it is a broadcast packet.
2218 *
2219 * @returns true if destination address indicates broadcast.
2220 * @param pvBuf The ethernet packet.
2221 */
2222DECLINLINE(bool) e1kIsBroadcast(const void *pvBuf)
2223{
2224 static const uint8_t s_abBcastAddr[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
2225 return memcmp(pvBuf, s_abBcastAddr, sizeof(s_abBcastAddr)) == 0;
2226}
2227
2228/**
2229 * Returns true if it is a multicast packet.
2230 *
2231 * @remarks returns true for broadcast packets as well.
2232 * @returns true if destination address indicates multicast.
2233 * @param pvBuf The ethernet packet.
2234 */
2235DECLINLINE(bool) e1kIsMulticast(const void *pvBuf)
2236{
2237 return (*(char*)pvBuf) & 1;
2238}
2239
2240/**
2241 * Set IXSM, IPCS and TCPCS flags according to the packet type.
2242 *
2243 * @remarks We emulate checksum offloading for major packets types only.
2244 *
2245 * @returns VBox status code.
2246 * @param pThis The device state structure.
2247 * @param pFrame The available data.
2248 * @param cb Number of bytes available in the buffer.
2249 * @param status Bit fields containing status info.
2250 */
2251static int e1kRxChecksumOffload(PE1KSTATE pThis, const uint8_t *pFrame, size_t cb, E1KRXDST *pStatus)
2252{
2253 /** @todo
2254 * It is not safe to bypass checksum verification for packets coming
2255 * from real wire. We currently unable to tell where packets are
2256 * coming from so we tell the driver to ignore our checksum flags
2257 * and do verification in software.
2258 */
2259#if 0
2260 uint16_t uEtherType = ntohs(*(uint16_t*)(pFrame + 12));
2261
2262 E1kLog2(("%s e1kRxChecksumOffload: EtherType=%x\n", pThis->szPrf, uEtherType));
2263
2264 switch (uEtherType)
2265 {
2266 case 0x800: /* IPv4 */
2267 {
2268 pStatus->fIXSM = false;
2269 pStatus->fIPCS = true;
2270 PRTNETIPV4 pIpHdr4 = (PRTNETIPV4)(pFrame + 14);
2271 /* TCP/UDP checksum offloading works with TCP and UDP only */
2272 pStatus->fTCPCS = pIpHdr4->ip_p == 6 || pIpHdr4->ip_p == 17;
2273 break;
2274 }
2275 case 0x86DD: /* IPv6 */
2276 pStatus->fIXSM = false;
2277 pStatus->fIPCS = false;
2278 pStatus->fTCPCS = true;
2279 break;
2280 default: /* ARP, VLAN, etc. */
2281 pStatus->fIXSM = true;
2282 break;
2283 }
2284#else
2285 pStatus->fIXSM = true;
2286#endif
2287 return VINF_SUCCESS;
2288}
2289
2290/**
2291 * Pad and store received packet.
2292 *
2293 * @remarks Make sure that the packet appears to upper layer as one coming
2294 * from real Ethernet: pad it and insert FCS.
2295 *
2296 * @returns VBox status code.
2297 * @param pThis The device state structure.
2298 * @param pvBuf The available data.
2299 * @param cb Number of bytes available in the buffer.
2300 * @param status Bit fields containing status info.
2301 */
2302static int e1kHandleRxPacket(PE1KSTATE pThis, const void *pvBuf, size_t cb, E1KRXDST status)
2303{
2304#if defined(IN_RING3) /** @todo Remove this extra copying, it's gonna make us run out of kernel / hypervisor stack! */
2305 uint8_t rxPacket[E1K_MAX_RX_PKT_SIZE];
2306 uint8_t *ptr = rxPacket;
2307
2308 int rc = e1kCsRxEnter(pThis, VERR_SEM_BUSY);
2309 if (RT_UNLIKELY(rc != VINF_SUCCESS))
2310 return rc;
2311
2312 if (cb > 70) /* unqualified guess */
2313 pThis->led.Asserted.s.fReading = pThis->led.Actual.s.fReading = 1;
2314
2315 Assert(cb <= E1K_MAX_RX_PKT_SIZE);
2316 Assert(cb > 16);
2317 size_t cbMax = ((RCTL & RCTL_LPE) ? E1K_MAX_RX_PKT_SIZE - 4 : 1518) - (status.fVP ? 0 : 4);
2318 E1kLog3(("%s Max RX packet size is %u\n", pThis->szPrf, cbMax));
2319 if (status.fVP)
2320 {
2321 /* VLAN packet -- strip VLAN tag in VLAN mode */
2322 if ((CTRL & CTRL_VME) && cb > 16)
2323 {
2324 uint16_t *u16Ptr = (uint16_t*)pvBuf;
2325 memcpy(rxPacket, pvBuf, 12); /* Copy src and dst addresses */
2326 status.u16Special = RT_BE2H_U16(u16Ptr[7]); /* Extract VLAN tag */
2327 memcpy(rxPacket + 12, (uint8_t*)pvBuf + 16, cb - 16); /* Copy the rest of the packet */
2328 cb -= 4;
2329 E1kLog3(("%s Stripped tag for VLAN %u (cb=%u)\n",
2330 pThis->szPrf, status.u16Special, cb));
2331 }
2332 else
2333 status.fVP = false; /* Set VP only if we stripped the tag */
2334 }
2335 else
2336 memcpy(rxPacket, pvBuf, cb);
2337 /* Pad short packets */
2338 if (cb < 60)
2339 {
2340 memset(rxPacket + cb, 0, 60 - cb);
2341 cb = 60;
2342 }
2343 if (!(RCTL & RCTL_SECRC) && cb <= cbMax)
2344 {
2345 STAM_PROFILE_ADV_START(&pThis->StatReceiveCRC, a);
2346 /*
2347 * Add FCS if CRC stripping is not enabled. Since the value of CRC
2348 * is ignored by most of drivers we may as well save us the trouble
2349 * of calculating it (see EthernetCRC CFGM parameter).
2350 */
2351 if (pThis->fEthernetCRC)
2352 *(uint32_t*)(rxPacket + cb) = RTCrc32(rxPacket, cb);
2353 cb += sizeof(uint32_t);
2354 STAM_PROFILE_ADV_STOP(&pThis->StatReceiveCRC, a);
2355 E1kLog3(("%s Added FCS (cb=%u)\n", pThis->szPrf, cb));
2356 }
2357 /* Compute checksum of complete packet */
2358 uint16_t checksum = e1kCSum16(rxPacket + GET_BITS(RXCSUM, PCSS), cb);
2359 e1kRxChecksumOffload(pThis, rxPacket, cb, &status);
2360
2361 /* Update stats */
2362 E1K_INC_CNT32(GPRC);
2363 if (e1kIsBroadcast(pvBuf))
2364 E1K_INC_CNT32(BPRC);
2365 else if (e1kIsMulticast(pvBuf))
2366 E1K_INC_CNT32(MPRC);
2367 /* Update octet receive counter */
2368 E1K_ADD_CNT64(GORCL, GORCH, cb);
2369 STAM_REL_COUNTER_ADD(&pThis->StatReceiveBytes, cb);
2370 if (cb == 64)
2371 E1K_INC_CNT32(PRC64);
2372 else if (cb < 128)
2373 E1K_INC_CNT32(PRC127);
2374 else if (cb < 256)
2375 E1K_INC_CNT32(PRC255);
2376 else if (cb < 512)
2377 E1K_INC_CNT32(PRC511);
2378 else if (cb < 1024)
2379 E1K_INC_CNT32(PRC1023);
2380 else
2381 E1K_INC_CNT32(PRC1522);
2382
2383 E1K_INC_ISTAT_CNT(pThis->uStatRxFrm);
2384
2385#ifdef E1K_WITH_RXD_CACHE
2386 while (cb > 0)
2387 {
2388 E1KRXDESC *pDesc = e1kRxDGet(pThis);
2389
2390 if (pDesc == NULL)
2391 {
2392 E1kLog(("%s Out of receive buffers, dropping the packet "
2393 "(cb=%u, in_cache=%u, RDH=%x RDT=%x)\n",
2394 pThis->szPrf, cb, e1kRxDInCache(pThis), RDH, RDT));
2395 break;
2396 }
2397#else /* !E1K_WITH_RXD_CACHE */
2398 if (RDH == RDT)
2399 {
2400 E1kLog(("%s Out of receive buffers, dropping the packet\n",
2401 pThis->szPrf));
2402 }
2403 /* Store the packet to receive buffers */
2404 while (RDH != RDT)
2405 {
2406 /* Load the descriptor pointed by head */
2407 E1KRXDESC desc, *pDesc = &desc;
2408 PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns), e1kDescAddr(RDBAH, RDBAL, RDH),
2409 &desc, sizeof(desc));
2410#endif /* !E1K_WITH_RXD_CACHE */
2411 if (pDesc->u64BufAddr)
2412 {
2413 /* Update descriptor */
2414 pDesc->status = status;
2415 pDesc->u16Checksum = checksum;
2416 pDesc->status.fDD = true;
2417
2418 /*
2419 * We need to leave Rx critical section here or we risk deadlocking
2420 * with EMT in e1kRegWriteRDT when the write is to an unallocated
2421 * page or has an access handler associated with it.
2422 * Note that it is safe to leave the critical section here since
2423 * e1kRegWriteRDT() never modifies RDH. It never touches already
2424 * fetched RxD cache entries either.
2425 */
2426 if (cb > pThis->u16RxBSize)
2427 {
2428 pDesc->status.fEOP = false;
2429 e1kCsRxLeave(pThis);
2430 e1kStoreRxFragment(pThis, pDesc, ptr, pThis->u16RxBSize);
2431 rc = e1kCsRxEnter(pThis, VERR_SEM_BUSY);
2432 if (RT_UNLIKELY(rc != VINF_SUCCESS))
2433 return rc;
2434 ptr += pThis->u16RxBSize;
2435 cb -= pThis->u16RxBSize;
2436 }
2437 else
2438 {
2439 pDesc->status.fEOP = true;
2440 e1kCsRxLeave(pThis);
2441 e1kStoreRxFragment(pThis, pDesc, ptr, cb);
2442#ifdef E1K_WITH_RXD_CACHE
2443 rc = e1kCsRxEnter(pThis, VERR_SEM_BUSY);
2444 if (RT_UNLIKELY(rc != VINF_SUCCESS))
2445 return rc;
2446 cb = 0;
2447#else /* !E1K_WITH_RXD_CACHE */
2448 pThis->led.Actual.s.fReading = 0;
2449 return VINF_SUCCESS;
2450#endif /* !E1K_WITH_RXD_CACHE */
2451 }
2452 /*
2453 * Note: RDH is advanced by e1kStoreRxFragment if E1K_WITH_RXD_CACHE
2454 * is not defined.
2455 */
2456 }
2457#ifdef E1K_WITH_RXD_CACHE
2458 /* Write back the descriptor. */
2459 pDesc->status.fDD = true;
2460 e1kRxDPut(pThis, pDesc);
2461#else /* !E1K_WITH_RXD_CACHE */
2462 else
2463 {
2464 /* Write back the descriptor. */
2465 pDesc->status.fDD = true;
2466 PDMDevHlpPCIPhysWrite(pThis->CTX_SUFF(pDevIns),
2467 e1kDescAddr(RDBAH, RDBAL, RDH),
2468 pDesc, sizeof(E1KRXDESC));
2469 e1kAdvanceRDH(pThis);
2470 }
2471#endif /* !E1K_WITH_RXD_CACHE */
2472 }
2473
2474 if (cb > 0)
2475 E1kLog(("%s Out of receive buffers, dropping %u bytes", pThis->szPrf, cb));
2476
2477 pThis->led.Actual.s.fReading = 0;
2478
2479 e1kCsRxLeave(pThis);
2480#ifdef E1K_WITH_RXD_CACHE
2481 /* Complete packet has been stored -- it is time to let the guest know. */
2482# ifdef E1K_USE_RX_TIMERS
2483 if (RDTR)
2484 {
2485 /* Arm the timer to fire in RDTR usec (discard .024) */
2486 e1kArmTimer(pThis, pThis->CTX_SUFF(pRIDTimer), RDTR);
2487 /* If absolute timer delay is enabled and the timer is not running yet, arm it. */
2488 if (RADV != 0 && !TMTimerIsActive(pThis->CTX_SUFF(pRADTimer)))
2489 e1kArmTimer(pThis, pThis->CTX_SUFF(pRADTimer), RADV);
2490 }
2491 else
2492 {
2493# endif /* E1K_USE_RX_TIMERS */
2494 /* 0 delay means immediate interrupt */
2495 E1K_INC_ISTAT_CNT(pThis->uStatIntRx);
2496 e1kRaiseInterrupt(pThis, VERR_SEM_BUSY, ICR_RXT0);
2497# ifdef E1K_USE_RX_TIMERS
2498 }
2499# endif /* E1K_USE_RX_TIMERS */
2500#endif /* E1K_WITH_RXD_CACHE */
2501
2502 return VINF_SUCCESS;
2503#else
2504 return VERR_INTERNAL_ERROR_2;
2505#endif
2506}
2507
2508
2509/**
2510 * Bring the link up after the configured delay, 5 seconds by default.
2511 *
2512 * @param pThis The device state structure.
2513 * @thread any
2514 */
2515DECLINLINE(void) e1kBringLinkUpDelayed(PE1KSTATE pThis)
2516{
2517 E1kLog(("%s Will bring up the link in %d seconds...\n",
2518 pThis->szPrf, pThis->cMsLinkUpDelay / 1000));
2519 e1kArmTimer(pThis, pThis->CTX_SUFF(pLUTimer), pThis->cMsLinkUpDelay * 1000);
2520}
2521
2522#ifdef IN_RING3
2523/**
2524 * Bring up the link immediately.
2525 *
2526 * @param pThis The device state structure.
2527 */
2528DECLINLINE(void) e1kR3LinkUp(PE1KSTATE pThis)
2529{
2530 E1kLog(("%s Link is up\n", pThis->szPrf));
2531 STATUS |= STATUS_LU;
2532 Phy::setLinkStatus(&pThis->phy, true);
2533 e1kRaiseInterrupt(pThis, VERR_SEM_BUSY, ICR_LSC);
2534 if (pThis->pDrvR3)
2535 pThis->pDrvR3->pfnNotifyLinkChanged(pThis->pDrvR3, PDMNETWORKLINKSTATE_UP);
2536}
2537
2538/**
2539 * Bring down the link immediately.
2540 *
2541 * @param pThis The device state structure.
2542 */
2543DECLINLINE(void) e1kR3LinkDown(PE1KSTATE pThis)
2544{
2545 E1kLog(("%s Link is down\n", pThis->szPrf));
2546 STATUS &= ~STATUS_LU;
2547 Phy::setLinkStatus(&pThis->phy, false);
2548 e1kRaiseInterrupt(pThis, VERR_SEM_BUSY, ICR_LSC);
2549 if (pThis->pDrvR3)
2550 pThis->pDrvR3->pfnNotifyLinkChanged(pThis->pDrvR3, PDMNETWORKLINKSTATE_DOWN);
2551}
2552
2553/**
2554 * Bring down the link temporarily.
2555 *
2556 * @param pThis The device state structure.
2557 */
2558DECLINLINE(void) e1kR3LinkDownTemp(PE1KSTATE pThis)
2559{
2560 E1kLog(("%s Link is down temporarily\n", pThis->szPrf));
2561 STATUS &= ~STATUS_LU;
2562 Phy::setLinkStatus(&pThis->phy, false);
2563 e1kRaiseInterrupt(pThis, VERR_SEM_BUSY, ICR_LSC);
2564 /*
2565 * Notifying the associated driver that the link went down (even temporarily)
2566 * seems to be the right thing, but it was not done before. This may cause
2567 * a regression if the driver does not expect the link to go down as a result
2568 * of sending PDMNETWORKLINKSTATE_DOWN_RESUME to this device. Earlier versions
2569 * of code notified the driver that the link was up! See @bugref{7057}.
2570 */
2571 if (pThis->pDrvR3)
2572 pThis->pDrvR3->pfnNotifyLinkChanged(pThis->pDrvR3, PDMNETWORKLINKSTATE_DOWN);
2573 e1kBringLinkUpDelayed(pThis);
2574}
2575#endif /* IN_RING3 */
2576
2577#if 0 /* unused */
2578/**
2579 * Read handler for Device Status register.
2580 *
2581 * Get the link status from PHY.
2582 *
2583 * @returns VBox status code.
2584 *
2585 * @param pThis The device state structure.
2586 * @param offset Register offset in memory-mapped frame.
2587 * @param index Register index in register array.
2588 * @param mask Used to implement partial reads (8 and 16-bit).
2589 */
2590static int e1kRegReadCTRL(PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t *pu32Value)
2591{
2592 E1kLog(("%s e1kRegReadCTRL: mdio dir=%s mdc dir=%s mdc=%d\n",
2593 pThis->szPrf, (CTRL & CTRL_MDIO_DIR)?"OUT":"IN ",
2594 (CTRL & CTRL_MDC_DIR)?"OUT":"IN ", !!(CTRL & CTRL_MDC)));
2595 if ((CTRL & CTRL_MDIO_DIR) == 0 && (CTRL & CTRL_MDC))
2596 {
2597 /* MDC is high and MDIO pin is used for input, read MDIO pin from PHY */
2598 if (Phy::readMDIO(&pThis->phy))
2599 *pu32Value = CTRL | CTRL_MDIO;
2600 else
2601 *pu32Value = CTRL & ~CTRL_MDIO;
2602 E1kLog(("%s e1kRegReadCTRL: Phy::readMDIO(%d)\n",
2603 pThis->szPrf, !!(*pu32Value & CTRL_MDIO)));
2604 }
2605 else
2606 {
2607 /* MDIO pin is used for output, ignore it */
2608 *pu32Value = CTRL;
2609 }
2610 return VINF_SUCCESS;
2611}
2612#endif /* unused */
2613
2614/**
2615 * Write handler for Device Control register.
2616 *
2617 * Handles reset.
2618 *
2619 * @param pThis The device state structure.
2620 * @param offset Register offset in memory-mapped frame.
2621 * @param index Register index in register array.
2622 * @param value The value to store.
2623 * @param mask Used to implement partial writes (8 and 16-bit).
2624 * @thread EMT
2625 */
2626static int e1kRegWriteCTRL(PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t value)
2627{
2628 int rc = VINF_SUCCESS;
2629
2630 if (value & CTRL_RESET)
2631 { /* RST */
2632#ifndef IN_RING3
2633 return VINF_IOM_R3_IOPORT_WRITE;
2634#else
2635 e1kHardReset(pThis);
2636#endif
2637 }
2638 else
2639 {
2640 if ( (value & CTRL_SLU)
2641 && pThis->fCableConnected
2642 && !(STATUS & STATUS_LU))
2643 {
2644 /* The driver indicates that we should bring up the link */
2645 /* Do so in 5 seconds (by default). */
2646 e1kBringLinkUpDelayed(pThis);
2647 /*
2648 * Change the status (but not PHY status) anyway as Windows expects
2649 * it for 82543GC.
2650 */
2651 STATUS |= STATUS_LU;
2652 }
2653 if (value & CTRL_VME)
2654 {
2655 E1kLog(("%s VLAN Mode Enabled\n", pThis->szPrf));
2656 }
2657 E1kLog(("%s e1kRegWriteCTRL: mdio dir=%s mdc dir=%s mdc=%s mdio=%d\n",
2658 pThis->szPrf, (value & CTRL_MDIO_DIR)?"OUT":"IN ",
2659 (value & CTRL_MDC_DIR)?"OUT":"IN ", (value & CTRL_MDC)?"HIGH":"LOW ", !!(value & CTRL_MDIO)));
2660 if (value & CTRL_MDC)
2661 {
2662 if (value & CTRL_MDIO_DIR)
2663 {
2664 E1kLog(("%s e1kRegWriteCTRL: Phy::writeMDIO(%d)\n", pThis->szPrf, !!(value & CTRL_MDIO)));
2665 /* MDIO direction pin is set to output and MDC is high, write MDIO pin value to PHY */
2666 Phy::writeMDIO(&pThis->phy, !!(value & CTRL_MDIO));
2667 }
2668 else
2669 {
2670 if (Phy::readMDIO(&pThis->phy))
2671 value |= CTRL_MDIO;
2672 else
2673 value &= ~CTRL_MDIO;
2674 E1kLog(("%s e1kRegWriteCTRL: Phy::readMDIO(%d)\n",
2675 pThis->szPrf, !!(value & CTRL_MDIO)));
2676 }
2677 }
2678 rc = e1kRegWriteDefault(pThis, offset, index, value);
2679 }
2680
2681 return rc;
2682}
2683
2684/**
2685 * Write handler for EEPROM/Flash Control/Data register.
2686 *
2687 * Handles EEPROM access requests; forwards writes to EEPROM device if access has been granted.
2688 *
2689 * @param pThis The device state structure.
2690 * @param offset Register offset in memory-mapped frame.
2691 * @param index Register index in register array.
2692 * @param value The value to store.
2693 * @param mask Used to implement partial writes (8 and 16-bit).
2694 * @thread EMT
2695 */
2696static int e1kRegWriteEECD(PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t value)
2697{
2698#ifdef IN_RING3
2699 /* So far we are concerned with lower byte only */
2700 if ((EECD & EECD_EE_GNT) || pThis->eChip == E1K_CHIP_82543GC)
2701 {
2702 /* Access to EEPROM granted -- forward 4-wire bits to EEPROM device */
2703 /* Note: 82543GC does not need to request EEPROM access */
2704 STAM_PROFILE_ADV_START(&pThis->StatEEPROMWrite, a);
2705 pThis->eeprom.write(value & EECD_EE_WIRES);
2706 STAM_PROFILE_ADV_STOP(&pThis->StatEEPROMWrite, a);
2707 }
2708 if (value & EECD_EE_REQ)
2709 EECD |= EECD_EE_REQ|EECD_EE_GNT;
2710 else
2711 EECD &= ~EECD_EE_GNT;
2712 //e1kRegWriteDefault(pThis, offset, index, value );
2713
2714 return VINF_SUCCESS;
2715#else /* !IN_RING3 */
2716 return VINF_IOM_R3_MMIO_WRITE;
2717#endif /* !IN_RING3 */
2718}
2719
2720/**
2721 * Read handler for EEPROM/Flash Control/Data register.
2722 *
2723 * Lower 4 bits come from EEPROM device if EEPROM access has been granted.
2724 *
2725 * @returns VBox status code.
2726 *
2727 * @param pThis The device state structure.
2728 * @param offset Register offset in memory-mapped frame.
2729 * @param index Register index in register array.
2730 * @param mask Used to implement partial reads (8 and 16-bit).
2731 * @thread EMT
2732 */
2733static int e1kRegReadEECD(PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t *pu32Value)
2734{
2735#ifdef IN_RING3
2736 uint32_t value;
2737 int rc = e1kRegReadDefault(pThis, offset, index, &value);
2738 if (RT_SUCCESS(rc))
2739 {
2740 if ((value & EECD_EE_GNT) || pThis->eChip == E1K_CHIP_82543GC)
2741 {
2742 /* Note: 82543GC does not need to request EEPROM access */
2743 /* Access to EEPROM granted -- get 4-wire bits to EEPROM device */
2744 STAM_PROFILE_ADV_START(&pThis->StatEEPROMRead, a);
2745 value |= pThis->eeprom.read();
2746 STAM_PROFILE_ADV_STOP(&pThis->StatEEPROMRead, a);
2747 }
2748 *pu32Value = value;
2749 }
2750
2751 return rc;
2752#else /* !IN_RING3 */
2753 return VINF_IOM_R3_MMIO_READ;
2754#endif /* !IN_RING3 */
2755}
2756
2757/**
2758 * Write handler for EEPROM Read register.
2759 *
2760 * Handles EEPROM word access requests, reads EEPROM and stores the result
2761 * into DATA field.
2762 *
2763 * @param pThis The device state structure.
2764 * @param offset Register offset in memory-mapped frame.
2765 * @param index Register index in register array.
2766 * @param value The value to store.
2767 * @param mask Used to implement partial writes (8 and 16-bit).
2768 * @thread EMT
2769 */
2770static int e1kRegWriteEERD(PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t value)
2771{
2772#ifdef IN_RING3
2773 /* Make use of 'writable' and 'readable' masks. */
2774 e1kRegWriteDefault(pThis, offset, index, value);
2775 /* DONE and DATA are set only if read was triggered by START. */
2776 if (value & EERD_START)
2777 {
2778 uint16_t tmp;
2779 STAM_PROFILE_ADV_START(&pThis->StatEEPROMRead, a);
2780 if (pThis->eeprom.readWord(GET_BITS_V(value, EERD, ADDR), &tmp))
2781 SET_BITS(EERD, DATA, tmp);
2782 EERD |= EERD_DONE;
2783 STAM_PROFILE_ADV_STOP(&pThis->StatEEPROMRead, a);
2784 }
2785
2786 return VINF_SUCCESS;
2787#else /* !IN_RING3 */
2788 return VINF_IOM_R3_MMIO_WRITE;
2789#endif /* !IN_RING3 */
2790}
2791
2792
2793/**
2794 * Write handler for MDI Control register.
2795 *
2796 * Handles PHY read/write requests; forwards requests to internal PHY device.
2797 *
2798 * @param pThis The device state structure.
2799 * @param offset Register offset in memory-mapped frame.
2800 * @param index Register index in register array.
2801 * @param value The value to store.
2802 * @param mask Used to implement partial writes (8 and 16-bit).
2803 * @thread EMT
2804 */
2805static int e1kRegWriteMDIC(PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t value)
2806{
2807 if (value & MDIC_INT_EN)
2808 {
2809 E1kLog(("%s ERROR! Interrupt at the end of an MDI cycle is not supported yet.\n",
2810 pThis->szPrf));
2811 }
2812 else if (value & MDIC_READY)
2813 {
2814 E1kLog(("%s ERROR! Ready bit is not reset by software during write operation.\n",
2815 pThis->szPrf));
2816 }
2817 else if (GET_BITS_V(value, MDIC, PHY) != 1)
2818 {
2819 E1kLog(("%s ERROR! Access to invalid PHY detected, phy=%d.\n",
2820 pThis->szPrf, GET_BITS_V(value, MDIC, PHY)));
2821 }
2822 else
2823 {
2824 /* Store the value */
2825 e1kRegWriteDefault(pThis, offset, index, value);
2826 STAM_COUNTER_INC(&pThis->StatPHYAccesses);
2827 /* Forward op to PHY */
2828 if (value & MDIC_OP_READ)
2829 SET_BITS(MDIC, DATA, Phy::readRegister(&pThis->phy, GET_BITS_V(value, MDIC, REG)));
2830 else
2831 Phy::writeRegister(&pThis->phy, GET_BITS_V(value, MDIC, REG), value & MDIC_DATA_MASK);
2832 /* Let software know that we are done */
2833 MDIC |= MDIC_READY;
2834 }
2835
2836 return VINF_SUCCESS;
2837}
2838
2839/**
2840 * Write handler for Interrupt Cause Read register.
2841 *
2842 * Bits corresponding to 1s in 'value' will be cleared in ICR register.
2843 *
2844 * @param pThis The device state structure.
2845 * @param offset Register offset in memory-mapped frame.
2846 * @param index Register index in register array.
2847 * @param value The value to store.
2848 * @param mask Used to implement partial writes (8 and 16-bit).
2849 * @thread EMT
2850 */
2851static int e1kRegWriteICR(PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t value)
2852{
2853 ICR &= ~value;
2854
2855 return VINF_SUCCESS;
2856}
2857
2858/**
2859 * Read handler for Interrupt Cause Read register.
2860 *
2861 * Reading this register acknowledges all interrupts.
2862 *
2863 * @returns VBox status code.
2864 *
2865 * @param pThis The device state structure.
2866 * @param offset Register offset in memory-mapped frame.
2867 * @param index Register index in register array.
2868 * @param mask Not used.
2869 * @thread EMT
2870 */
2871static int e1kRegReadICR(PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t *pu32Value)
2872{
2873 int rc = e1kCsEnter(pThis, VINF_IOM_R3_MMIO_READ);
2874 if (RT_UNLIKELY(rc != VINF_SUCCESS))
2875 return rc;
2876
2877 uint32_t value = 0;
2878 rc = e1kRegReadDefault(pThis, offset, index, &value);
2879 if (RT_SUCCESS(rc))
2880 {
2881 if (value)
2882 {
2883 /*
2884 * Not clearing ICR causes QNX to hang as it reads ICR in a loop
2885 * with disabled interrupts.
2886 */
2887 //if (IMS)
2888 if (1)
2889 {
2890 /*
2891 * Interrupts were enabled -- we are supposedly at the very
2892 * beginning of interrupt handler
2893 */
2894 E1kLogRel(("E1000: irq lowered, icr=0x%x\n", ICR));
2895 E1kLog(("%s e1kRegReadICR: Lowered IRQ (%08x)\n", pThis->szPrf, ICR));
2896 /* Clear all pending interrupts */
2897 ICR = 0;
2898 pThis->fIntRaised = false;
2899 /* Lower(0) INTA(0) */
2900 PDMDevHlpPCISetIrq(pThis->CTX_SUFF(pDevIns), 0, 0);
2901
2902 pThis->u64AckedAt = TMTimerGet(pThis->CTX_SUFF(pIntTimer));
2903 if (pThis->fIntMaskUsed)
2904 pThis->fDelayInts = true;
2905 }
2906 else
2907 {
2908 /*
2909 * Interrupts are disabled -- in windows guests ICR read is done
2910 * just before re-enabling interrupts
2911 */
2912 E1kLog(("%s e1kRegReadICR: Suppressing auto-clear due to disabled interrupts (%08x)\n", pThis->szPrf, ICR));
2913 }
2914 }
2915 *pu32Value = value;
2916 }
2917 e1kCsLeave(pThis);
2918
2919 return rc;
2920}
2921
2922/**
2923 * Write handler for Interrupt Cause Set register.
2924 *
2925 * Bits corresponding to 1s in 'value' will be set in ICR register.
2926 *
2927 * @param pThis The device state structure.
2928 * @param offset Register offset in memory-mapped frame.
2929 * @param index Register index in register array.
2930 * @param value The value to store.
2931 * @param mask Used to implement partial writes (8 and 16-bit).
2932 * @thread EMT
2933 */
2934static int e1kRegWriteICS(PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t value)
2935{
2936 E1K_INC_ISTAT_CNT(pThis->uStatIntICS);
2937 return e1kRaiseInterrupt(pThis, VINF_IOM_R3_MMIO_WRITE, value & g_aE1kRegMap[ICS_IDX].writable);
2938}
2939
2940/**
2941 * Write handler for Interrupt Mask Set register.
2942 *
2943 * Will trigger pending interrupts.
2944 *
2945 * @param pThis The device state structure.
2946 * @param offset Register offset in memory-mapped frame.
2947 * @param index Register index in register array.
2948 * @param value The value to store.
2949 * @param mask Used to implement partial writes (8 and 16-bit).
2950 * @thread EMT
2951 */
2952static int e1kRegWriteIMS(PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t value)
2953{
2954 IMS |= value;
2955 E1kLogRel(("E1000: irq enabled, RDH=%x RDT=%x TDH=%x TDT=%x\n", RDH, RDT, TDH, TDT));
2956 E1kLog(("%s e1kRegWriteIMS: IRQ enabled\n", pThis->szPrf));
2957 /* Mask changes, we need to raise pending interrupts. */
2958 if ((ICR & IMS) && !pThis->fLocked)
2959 {
2960 E1kLog2(("%s e1kRegWriteIMS: IRQ pending (%08x), arming late int timer...\n",
2961 pThis->szPrf, ICR));
2962 /* Raising an interrupt immediately causes win7 to hang upon NIC reconfiguration, see @bugref{5023}. */
2963 TMTimerSet(pThis->CTX_SUFF(pIntTimer), TMTimerFromNano(pThis->CTX_SUFF(pIntTimer), ITR * 256) +
2964 TMTimerGet(pThis->CTX_SUFF(pIntTimer)));
2965 }
2966
2967 return VINF_SUCCESS;
2968}
2969
2970/**
2971 * Write handler for Interrupt Mask Clear register.
2972 *
2973 * Bits corresponding to 1s in 'value' will be cleared in IMS register.
2974 *
2975 * @param pThis The device state structure.
2976 * @param offset Register offset in memory-mapped frame.
2977 * @param index Register index in register array.
2978 * @param value The value to store.
2979 * @param mask Used to implement partial writes (8 and 16-bit).
2980 * @thread EMT
2981 */
2982static int e1kRegWriteIMC(PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t value)
2983{
2984 int rc = e1kCsEnter(pThis, VINF_IOM_R3_MMIO_WRITE);
2985 if (RT_UNLIKELY(rc != VINF_SUCCESS))
2986 return rc;
2987 if (pThis->fIntRaised)
2988 {
2989 /*
2990 * Technically we should reset fIntRaised in ICR read handler, but it will cause
2991 * Windows to freeze since it may receive an interrupt while still in the very beginning
2992 * of interrupt handler.
2993 */
2994 E1K_INC_ISTAT_CNT(pThis->uStatIntLower);
2995 STAM_COUNTER_INC(&pThis->StatIntsPrevented);
2996 E1kLogRel(("E1000: irq lowered (IMC), icr=0x%x\n", ICR));
2997 /* Lower(0) INTA(0) */
2998 PDMDevHlpPCISetIrq(pThis->CTX_SUFF(pDevIns), 0, 0);
2999 pThis->fIntRaised = false;
3000 E1kLog(("%s e1kRegWriteIMC: Lowered IRQ: ICR=%08x\n", pThis->szPrf, ICR));
3001 }
3002 IMS &= ~value;
3003 E1kLog(("%s e1kRegWriteIMC: IRQ disabled\n", pThis->szPrf));
3004 e1kCsLeave(pThis);
3005
3006 return VINF_SUCCESS;
3007}
3008
3009/**
3010 * Write handler for Receive Control register.
3011 *
3012 * @param pThis The device state structure.
3013 * @param offset Register offset in memory-mapped frame.
3014 * @param index Register index in register array.
3015 * @param value The value to store.
3016 * @param mask Used to implement partial writes (8 and 16-bit).
3017 * @thread EMT
3018 */
3019static int e1kRegWriteRCTL(PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t value)
3020{
3021 /* Update promiscuous mode */
3022 bool fBecomePromiscous = !!(value & (RCTL_UPE | RCTL_MPE));
3023 if (fBecomePromiscous != !!( RCTL & (RCTL_UPE | RCTL_MPE)))
3024 {
3025 /* Promiscuity has changed, pass the knowledge on. */
3026#ifndef IN_RING3
3027 return VINF_IOM_R3_IOPORT_WRITE;
3028#else
3029 if (pThis->pDrvR3)
3030 pThis->pDrvR3->pfnSetPromiscuousMode(pThis->pDrvR3, fBecomePromiscous);
3031#endif
3032 }
3033
3034 /* Adjust receive buffer size */
3035 unsigned cbRxBuf = 2048 >> GET_BITS_V(value, RCTL, BSIZE);
3036 if (value & RCTL_BSEX)
3037 cbRxBuf *= 16;
3038 if (cbRxBuf != pThis->u16RxBSize)
3039 E1kLog2(("%s e1kRegWriteRCTL: Setting receive buffer size to %d (old %d)\n",
3040 pThis->szPrf, cbRxBuf, pThis->u16RxBSize));
3041 pThis->u16RxBSize = cbRxBuf;
3042
3043 /* Update the register */
3044 e1kRegWriteDefault(pThis, offset, index, value);
3045
3046 return VINF_SUCCESS;
3047}
3048
3049/**
3050 * Write handler for Packet Buffer Allocation register.
3051 *
3052 * TXA = 64 - RXA.
3053 *
3054 * @param pThis The device state structure.
3055 * @param offset Register offset in memory-mapped frame.
3056 * @param index Register index in register array.
3057 * @param value The value to store.
3058 * @param mask Used to implement partial writes (8 and 16-bit).
3059 * @thread EMT
3060 */
3061static int e1kRegWritePBA(PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t value)
3062{
3063 e1kRegWriteDefault(pThis, offset, index, value);
3064 PBA_st->txa = 64 - PBA_st->rxa;
3065
3066 return VINF_SUCCESS;
3067}
3068
3069/**
3070 * Write handler for Receive Descriptor Tail register.
3071 *
3072 * @remarks Write into RDT forces switch to HC and signal to
3073 * e1kR3NetworkDown_WaitReceiveAvail().
3074 *
3075 * @returns VBox status code.
3076 *
3077 * @param pThis The device state structure.
3078 * @param offset Register offset in memory-mapped frame.
3079 * @param index Register index in register array.
3080 * @param value The value to store.
3081 * @param mask Used to implement partial writes (8 and 16-bit).
3082 * @thread EMT
3083 */
3084static int e1kRegWriteRDT(PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t value)
3085{
3086#ifndef IN_RING3
3087 /* XXX */
3088// return VINF_IOM_R3_MMIO_WRITE;
3089#endif
3090 int rc = e1kCsRxEnter(pThis, VINF_IOM_R3_MMIO_WRITE);
3091 if (RT_LIKELY(rc == VINF_SUCCESS))
3092 {
3093 E1kLog(("%s e1kRegWriteRDT\n", pThis->szPrf));
3094 rc = e1kRegWriteDefault(pThis, offset, index, value);
3095#ifdef E1K_WITH_RXD_CACHE
3096 /*
3097 * We need to fetch descriptors now as RDT may go whole circle
3098 * before we attempt to store a received packet. For example,
3099 * Intel's DOS drivers use 2 (!) RX descriptors with the total ring
3100 * size being only 8 descriptors! Note that we fetch descriptors
3101 * only when the cache is empty to reduce the number of memory reads
3102 * in case of frequent RDT writes. Don't fetch anything when the
3103 * receiver is disabled either as RDH, RDT, RDLEN can be in some
3104 * messed up state.
3105 * Note that despite the cache may seem empty, meaning that there are
3106 * no more available descriptors in it, it may still be used by RX
3107 * thread which has not yet written the last descriptor back but has
3108 * temporarily released the RX lock in order to write the packet body
3109 * to descriptor's buffer. At this point we still going to do prefetch
3110 * but it won't actually fetch anything if there are no unused slots in
3111 * our "empty" cache (nRxDFetched==E1K_RXD_CACHE_SIZE). We must not
3112 * reset the cache here even if it appears empty. It will be reset at
3113 * a later point in e1kRxDGet().
3114 */
3115 if (e1kRxDIsCacheEmpty(pThis) && (RCTL & RCTL_EN))
3116 e1kRxDPrefetch(pThis);
3117#endif /* E1K_WITH_RXD_CACHE */
3118 e1kCsRxLeave(pThis);
3119 if (RT_SUCCESS(rc))
3120 {
3121/** @todo bird: Use SUPSem* for this so we can signal it in ring-0 as well
3122 * without requiring any context switches. We should also check the
3123 * wait condition before bothering to queue the item as we're currently
3124 * queuing thousands of items per second here in a normal transmit
3125 * scenario. Expect performance changes when fixing this! */
3126#ifdef IN_RING3
3127 /* Signal that we have more receive descriptors available. */
3128 e1kWakeupReceive(pThis->CTX_SUFF(pDevIns));
3129#else
3130 PPDMQUEUEITEMCORE pItem = PDMQueueAlloc(pThis->CTX_SUFF(pCanRxQueue));
3131 if (pItem)
3132 PDMQueueInsert(pThis->CTX_SUFF(pCanRxQueue), pItem);
3133#endif
3134 }
3135 }
3136 return rc;
3137}
3138
3139/**
3140 * Write handler for Receive Delay Timer register.
3141 *
3142 * @param pThis The device state structure.
3143 * @param offset Register offset in memory-mapped frame.
3144 * @param index Register index in register array.
3145 * @param value The value to store.
3146 * @param mask Used to implement partial writes (8 and 16-bit).
3147 * @thread EMT
3148 */
3149static int e1kRegWriteRDTR(PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t value)
3150{
3151 e1kRegWriteDefault(pThis, offset, index, value);
3152 if (value & RDTR_FPD)
3153 {
3154 /* Flush requested, cancel both timers and raise interrupt */
3155#ifdef E1K_USE_RX_TIMERS
3156 e1kCancelTimer(pThis, pThis->CTX_SUFF(pRIDTimer));
3157 e1kCancelTimer(pThis, pThis->CTX_SUFF(pRADTimer));
3158#endif
3159 E1K_INC_ISTAT_CNT(pThis->uStatIntRDTR);
3160 return e1kRaiseInterrupt(pThis, VINF_IOM_R3_MMIO_WRITE, ICR_RXT0);
3161 }
3162
3163 return VINF_SUCCESS;
3164}
3165
3166DECLINLINE(uint32_t) e1kGetTxLen(PE1KSTATE pThis)
3167{
3168 /**
3169 * Make sure TDT won't change during computation. EMT may modify TDT at
3170 * any moment.
3171 */
3172 uint32_t tdt = TDT;
3173 return (TDH>tdt ? TDLEN/sizeof(E1KTXDESC) : 0) + tdt - TDH;
3174}
3175
3176#ifdef IN_RING3
3177#ifdef E1K_TX_DELAY
3178
3179/**
3180 * Transmit Delay Timer handler.
3181 *
3182 * @remarks We only get here when the timer expires.
3183 *
3184 * @param pDevIns Pointer to device instance structure.
3185 * @param pTimer Pointer to the timer.
3186 * @param pvUser NULL.
3187 * @thread EMT
3188 */
3189static DECLCALLBACK(void) e1kTxDelayTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
3190{
3191 PE1KSTATE pThis = (PE1KSTATE )pvUser;
3192 Assert(PDMCritSectIsOwner(&pThis->csTx));
3193
3194 E1K_INC_ISTAT_CNT(pThis->uStatTxDelayExp);
3195#ifdef E1K_INT_STATS
3196 uint64_t u64Elapsed = RTTimeNanoTS() - pThis->u64ArmedAt;
3197 if (u64Elapsed > pThis->uStatMaxTxDelay)
3198 pThis->uStatMaxTxDelay = u64Elapsed;
3199#endif
3200 int rc = e1kXmitPending(pThis, false /*fOnWorkerThread*/);
3201 AssertMsg(RT_SUCCESS(rc) || rc == VERR_TRY_AGAIN, ("%Rrc\n", rc));
3202}
3203#endif /* E1K_TX_DELAY */
3204
3205#ifdef E1K_USE_TX_TIMERS
3206
3207/**
3208 * Transmit Interrupt Delay Timer handler.
3209 *
3210 * @remarks We only get here when the timer expires.
3211 *
3212 * @param pDevIns Pointer to device instance structure.
3213 * @param pTimer Pointer to the timer.
3214 * @param pvUser NULL.
3215 * @thread EMT
3216 */
3217static DECLCALLBACK(void) e1kTxIntDelayTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
3218{
3219 PE1KSTATE pThis = (PE1KSTATE )pvUser;
3220
3221 E1K_INC_ISTAT_CNT(pThis->uStatTID);
3222 /* Cancel absolute delay timer as we have already got attention */
3223#ifndef E1K_NO_TAD
3224 e1kCancelTimer(pThis, pThis->CTX_SUFF(pTADTimer));
3225#endif /* E1K_NO_TAD */
3226 e1kRaiseInterrupt(pThis, ICR_TXDW);
3227}
3228
3229/**
3230 * Transmit Absolute Delay Timer handler.
3231 *
3232 * @remarks We only get here when the timer expires.
3233 *
3234 * @param pDevIns Pointer to device instance structure.
3235 * @param pTimer Pointer to the timer.
3236 * @param pvUser NULL.
3237 * @thread EMT
3238 */
3239static DECLCALLBACK(void) e1kTxAbsDelayTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
3240{
3241 PE1KSTATE pThis = (PE1KSTATE )pvUser;
3242
3243 E1K_INC_ISTAT_CNT(pThis->uStatTAD);
3244 /* Cancel interrupt delay timer as we have already got attention */
3245 e1kCancelTimer(pThis, pThis->CTX_SUFF(pTIDTimer));
3246 e1kRaiseInterrupt(pThis, ICR_TXDW);
3247}
3248
3249#endif /* E1K_USE_TX_TIMERS */
3250#ifdef E1K_USE_RX_TIMERS
3251
3252/**
3253 * Receive Interrupt Delay Timer handler.
3254 *
3255 * @remarks We only get here when the timer expires.
3256 *
3257 * @param pDevIns Pointer to device instance structure.
3258 * @param pTimer Pointer to the timer.
3259 * @param pvUser NULL.
3260 * @thread EMT
3261 */
3262static DECLCALLBACK(void) e1kRxIntDelayTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
3263{
3264 PE1KSTATE pThis = (PE1KSTATE )pvUser;
3265
3266 E1K_INC_ISTAT_CNT(pThis->uStatRID);
3267 /* Cancel absolute delay timer as we have already got attention */
3268 e1kCancelTimer(pThis, pThis->CTX_SUFF(pRADTimer));
3269 e1kRaiseInterrupt(pThis, ICR_RXT0);
3270}
3271
3272/**
3273 * Receive Absolute Delay Timer handler.
3274 *
3275 * @remarks We only get here when the timer expires.
3276 *
3277 * @param pDevIns Pointer to device instance structure.
3278 * @param pTimer Pointer to the timer.
3279 * @param pvUser NULL.
3280 * @thread EMT
3281 */
3282static DECLCALLBACK(void) e1kRxAbsDelayTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
3283{
3284 PE1KSTATE pThis = (PE1KSTATE )pvUser;
3285
3286 E1K_INC_ISTAT_CNT(pThis->uStatRAD);
3287 /* Cancel interrupt delay timer as we have already got attention */
3288 e1kCancelTimer(pThis, pThis->CTX_SUFF(pRIDTimer));
3289 e1kRaiseInterrupt(pThis, ICR_RXT0);
3290}
3291
3292#endif /* E1K_USE_RX_TIMERS */
3293
3294/**
3295 * Late Interrupt Timer handler.
3296 *
3297 * @param pDevIns Pointer to device instance structure.
3298 * @param pTimer Pointer to the timer.
3299 * @param pvUser NULL.
3300 * @thread EMT
3301 */
3302static DECLCALLBACK(void) e1kLateIntTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
3303{
3304 PE1KSTATE pThis = (PE1KSTATE )pvUser;
3305
3306 STAM_PROFILE_ADV_START(&pThis->StatLateIntTimer, a);
3307 STAM_COUNTER_INC(&pThis->StatLateInts);
3308 E1K_INC_ISTAT_CNT(pThis->uStatIntLate);
3309#if 0
3310 if (pThis->iStatIntLost > -100)
3311 pThis->iStatIntLost--;
3312#endif
3313 e1kRaiseInterrupt(pThis, VERR_SEM_BUSY, 0);
3314 STAM_PROFILE_ADV_STOP(&pThis->StatLateIntTimer, a);
3315}
3316
3317/**
3318 * Link Up Timer handler.
3319 *
3320 * @param pDevIns Pointer to device instance structure.
3321 * @param pTimer Pointer to the timer.
3322 * @param pvUser NULL.
3323 * @thread EMT
3324 */
3325static DECLCALLBACK(void) e1kLinkUpTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
3326{
3327 PE1KSTATE pThis = (PE1KSTATE )pvUser;
3328
3329 /*
3330 * This can happen if we set the link status to down when the Link up timer was
3331 * already armed (shortly after e1kLoadDone() or when the cable was disconnected
3332 * and connect+disconnect the cable very quick.
3333 */
3334 if (!pThis->fCableConnected)
3335 return;
3336
3337 e1kR3LinkUp(pThis);
3338}
3339
3340#endif /* IN_RING3 */
3341
3342/**
3343 * Sets up the GSO context according to the TSE new context descriptor.
3344 *
3345 * @param pGso The GSO context to setup.
3346 * @param pCtx The context descriptor.
3347 */
3348DECLINLINE(void) e1kSetupGsoCtx(PPDMNETWORKGSO pGso, E1KTXCTX const *pCtx)
3349{
3350 pGso->u8Type = PDMNETWORKGSOTYPE_INVALID;
3351
3352 /*
3353 * See if the context descriptor describes something that could be TCP or
3354 * UDP over IPv[46].
3355 */
3356 /* Check the header ordering and spacing: 1. Ethernet, 2. IP, 3. TCP/UDP. */
3357 if (RT_UNLIKELY( pCtx->ip.u8CSS < sizeof(RTNETETHERHDR) ))
3358 {
3359 E1kLog(("e1kSetupGsoCtx: IPCSS=%#x\n", pCtx->ip.u8CSS));
3360 return;
3361 }
3362 if (RT_UNLIKELY( pCtx->tu.u8CSS < (size_t)pCtx->ip.u8CSS + (pCtx->dw2.fIP ? RTNETIPV4_MIN_LEN : RTNETIPV6_MIN_LEN) ))
3363 {
3364 E1kLog(("e1kSetupGsoCtx: TUCSS=%#x\n", pCtx->tu.u8CSS));
3365 return;
3366 }
3367 if (RT_UNLIKELY( pCtx->dw2.fTCP
3368 ? pCtx->dw3.u8HDRLEN < (size_t)pCtx->tu.u8CSS + RTNETTCP_MIN_LEN
3369 : pCtx->dw3.u8HDRLEN != (size_t)pCtx->tu.u8CSS + RTNETUDP_MIN_LEN ))
3370 {
3371 E1kLog(("e1kSetupGsoCtx: HDRLEN=%#x TCP=%d\n", pCtx->dw3.u8HDRLEN, pCtx->dw2.fTCP));
3372 return;
3373 }
3374
3375 /* The end of the TCP/UDP checksum should stop at the end of the packet or at least after the headers. */
3376 if (RT_UNLIKELY( pCtx->tu.u16CSE > 0 && pCtx->tu.u16CSE <= pCtx->dw3.u8HDRLEN ))
3377 {
3378 E1kLog(("e1kSetupGsoCtx: TUCSE=%#x HDRLEN=%#x\n", pCtx->tu.u16CSE, pCtx->dw3.u8HDRLEN));
3379 return;
3380 }
3381
3382 /* IPv4 checksum offset. */
3383 if (RT_UNLIKELY( pCtx->dw2.fIP && (size_t)pCtx->ip.u8CSO - pCtx->ip.u8CSS != RT_UOFFSETOF(RTNETIPV4, ip_sum) ))
3384 {
3385 E1kLog(("e1kSetupGsoCtx: IPCSO=%#x IPCSS=%#x\n", pCtx->ip.u8CSO, pCtx->ip.u8CSS));
3386 return;
3387 }
3388
3389 /* TCP/UDP checksum offsets. */
3390 if (RT_UNLIKELY( (size_t)pCtx->tu.u8CSO - pCtx->tu.u8CSS
3391 != ( pCtx->dw2.fTCP
3392 ? RT_UOFFSETOF(RTNETTCP, th_sum)
3393 : RT_UOFFSETOF(RTNETUDP, uh_sum) ) ))
3394 {
3395 E1kLog(("e1kSetupGsoCtx: TUCSO=%#x TUCSS=%#x TCP=%d\n", pCtx->ip.u8CSO, pCtx->ip.u8CSS, pCtx->dw2.fTCP));
3396 return;
3397 }
3398
3399 /*
3400 * Because of internal networking using a 16-bit size field for GSO context
3401 * plus frame, we have to make sure we don't exceed this.
3402 */
3403 if (RT_UNLIKELY( pCtx->dw3.u8HDRLEN + pCtx->dw2.u20PAYLEN > VBOX_MAX_GSO_SIZE ))
3404 {
3405 E1kLog(("e1kSetupGsoCtx: HDRLEN(=%#x) + PAYLEN(=%#x) = %#x, max is %#x\n",
3406 pCtx->dw3.u8HDRLEN, pCtx->dw2.u20PAYLEN, pCtx->dw3.u8HDRLEN + pCtx->dw2.u20PAYLEN, VBOX_MAX_GSO_SIZE));
3407 return;
3408 }
3409
3410 /*
3411 * We're good for now - we'll do more checks when seeing the data.
3412 * So, figure the type of offloading and setup the context.
3413 */
3414 if (pCtx->dw2.fIP)
3415 {
3416 if (pCtx->dw2.fTCP)
3417 {
3418 pGso->u8Type = PDMNETWORKGSOTYPE_IPV4_TCP;
3419 pGso->cbHdrsSeg = pCtx->dw3.u8HDRLEN;
3420 }
3421 else
3422 {
3423 pGso->u8Type = PDMNETWORKGSOTYPE_IPV4_UDP;
3424 pGso->cbHdrsSeg = pCtx->tu.u8CSS; /* IP header only */
3425 }
3426 /** @todo Detect IPv4-IPv6 tunneling (need test setup since linux doesn't do
3427 * this yet it seems)... */
3428 }
3429 else
3430 {
3431 pGso->cbHdrsSeg = pCtx->dw3.u8HDRLEN; /* @todo IPv6 UFO */
3432 if (pCtx->dw2.fTCP)
3433 pGso->u8Type = PDMNETWORKGSOTYPE_IPV6_TCP;
3434 else
3435 pGso->u8Type = PDMNETWORKGSOTYPE_IPV6_UDP;
3436 }
3437 pGso->offHdr1 = pCtx->ip.u8CSS;
3438 pGso->offHdr2 = pCtx->tu.u8CSS;
3439 pGso->cbHdrsTotal = pCtx->dw3.u8HDRLEN;
3440 pGso->cbMaxSeg = pCtx->dw3.u16MSS;
3441 Assert(PDMNetGsoIsValid(pGso, sizeof(*pGso), pGso->cbMaxSeg * 5));
3442 E1kLog2(("e1kSetupGsoCtx: mss=%#x hdr=%#x hdrseg=%#x hdr1=%#x hdr2=%#x %s\n",
3443 pGso->cbMaxSeg, pGso->cbHdrsTotal, pGso->cbHdrsSeg, pGso->offHdr1, pGso->offHdr2, PDMNetGsoTypeName((PDMNETWORKGSOTYPE)pGso->u8Type) ));
3444}
3445
3446/**
3447 * Checks if we can use GSO processing for the current TSE frame.
3448 *
3449 * @param pThis The device state structure.
3450 * @param pGso The GSO context.
3451 * @param pData The first data descriptor of the frame.
3452 * @param pCtx The TSO context descriptor.
3453 */
3454DECLINLINE(bool) e1kCanDoGso(PE1KSTATE pThis, PCPDMNETWORKGSO pGso, E1KTXDAT const *pData, E1KTXCTX const *pCtx)
3455{
3456 if (!pData->cmd.fTSE)
3457 {
3458 E1kLog2(("e1kCanDoGso: !TSE\n"));
3459 return false;
3460 }
3461 if (pData->cmd.fVLE) /** @todo VLAN tagging. */
3462 {
3463 E1kLog(("e1kCanDoGso: VLE\n"));
3464 return false;
3465 }
3466 if (RT_UNLIKELY(!pThis->fGSOEnabled))
3467 {
3468 E1kLog3(("e1kCanDoGso: GSO disabled via CFGM\n"));
3469 return false;
3470 }
3471
3472 switch ((PDMNETWORKGSOTYPE)pGso->u8Type)
3473 {
3474 case PDMNETWORKGSOTYPE_IPV4_TCP:
3475 case PDMNETWORKGSOTYPE_IPV4_UDP:
3476 if (!pData->dw3.fIXSM)
3477 {
3478 E1kLog(("e1kCanDoGso: !IXSM (IPv4)\n"));
3479 return false;
3480 }
3481 if (!pData->dw3.fTXSM)
3482 {
3483 E1kLog(("e1kCanDoGso: !TXSM (IPv4)\n"));
3484 return false;
3485 }
3486 /** @todo what more check should we perform here? Ethernet frame type? */
3487 E1kLog2(("e1kCanDoGso: OK, IPv4\n"));
3488 return true;
3489
3490 case PDMNETWORKGSOTYPE_IPV6_TCP:
3491 case PDMNETWORKGSOTYPE_IPV6_UDP:
3492 if (pData->dw3.fIXSM && pCtx->ip.u8CSO)
3493 {
3494 E1kLog(("e1kCanDoGso: IXSM (IPv6)\n"));
3495 return false;
3496 }
3497 if (!pData->dw3.fTXSM)
3498 {
3499 E1kLog(("e1kCanDoGso: TXSM (IPv6)\n"));
3500 return false;
3501 }
3502 /** @todo what more check should we perform here? Ethernet frame type? */
3503 E1kLog2(("e1kCanDoGso: OK, IPv4\n"));
3504 return true;
3505
3506 default:
3507 Assert(pGso->u8Type == PDMNETWORKGSOTYPE_INVALID);
3508 E1kLog2(("e1kCanDoGso: e1kSetupGsoCtx failed\n"));
3509 return false;
3510 }
3511}
3512
3513/**
3514 * Frees the current xmit buffer.
3515 *
3516 * @param pThis The device state structure.
3517 */
3518static void e1kXmitFreeBuf(PE1KSTATE pThis)
3519{
3520 PPDMSCATTERGATHER pSg = pThis->CTX_SUFF(pTxSg);
3521 if (pSg)
3522 {
3523 pThis->CTX_SUFF(pTxSg) = NULL;
3524
3525 if (pSg->pvAllocator != pThis)
3526 {
3527 PPDMINETWORKUP pDrv = pThis->CTX_SUFF(pDrv);
3528 if (pDrv)
3529 pDrv->pfnFreeBuf(pDrv, pSg);
3530 }
3531 else
3532 {
3533 /* loopback */
3534 AssertCompileMemberSize(E1KSTATE, uTxFallback.Sg, 8 * sizeof(size_t));
3535 Assert(pSg->fFlags == (PDMSCATTERGATHER_FLAGS_MAGIC | PDMSCATTERGATHER_FLAGS_OWNER_3));
3536 pSg->fFlags = 0;
3537 pSg->pvAllocator = NULL;
3538 }
3539 }
3540}
3541
3542#ifndef E1K_WITH_TXD_CACHE
3543/**
3544 * Allocates an xmit buffer.
3545 *
3546 * @returns See PDMINETWORKUP::pfnAllocBuf.
3547 * @param pThis The device state structure.
3548 * @param cbMin The minimum frame size.
3549 * @param fExactSize Whether cbMin is exact or if we have to max it
3550 * out to the max MTU size.
3551 * @param fGso Whether this is a GSO frame or not.
3552 */
3553DECLINLINE(int) e1kXmitAllocBuf(PE1KSTATE pThis, size_t cbMin, bool fExactSize, bool fGso)
3554{
3555 /* Adjust cbMin if necessary. */
3556 if (!fExactSize)
3557 cbMin = RT_MAX(cbMin, E1K_MAX_TX_PKT_SIZE);
3558
3559 /* Deal with existing buffer (descriptor screw up, reset, etc). */
3560 if (RT_UNLIKELY(pThis->CTX_SUFF(pTxSg)))
3561 e1kXmitFreeBuf(pThis);
3562 Assert(pThis->CTX_SUFF(pTxSg) == NULL);
3563
3564 /*
3565 * Allocate the buffer.
3566 */
3567 PPDMSCATTERGATHER pSg;
3568 if (RT_LIKELY(GET_BITS(RCTL, LBM) != RCTL_LBM_TCVR))
3569 {
3570 PPDMINETWORKUP pDrv = pThis->CTX_SUFF(pDrv);
3571 if (RT_UNLIKELY(!pDrv))
3572 return VERR_NET_DOWN;
3573 int rc = pDrv->pfnAllocBuf(pDrv, cbMin, fGso ? &pThis->GsoCtx : NULL, &pSg);
3574 if (RT_FAILURE(rc))
3575 {
3576 /* Suspend TX as we are out of buffers atm */
3577 STATUS |= STATUS_TXOFF;
3578 return rc;
3579 }
3580 }
3581 else
3582 {
3583 /* Create a loopback using the fallback buffer and preallocated SG. */
3584 AssertCompileMemberSize(E1KSTATE, uTxFallback.Sg, 8 * sizeof(size_t));
3585 pSg = &pThis->uTxFallback.Sg;
3586 pSg->fFlags = PDMSCATTERGATHER_FLAGS_MAGIC | PDMSCATTERGATHER_FLAGS_OWNER_3;
3587 pSg->cbUsed = 0;
3588 pSg->cbAvailable = 0;
3589 pSg->pvAllocator = pThis;
3590 pSg->pvUser = NULL; /* No GSO here. */
3591 pSg->cSegs = 1;
3592 pSg->aSegs[0].pvSeg = pThis->aTxPacketFallback;
3593 pSg->aSegs[0].cbSeg = sizeof(pThis->aTxPacketFallback);
3594 }
3595
3596 pThis->CTX_SUFF(pTxSg) = pSg;
3597 return VINF_SUCCESS;
3598}
3599#else /* E1K_WITH_TXD_CACHE */
3600/**
3601 * Allocates an xmit buffer.
3602 *
3603 * @returns See PDMINETWORKUP::pfnAllocBuf.
3604 * @param pThis The device state structure.
3605 * @param cbMin The minimum frame size.
3606 * @param fExactSize Whether cbMin is exact or if we have to max it
3607 * out to the max MTU size.
3608 * @param fGso Whether this is a GSO frame or not.
3609 */
3610DECLINLINE(int) e1kXmitAllocBuf(PE1KSTATE pThis, bool fGso)
3611{
3612 /* Deal with existing buffer (descriptor screw up, reset, etc). */
3613 if (RT_UNLIKELY(pThis->CTX_SUFF(pTxSg)))
3614 e1kXmitFreeBuf(pThis);
3615 Assert(pThis->CTX_SUFF(pTxSg) == NULL);
3616
3617 /*
3618 * Allocate the buffer.
3619 */
3620 PPDMSCATTERGATHER pSg;
3621 if (RT_LIKELY(GET_BITS(RCTL, LBM) != RCTL_LBM_TCVR))
3622 {
3623 if (pThis->cbTxAlloc == 0)
3624 {
3625 /* Zero packet, no need for the buffer */
3626 return VINF_SUCCESS;
3627 }
3628
3629 PPDMINETWORKUP pDrv = pThis->CTX_SUFF(pDrv);
3630 if (RT_UNLIKELY(!pDrv))
3631 return VERR_NET_DOWN;
3632 int rc = pDrv->pfnAllocBuf(pDrv, pThis->cbTxAlloc, fGso ? &pThis->GsoCtx : NULL, &pSg);
3633 if (RT_FAILURE(rc))
3634 {
3635 /* Suspend TX as we are out of buffers atm */
3636 STATUS |= STATUS_TXOFF;
3637 return rc;
3638 }
3639 E1kLog3(("%s Allocated buffer for TX packet: cb=%u %s%s\n",
3640 pThis->szPrf, pThis->cbTxAlloc,
3641 pThis->fVTag ? "VLAN " : "",
3642 pThis->fGSO ? "GSO " : ""));
3643 pThis->cbTxAlloc = 0;
3644 }
3645 else
3646 {
3647 /* Create a loopback using the fallback buffer and preallocated SG. */
3648 AssertCompileMemberSize(E1KSTATE, uTxFallback.Sg, 8 * sizeof(size_t));
3649 pSg = &pThis->uTxFallback.Sg;
3650 pSg->fFlags = PDMSCATTERGATHER_FLAGS_MAGIC | PDMSCATTERGATHER_FLAGS_OWNER_3;
3651 pSg->cbUsed = 0;
3652 pSg->cbAvailable = 0;
3653 pSg->pvAllocator = pThis;
3654 pSg->pvUser = NULL; /* No GSO here. */
3655 pSg->cSegs = 1;
3656 pSg->aSegs[0].pvSeg = pThis->aTxPacketFallback;
3657 pSg->aSegs[0].cbSeg = sizeof(pThis->aTxPacketFallback);
3658 }
3659
3660 pThis->CTX_SUFF(pTxSg) = pSg;
3661 return VINF_SUCCESS;
3662}
3663#endif /* E1K_WITH_TXD_CACHE */
3664
3665/**
3666 * Checks if it's a GSO buffer or not.
3667 *
3668 * @returns true / false.
3669 * @param pTxSg The scatter / gather buffer.
3670 */
3671DECLINLINE(bool) e1kXmitIsGsoBuf(PDMSCATTERGATHER const *pTxSg)
3672{
3673#if 0
3674 if (!pTxSg)
3675 E1kLog(("e1kXmitIsGsoBuf: pTxSG is NULL\n"));
3676 if (pTxSg && pTxSg->pvUser)
3677 E1kLog(("e1kXmitIsGsoBuf: pvUser is NULL\n"));
3678#endif
3679 return pTxSg && pTxSg->pvUser /* GSO indicator */;
3680}
3681
3682#ifndef E1K_WITH_TXD_CACHE
3683/**
3684 * Load transmit descriptor from guest memory.
3685 *
3686 * @param pThis The device state structure.
3687 * @param pDesc Pointer to descriptor union.
3688 * @param addr Physical address in guest context.
3689 * @thread E1000_TX
3690 */
3691DECLINLINE(void) e1kLoadDesc(PE1KSTATE pThis, E1KTXDESC* pDesc, RTGCPHYS addr)
3692{
3693 PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns), addr, pDesc, sizeof(E1KTXDESC));
3694}
3695#else /* E1K_WITH_TXD_CACHE */
3696/**
3697 * Load transmit descriptors from guest memory.
3698 *
3699 * We need two physical reads in case the tail wrapped around the end of TX
3700 * descriptor ring.
3701 *
3702 * @returns the actual number of descriptors fetched.
3703 * @param pThis The device state structure.
3704 * @param pDesc Pointer to descriptor union.
3705 * @param addr Physical address in guest context.
3706 * @thread E1000_TX
3707 */
3708DECLINLINE(unsigned) e1kTxDLoadMore(PE1KSTATE pThis)
3709{
3710 Assert(pThis->iTxDCurrent == 0);
3711 /* We've already loaded pThis->nTxDFetched descriptors past TDH. */
3712 unsigned nDescsAvailable = e1kGetTxLen(pThis) - pThis->nTxDFetched;
3713 unsigned nDescsToFetch = RT_MIN(nDescsAvailable, E1K_TXD_CACHE_SIZE - pThis->nTxDFetched);
3714 unsigned nDescsTotal = TDLEN / sizeof(E1KTXDESC);
3715 unsigned nFirstNotLoaded = (TDH + pThis->nTxDFetched) % nDescsTotal;
3716 unsigned nDescsInSingleRead = RT_MIN(nDescsToFetch, nDescsTotal - nFirstNotLoaded);
3717 E1kLog3(("%s e1kTxDLoadMore: nDescsAvailable=%u nDescsToFetch=%u "
3718 "nDescsTotal=%u nFirstNotLoaded=0x%x nDescsInSingleRead=%u\n",
3719 pThis->szPrf, nDescsAvailable, nDescsToFetch, nDescsTotal,
3720 nFirstNotLoaded, nDescsInSingleRead));
3721 if (nDescsToFetch == 0)
3722 return 0;
3723 E1KTXDESC* pFirstEmptyDesc = &pThis->aTxDescriptors[pThis->nTxDFetched];
3724 PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns),
3725 ((uint64_t)TDBAH << 32) + TDBAL + nFirstNotLoaded * sizeof(E1KTXDESC),
3726 pFirstEmptyDesc, nDescsInSingleRead * sizeof(E1KTXDESC));
3727 E1kLog3(("%s Fetched %u TX descriptors at %08x%08x(0x%x), TDLEN=%08x, TDH=%08x, TDT=%08x\n",
3728 pThis->szPrf, nDescsInSingleRead,
3729 TDBAH, TDBAL + TDH * sizeof(E1KTXDESC),
3730 nFirstNotLoaded, TDLEN, TDH, TDT));
3731 if (nDescsToFetch > nDescsInSingleRead)
3732 {
3733 PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns),
3734 ((uint64_t)TDBAH << 32) + TDBAL,
3735 pFirstEmptyDesc + nDescsInSingleRead,
3736 (nDescsToFetch - nDescsInSingleRead) * sizeof(E1KTXDESC));
3737 E1kLog3(("%s Fetched %u TX descriptors at %08x%08x\n",
3738 pThis->szPrf, nDescsToFetch - nDescsInSingleRead,
3739 TDBAH, TDBAL));
3740 }
3741 pThis->nTxDFetched += nDescsToFetch;
3742 return nDescsToFetch;
3743}
3744
3745/**
3746 * Load transmit descriptors from guest memory only if there are no loaded
3747 * descriptors.
3748 *
3749 * @returns true if there are descriptors in cache.
3750 * @param pThis The device state structure.
3751 * @param pDesc Pointer to descriptor union.
3752 * @param addr Physical address in guest context.
3753 * @thread E1000_TX
3754 */
3755DECLINLINE(bool) e1kTxDLazyLoad(PE1KSTATE pThis)
3756{
3757 if (pThis->nTxDFetched == 0)
3758 return e1kTxDLoadMore(pThis) != 0;
3759 return true;
3760}
3761#endif /* E1K_WITH_TXD_CACHE */
3762
3763/**
3764 * Write back transmit descriptor to guest memory.
3765 *
3766 * @param pThis The device state structure.
3767 * @param pDesc Pointer to descriptor union.
3768 * @param addr Physical address in guest context.
3769 * @thread E1000_TX
3770 */
3771DECLINLINE(void) e1kWriteBackDesc(PE1KSTATE pThis, E1KTXDESC* pDesc, RTGCPHYS addr)
3772{
3773 /* Only the last half of the descriptor has to be written back. */
3774 e1kPrintTDesc(pThis, pDesc, "^^^");
3775 PDMDevHlpPCIPhysWrite(pThis->CTX_SUFF(pDevIns), addr, pDesc, sizeof(E1KTXDESC));
3776}
3777
3778/**
3779 * Transmit complete frame.
3780 *
3781 * @remarks We skip the FCS since we're not responsible for sending anything to
3782 * a real ethernet wire.
3783 *
3784 * @param pThis The device state structure.
3785 * @param fOnWorkerThread Whether we're on a worker thread or an EMT.
3786 * @thread E1000_TX
3787 */
3788static void e1kTransmitFrame(PE1KSTATE pThis, bool fOnWorkerThread)
3789{
3790 PPDMSCATTERGATHER pSg = pThis->CTX_SUFF(pTxSg);
3791 uint32_t cbFrame = pSg ? (uint32_t)pSg->cbUsed : 0;
3792 Assert(!pSg || pSg->cSegs == 1);
3793
3794 if (cbFrame > 70) /* unqualified guess */
3795 pThis->led.Asserted.s.fWriting = pThis->led.Actual.s.fWriting = 1;
3796
3797#ifdef E1K_INT_STATS
3798 if (cbFrame <= 1514)
3799 E1K_INC_ISTAT_CNT(pThis->uStatTx1514);
3800 else if (cbFrame <= 2962)
3801 E1K_INC_ISTAT_CNT(pThis->uStatTx2962);
3802 else if (cbFrame <= 4410)
3803 E1K_INC_ISTAT_CNT(pThis->uStatTx4410);
3804 else if (cbFrame <= 5858)
3805 E1K_INC_ISTAT_CNT(pThis->uStatTx5858);
3806 else if (cbFrame <= 7306)
3807 E1K_INC_ISTAT_CNT(pThis->uStatTx7306);
3808 else if (cbFrame <= 8754)
3809 E1K_INC_ISTAT_CNT(pThis->uStatTx8754);
3810 else if (cbFrame <= 16384)
3811 E1K_INC_ISTAT_CNT(pThis->uStatTx16384);
3812 else if (cbFrame <= 32768)
3813 E1K_INC_ISTAT_CNT(pThis->uStatTx32768);
3814 else
3815 E1K_INC_ISTAT_CNT(pThis->uStatTxLarge);
3816#endif /* E1K_INT_STATS */
3817
3818 /* Add VLAN tag */
3819 if (cbFrame > 12 && pThis->fVTag)
3820 {
3821 E1kLog3(("%s Inserting VLAN tag %08x\n",
3822 pThis->szPrf, RT_BE2H_U16(VET) | (RT_BE2H_U16(pThis->u16VTagTCI) << 16)));
3823 memmove((uint8_t*)pSg->aSegs[0].pvSeg + 16, (uint8_t*)pSg->aSegs[0].pvSeg + 12, cbFrame - 12);
3824 *((uint32_t*)pSg->aSegs[0].pvSeg + 3) = RT_BE2H_U16(VET) | (RT_BE2H_U16(pThis->u16VTagTCI) << 16);
3825 pSg->cbUsed += 4;
3826 cbFrame += 4;
3827 Assert(pSg->cbUsed == cbFrame);
3828 Assert(pSg->cbUsed <= pSg->cbAvailable);
3829 }
3830/* E1kLog2(("%s < < < Outgoing packet. Dump follows: > > >\n"
3831 "%.*Rhxd\n"
3832 "%s < < < < < < < < < < < < < End of dump > > > > > > > > > > > >\n",
3833 pThis->szPrf, cbFrame, pSg->aSegs[0].pvSeg, pThis->szPrf));*/
3834
3835 /* Update the stats */
3836 E1K_INC_CNT32(TPT);
3837 E1K_ADD_CNT64(TOTL, TOTH, cbFrame);
3838 E1K_INC_CNT32(GPTC);
3839 if (pSg && e1kIsBroadcast(pSg->aSegs[0].pvSeg))
3840 E1K_INC_CNT32(BPTC);
3841 else if (pSg && e1kIsMulticast(pSg->aSegs[0].pvSeg))
3842 E1K_INC_CNT32(MPTC);
3843 /* Update octet transmit counter */
3844 E1K_ADD_CNT64(GOTCL, GOTCH, cbFrame);
3845 if (pThis->CTX_SUFF(pDrv))
3846 STAM_REL_COUNTER_ADD(&pThis->StatTransmitBytes, cbFrame);
3847 if (cbFrame == 64)
3848 E1K_INC_CNT32(PTC64);
3849 else if (cbFrame < 128)
3850 E1K_INC_CNT32(PTC127);
3851 else if (cbFrame < 256)
3852 E1K_INC_CNT32(PTC255);
3853 else if (cbFrame < 512)
3854 E1K_INC_CNT32(PTC511);
3855 else if (cbFrame < 1024)
3856 E1K_INC_CNT32(PTC1023);
3857 else
3858 E1K_INC_CNT32(PTC1522);
3859
3860 E1K_INC_ISTAT_CNT(pThis->uStatTxFrm);
3861
3862 /*
3863 * Dump and send the packet.
3864 */
3865 int rc = VERR_NET_DOWN;
3866 if (pSg && pSg->pvAllocator != pThis)
3867 {
3868 e1kPacketDump(pThis, (uint8_t const *)pSg->aSegs[0].pvSeg, cbFrame, "--> Outgoing");
3869
3870 pThis->CTX_SUFF(pTxSg) = NULL;
3871 PPDMINETWORKUP pDrv = pThis->CTX_SUFF(pDrv);
3872 if (pDrv)
3873 {
3874 /* Release critical section to avoid deadlock in CanReceive */
3875 //e1kCsLeave(pThis);
3876 STAM_PROFILE_START(&pThis->CTX_SUFF_Z(StatTransmitSend), a);
3877 rc = pDrv->pfnSendBuf(pDrv, pSg, fOnWorkerThread);
3878 STAM_PROFILE_STOP(&pThis->CTX_SUFF_Z(StatTransmitSend), a);
3879 //e1kCsEnter(pThis, RT_SRC_POS);
3880 }
3881 }
3882 else if (pSg)
3883 {
3884 Assert(pSg->aSegs[0].pvSeg == pThis->aTxPacketFallback);
3885 e1kPacketDump(pThis, (uint8_t const *)pSg->aSegs[0].pvSeg, cbFrame, "--> Loopback");
3886
3887 /** @todo do we actually need to check that we're in loopback mode here? */
3888 if (GET_BITS(RCTL, LBM) == RCTL_LBM_TCVR)
3889 {
3890 E1KRXDST status;
3891 RT_ZERO(status);
3892 status.fPIF = true;
3893 e1kHandleRxPacket(pThis, pSg->aSegs[0].pvSeg, cbFrame, status);
3894 rc = VINF_SUCCESS;
3895 }
3896 e1kXmitFreeBuf(pThis);
3897 }
3898 else
3899 rc = VERR_NET_DOWN;
3900 if (RT_FAILURE(rc))
3901 {
3902 E1kLogRel(("E1000: ERROR! pfnSend returned %Rrc\n", rc));
3903 /** @todo handle VERR_NET_DOWN and VERR_NET_NO_BUFFER_SPACE. Signal error ? */
3904 }
3905
3906 pThis->led.Actual.s.fWriting = 0;
3907}
3908
3909/**
3910 * Compute and write internet checksum (e1kCSum16) at the specified offset.
3911 *
3912 * @param pThis The device state structure.
3913 * @param pPkt Pointer to the packet.
3914 * @param u16PktLen Total length of the packet.
3915 * @param cso Offset in packet to write checksum at.
3916 * @param css Offset in packet to start computing
3917 * checksum from.
3918 * @param cse Offset in packet to stop computing
3919 * checksum at.
3920 * @thread E1000_TX
3921 */
3922static void e1kInsertChecksum(PE1KSTATE pThis, uint8_t *pPkt, uint16_t u16PktLen, uint8_t cso, uint8_t css, uint16_t cse)
3923{
3924 if (css >= u16PktLen)
3925 {
3926 E1kLog2(("%s css(%X) is greater than packet length-1(%X), checksum is not inserted\n",
3927 pThis->szPrf, cso, u16PktLen));
3928 return;
3929 }
3930
3931 if (cso >= u16PktLen - 1)
3932 {
3933 E1kLog2(("%s cso(%X) is greater than packet length-2(%X), checksum is not inserted\n",
3934 pThis->szPrf, cso, u16PktLen));
3935 return;
3936 }
3937
3938 if (cse == 0)
3939 cse = u16PktLen - 1;
3940 uint16_t u16ChkSum = e1kCSum16(pPkt + css, cse - css + 1);
3941 E1kLog2(("%s Inserting csum: %04X at %02X, old value: %04X\n", pThis->szPrf,
3942 u16ChkSum, cso, *(uint16_t*)(pPkt + cso)));
3943 *(uint16_t*)(pPkt + cso) = u16ChkSum;
3944}
3945
3946/**
3947 * Add a part of descriptor's buffer to transmit frame.
3948 *
3949 * @remarks data.u64BufAddr is used unconditionally for both data
3950 * and legacy descriptors since it is identical to
3951 * legacy.u64BufAddr.
3952 *
3953 * @param pThis The device state structure.
3954 * @param pDesc Pointer to the descriptor to transmit.
3955 * @param u16Len Length of buffer to the end of segment.
3956 * @param fSend Force packet sending.
3957 * @param fOnWorkerThread Whether we're on a worker thread or an EMT.
3958 * @thread E1000_TX
3959 */
3960#ifndef E1K_WITH_TXD_CACHE
3961static void e1kFallbackAddSegment(PE1KSTATE pThis, RTGCPHYS PhysAddr, uint16_t u16Len, bool fSend, bool fOnWorkerThread)
3962{
3963 /* TCP header being transmitted */
3964 struct E1kTcpHeader *pTcpHdr = (struct E1kTcpHeader *)
3965 (pThis->aTxPacketFallback + pThis->contextTSE.tu.u8CSS);
3966 /* IP header being transmitted */
3967 struct E1kIpHeader *pIpHdr = (struct E1kIpHeader *)
3968 (pThis->aTxPacketFallback + pThis->contextTSE.ip.u8CSS);
3969
3970 E1kLog3(("%s e1kFallbackAddSegment: Length=%x, remaining payload=%x, header=%x, send=%RTbool\n",
3971 pThis->szPrf, u16Len, pThis->u32PayRemain, pThis->u16HdrRemain, fSend));
3972 Assert(pThis->u32PayRemain + pThis->u16HdrRemain > 0);
3973
3974 PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns), PhysAddr,
3975 pThis->aTxPacketFallback + pThis->u16TxPktLen, u16Len);
3976 E1kLog3(("%s Dump of the segment:\n"
3977 "%.*Rhxd\n"
3978 "%s --- End of dump ---\n",
3979 pThis->szPrf, u16Len, pThis->aTxPacketFallback + pThis->u16TxPktLen, pThis->szPrf));
3980 pThis->u16TxPktLen += u16Len;
3981 E1kLog3(("%s e1kFallbackAddSegment: pThis->u16TxPktLen=%x\n",
3982 pThis->szPrf, pThis->u16TxPktLen));
3983 if (pThis->u16HdrRemain > 0)
3984 {
3985 /* The header was not complete, check if it is now */
3986 if (u16Len >= pThis->u16HdrRemain)
3987 {
3988 /* The rest is payload */
3989 u16Len -= pThis->u16HdrRemain;
3990 pThis->u16HdrRemain = 0;
3991 /* Save partial checksum and flags */
3992 pThis->u32SavedCsum = pTcpHdr->chksum;
3993 pThis->u16SavedFlags = pTcpHdr->hdrlen_flags;
3994 /* Clear FIN and PSH flags now and set them only in the last segment */
3995 pTcpHdr->hdrlen_flags &= ~htons(E1K_TCP_FIN | E1K_TCP_PSH);
3996 }
3997 else
3998 {
3999 /* Still not */
4000 pThis->u16HdrRemain -= u16Len;
4001 E1kLog3(("%s e1kFallbackAddSegment: Header is still incomplete, 0x%x bytes remain.\n",
4002 pThis->szPrf, pThis->u16HdrRemain));
4003 return;
4004 }
4005 }
4006
4007 pThis->u32PayRemain -= u16Len;
4008
4009 if (fSend)
4010 {
4011 /* Leave ethernet header intact */
4012 /* IP Total Length = payload + headers - ethernet header */
4013 pIpHdr->total_len = htons(pThis->u16TxPktLen - pThis->contextTSE.ip.u8CSS);
4014 E1kLog3(("%s e1kFallbackAddSegment: End of packet, pIpHdr->total_len=%x\n",
4015 pThis->szPrf, ntohs(pIpHdr->total_len)));
4016 /* Update IP Checksum */
4017 pIpHdr->chksum = 0;
4018 e1kInsertChecksum(pThis, pThis->aTxPacketFallback, pThis->u16TxPktLen,
4019 pThis->contextTSE.ip.u8CSO,
4020 pThis->contextTSE.ip.u8CSS,
4021 pThis->contextTSE.ip.u16CSE);
4022
4023 /* Update TCP flags */
4024 /* Restore original FIN and PSH flags for the last segment */
4025 if (pThis->u32PayRemain == 0)
4026 {
4027 pTcpHdr->hdrlen_flags = pThis->u16SavedFlags;
4028 E1K_INC_CNT32(TSCTC);
4029 }
4030 /* Add TCP length to partial pseudo header sum */
4031 uint32_t csum = pThis->u32SavedCsum
4032 + htons(pThis->u16TxPktLen - pThis->contextTSE.tu.u8CSS);
4033 while (csum >> 16)
4034 csum = (csum >> 16) + (csum & 0xFFFF);
4035 pTcpHdr->chksum = csum;
4036 /* Compute final checksum */
4037 e1kInsertChecksum(pThis, pThis->aTxPacketFallback, pThis->u16TxPktLen,
4038 pThis->contextTSE.tu.u8CSO,
4039 pThis->contextTSE.tu.u8CSS,
4040 pThis->contextTSE.tu.u16CSE);
4041
4042 /*
4043 * Transmit it. If we've use the SG already, allocate a new one before
4044 * we copy of the data.
4045 */
4046 if (!pThis->CTX_SUFF(pTxSg))
4047 e1kXmitAllocBuf(pThis, pThis->u16TxPktLen + (pThis->fVTag ? 4 : 0), true /*fExactSize*/, false /*fGso*/);
4048 if (pThis->CTX_SUFF(pTxSg))
4049 {
4050 Assert(pThis->u16TxPktLen <= pThis->CTX_SUFF(pTxSg)->cbAvailable);
4051 Assert(pThis->CTX_SUFF(pTxSg)->cSegs == 1);
4052 if (pThis->CTX_SUFF(pTxSg)->aSegs[0].pvSeg != pThis->aTxPacketFallback)
4053 memcpy(pThis->CTX_SUFF(pTxSg)->aSegs[0].pvSeg, pThis->aTxPacketFallback, pThis->u16TxPktLen);
4054 pThis->CTX_SUFF(pTxSg)->cbUsed = pThis->u16TxPktLen;
4055 pThis->CTX_SUFF(pTxSg)->aSegs[0].cbSeg = pThis->u16TxPktLen;
4056 }
4057 e1kTransmitFrame(pThis, fOnWorkerThread);
4058
4059 /* Update Sequence Number */
4060 pTcpHdr->seqno = htonl(ntohl(pTcpHdr->seqno) + pThis->u16TxPktLen
4061 - pThis->contextTSE.dw3.u8HDRLEN);
4062 /* Increment IP identification */
4063 pIpHdr->ident = htons(ntohs(pIpHdr->ident) + 1);
4064 }
4065}
4066#else /* E1K_WITH_TXD_CACHE */
4067static int e1kFallbackAddSegment(PE1KSTATE pThis, RTGCPHYS PhysAddr, uint16_t u16Len, bool fSend, bool fOnWorkerThread)
4068{
4069 int rc = VINF_SUCCESS;
4070 /* TCP header being transmitted */
4071 struct E1kTcpHeader *pTcpHdr = (struct E1kTcpHeader *)
4072 (pThis->aTxPacketFallback + pThis->contextTSE.tu.u8CSS);
4073 /* IP header being transmitted */
4074 struct E1kIpHeader *pIpHdr = (struct E1kIpHeader *)
4075 (pThis->aTxPacketFallback + pThis->contextTSE.ip.u8CSS);
4076
4077 E1kLog3(("%s e1kFallbackAddSegment: Length=%x, remaining payload=%x, header=%x, send=%RTbool\n",
4078 pThis->szPrf, u16Len, pThis->u32PayRemain, pThis->u16HdrRemain, fSend));
4079 Assert(pThis->u32PayRemain + pThis->u16HdrRemain > 0);
4080
4081 PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns), PhysAddr,
4082 pThis->aTxPacketFallback + pThis->u16TxPktLen, u16Len);
4083 E1kLog3(("%s Dump of the segment:\n"
4084 "%.*Rhxd\n"
4085 "%s --- End of dump ---\n",
4086 pThis->szPrf, u16Len, pThis->aTxPacketFallback + pThis->u16TxPktLen, pThis->szPrf));
4087 pThis->u16TxPktLen += u16Len;
4088 E1kLog3(("%s e1kFallbackAddSegment: pThis->u16TxPktLen=%x\n",
4089 pThis->szPrf, pThis->u16TxPktLen));
4090 if (pThis->u16HdrRemain > 0)
4091 {
4092 /* The header was not complete, check if it is now */
4093 if (u16Len >= pThis->u16HdrRemain)
4094 {
4095 /* The rest is payload */
4096 u16Len -= pThis->u16HdrRemain;
4097 pThis->u16HdrRemain = 0;
4098 /* Save partial checksum and flags */
4099 pThis->u32SavedCsum = pTcpHdr->chksum;
4100 pThis->u16SavedFlags = pTcpHdr->hdrlen_flags;
4101 /* Clear FIN and PSH flags now and set them only in the last segment */
4102 pTcpHdr->hdrlen_flags &= ~htons(E1K_TCP_FIN | E1K_TCP_PSH);
4103 }
4104 else
4105 {
4106 /* Still not */
4107 pThis->u16HdrRemain -= u16Len;
4108 E1kLog3(("%s e1kFallbackAddSegment: Header is still incomplete, 0x%x bytes remain.\n",
4109 pThis->szPrf, pThis->u16HdrRemain));
4110 return rc;
4111 }
4112 }
4113
4114 pThis->u32PayRemain -= u16Len;
4115
4116 if (fSend)
4117 {
4118 /* Leave ethernet header intact */
4119 /* IP Total Length = payload + headers - ethernet header */
4120 pIpHdr->total_len = htons(pThis->u16TxPktLen - pThis->contextTSE.ip.u8CSS);
4121 E1kLog3(("%s e1kFallbackAddSegment: End of packet, pIpHdr->total_len=%x\n",
4122 pThis->szPrf, ntohs(pIpHdr->total_len)));
4123 /* Update IP Checksum */
4124 pIpHdr->chksum = 0;
4125 e1kInsertChecksum(pThis, pThis->aTxPacketFallback, pThis->u16TxPktLen,
4126 pThis->contextTSE.ip.u8CSO,
4127 pThis->contextTSE.ip.u8CSS,
4128 pThis->contextTSE.ip.u16CSE);
4129
4130 /* Update TCP flags */
4131 /* Restore original FIN and PSH flags for the last segment */
4132 if (pThis->u32PayRemain == 0)
4133 {
4134 pTcpHdr->hdrlen_flags = pThis->u16SavedFlags;
4135 E1K_INC_CNT32(TSCTC);
4136 }
4137 /* Add TCP length to partial pseudo header sum */
4138 uint32_t csum = pThis->u32SavedCsum
4139 + htons(pThis->u16TxPktLen - pThis->contextTSE.tu.u8CSS);
4140 while (csum >> 16)
4141 csum = (csum >> 16) + (csum & 0xFFFF);
4142 pTcpHdr->chksum = csum;
4143 /* Compute final checksum */
4144 e1kInsertChecksum(pThis, pThis->aTxPacketFallback, pThis->u16TxPktLen,
4145 pThis->contextTSE.tu.u8CSO,
4146 pThis->contextTSE.tu.u8CSS,
4147 pThis->contextTSE.tu.u16CSE);
4148
4149 /*
4150 * Transmit it.
4151 */
4152 if (pThis->CTX_SUFF(pTxSg))
4153 {
4154 Assert(pThis->u16TxPktLen <= pThis->CTX_SUFF(pTxSg)->cbAvailable);
4155 Assert(pThis->CTX_SUFF(pTxSg)->cSegs == 1);
4156 if (pThis->CTX_SUFF(pTxSg)->aSegs[0].pvSeg != pThis->aTxPacketFallback)
4157 memcpy(pThis->CTX_SUFF(pTxSg)->aSegs[0].pvSeg, pThis->aTxPacketFallback, pThis->u16TxPktLen);
4158 pThis->CTX_SUFF(pTxSg)->cbUsed = pThis->u16TxPktLen;
4159 pThis->CTX_SUFF(pTxSg)->aSegs[0].cbSeg = pThis->u16TxPktLen;
4160 }
4161 e1kTransmitFrame(pThis, fOnWorkerThread);
4162
4163 /* Update Sequence Number */
4164 pTcpHdr->seqno = htonl(ntohl(pTcpHdr->seqno) + pThis->u16TxPktLen
4165 - pThis->contextTSE.dw3.u8HDRLEN);
4166 /* Increment IP identification */
4167 pIpHdr->ident = htons(ntohs(pIpHdr->ident) + 1);
4168
4169 /* Allocate new buffer for the next segment. */
4170 if (pThis->u32PayRemain)
4171 {
4172 pThis->cbTxAlloc = RT_MIN(pThis->u32PayRemain,
4173 pThis->contextTSE.dw3.u16MSS)
4174 + pThis->contextTSE.dw3.u8HDRLEN
4175 + (pThis->fVTag ? 4 : 0);
4176 rc = e1kXmitAllocBuf(pThis, false /* fGSO */);
4177 }
4178 }
4179
4180 return rc;
4181}
4182#endif /* E1K_WITH_TXD_CACHE */
4183
4184#ifndef E1K_WITH_TXD_CACHE
4185/**
4186 * TCP segmentation offloading fallback: Add descriptor's buffer to transmit
4187 * frame.
4188 *
4189 * We construct the frame in the fallback buffer first and the copy it to the SG
4190 * buffer before passing it down to the network driver code.
4191 *
4192 * @returns true if the frame should be transmitted, false if not.
4193 *
4194 * @param pThis The device state structure.
4195 * @param pDesc Pointer to the descriptor to transmit.
4196 * @param cbFragment Length of descriptor's buffer.
4197 * @param fOnWorkerThread Whether we're on a worker thread or an EMT.
4198 * @thread E1000_TX
4199 */
4200static bool e1kFallbackAddToFrame(PE1KSTATE pThis, E1KTXDESC* pDesc, uint32_t cbFragment, bool fOnWorkerThread)
4201{
4202 PPDMSCATTERGATHER pTxSg = pThis->CTX_SUFF(pTxSg);
4203 Assert(e1kGetDescType(pDesc) == E1K_DTYP_DATA);
4204 Assert(pDesc->data.cmd.fTSE);
4205 Assert(!e1kXmitIsGsoBuf(pTxSg));
4206
4207 uint16_t u16MaxPktLen = pThis->contextTSE.dw3.u8HDRLEN + pThis->contextTSE.dw3.u16MSS;
4208 Assert(u16MaxPktLen != 0);
4209 Assert(u16MaxPktLen < E1K_MAX_TX_PKT_SIZE);
4210
4211 /*
4212 * Carve out segments.
4213 */
4214 do
4215 {
4216 /* Calculate how many bytes we have left in this TCP segment */
4217 uint32_t cb = u16MaxPktLen - pThis->u16TxPktLen;
4218 if (cb > cbFragment)
4219 {
4220 /* This descriptor fits completely into current segment */
4221 cb = cbFragment;
4222 e1kFallbackAddSegment(pThis, pDesc->data.u64BufAddr, cb, pDesc->data.cmd.fEOP /*fSend*/, fOnWorkerThread);
4223 }
4224 else
4225 {
4226 e1kFallbackAddSegment(pThis, pDesc->data.u64BufAddr, cb, true /*fSend*/, fOnWorkerThread);
4227 /*
4228 * Rewind the packet tail pointer to the beginning of payload,
4229 * so we continue writing right beyond the header.
4230 */
4231 pThis->u16TxPktLen = pThis->contextTSE.dw3.u8HDRLEN;
4232 }
4233
4234 pDesc->data.u64BufAddr += cb;
4235 cbFragment -= cb;
4236 } while (cbFragment > 0);
4237
4238 if (pDesc->data.cmd.fEOP)
4239 {
4240 /* End of packet, next segment will contain header. */
4241 if (pThis->u32PayRemain != 0)
4242 E1K_INC_CNT32(TSCTFC);
4243 pThis->u16TxPktLen = 0;
4244 e1kXmitFreeBuf(pThis);
4245 }
4246
4247 return false;
4248}
4249#else /* E1K_WITH_TXD_CACHE */
4250/**
4251 * TCP segmentation offloading fallback: Add descriptor's buffer to transmit
4252 * frame.
4253 *
4254 * We construct the frame in the fallback buffer first and the copy it to the SG
4255 * buffer before passing it down to the network driver code.
4256 *
4257 * @returns error code
4258 *
4259 * @param pThis The device state structure.
4260 * @param pDesc Pointer to the descriptor to transmit.
4261 * @param cbFragment Length of descriptor's buffer.
4262 * @param fOnWorkerThread Whether we're on a worker thread or an EMT.
4263 * @thread E1000_TX
4264 */
4265static int e1kFallbackAddToFrame(PE1KSTATE pThis, E1KTXDESC* pDesc, bool fOnWorkerThread)
4266{
4267 int rc = VINF_SUCCESS;
4268 PPDMSCATTERGATHER pTxSg = pThis->CTX_SUFF(pTxSg);
4269 Assert(e1kGetDescType(pDesc) == E1K_DTYP_DATA);
4270 Assert(pDesc->data.cmd.fTSE);
4271 Assert(!e1kXmitIsGsoBuf(pTxSg));
4272
4273 uint16_t u16MaxPktLen = pThis->contextTSE.dw3.u8HDRLEN + pThis->contextTSE.dw3.u16MSS;
4274 Assert(u16MaxPktLen != 0);
4275 Assert(u16MaxPktLen < E1K_MAX_TX_PKT_SIZE);
4276
4277 /*
4278 * Carve out segments.
4279 */
4280 do
4281 {
4282 /* Calculate how many bytes we have left in this TCP segment */
4283 uint32_t cb = u16MaxPktLen - pThis->u16TxPktLen;
4284 if (cb > pDesc->data.cmd.u20DTALEN)
4285 {
4286 /* This descriptor fits completely into current segment */
4287 cb = pDesc->data.cmd.u20DTALEN;
4288 rc = e1kFallbackAddSegment(pThis, pDesc->data.u64BufAddr, cb, pDesc->data.cmd.fEOP /*fSend*/, fOnWorkerThread);
4289 }
4290 else
4291 {
4292 rc = e1kFallbackAddSegment(pThis, pDesc->data.u64BufAddr, cb, true /*fSend*/, fOnWorkerThread);
4293 /*
4294 * Rewind the packet tail pointer to the beginning of payload,
4295 * so we continue writing right beyond the header.
4296 */
4297 pThis->u16TxPktLen = pThis->contextTSE.dw3.u8HDRLEN;
4298 }
4299
4300 pDesc->data.u64BufAddr += cb;
4301 pDesc->data.cmd.u20DTALEN -= cb;
4302 } while (pDesc->data.cmd.u20DTALEN > 0 && RT_SUCCESS(rc));
4303
4304 if (pDesc->data.cmd.fEOP)
4305 {
4306 /* End of packet, next segment will contain header. */
4307 if (pThis->u32PayRemain != 0)
4308 E1K_INC_CNT32(TSCTFC);
4309 pThis->u16TxPktLen = 0;
4310 e1kXmitFreeBuf(pThis);
4311 }
4312
4313 return false;
4314}
4315#endif /* E1K_WITH_TXD_CACHE */
4316
4317
4318/**
4319 * Add descriptor's buffer to transmit frame.
4320 *
4321 * This deals with GSO and normal frames, e1kFallbackAddToFrame deals with the
4322 * TSE frames we cannot handle as GSO.
4323 *
4324 * @returns true on success, false on failure.
4325 *
4326 * @param pThis The device state structure.
4327 * @param PhysAddr The physical address of the descriptor buffer.
4328 * @param cbFragment Length of descriptor's buffer.
4329 * @thread E1000_TX
4330 */
4331static bool e1kAddToFrame(PE1KSTATE pThis, RTGCPHYS PhysAddr, uint32_t cbFragment)
4332{
4333 PPDMSCATTERGATHER pTxSg = pThis->CTX_SUFF(pTxSg);
4334 bool const fGso = e1kXmitIsGsoBuf(pTxSg);
4335 uint32_t const cbNewPkt = cbFragment + pThis->u16TxPktLen;
4336
4337 if (RT_UNLIKELY( !fGso && cbNewPkt > E1K_MAX_TX_PKT_SIZE ))
4338 {
4339 E1kLog(("%s Transmit packet is too large: %u > %u(max)\n", pThis->szPrf, cbNewPkt, E1K_MAX_TX_PKT_SIZE));
4340 return false;
4341 }
4342 if (RT_UNLIKELY( fGso && cbNewPkt > pTxSg->cbAvailable ))
4343 {
4344 E1kLog(("%s Transmit packet is too large: %u > %u(max)/GSO\n", pThis->szPrf, cbNewPkt, pTxSg->cbAvailable));
4345 return false;
4346 }
4347
4348 if (RT_LIKELY(pTxSg))
4349 {
4350 Assert(pTxSg->cSegs == 1);
4351 Assert(pTxSg->cbUsed == pThis->u16TxPktLen);
4352
4353 PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns), PhysAddr,
4354 (uint8_t *)pTxSg->aSegs[0].pvSeg + pThis->u16TxPktLen, cbFragment);
4355
4356 pTxSg->cbUsed = cbNewPkt;
4357 }
4358 pThis->u16TxPktLen = cbNewPkt;
4359
4360 return true;
4361}
4362
4363
4364/**
4365 * Write the descriptor back to guest memory and notify the guest.
4366 *
4367 * @param pThis The device state structure.
4368 * @param pDesc Pointer to the descriptor have been transmitted.
4369 * @param addr Physical address of the descriptor in guest memory.
4370 * @thread E1000_TX
4371 */
4372static void e1kDescReport(PE1KSTATE pThis, E1KTXDESC* pDesc, RTGCPHYS addr)
4373{
4374 /*
4375 * We fake descriptor write-back bursting. Descriptors are written back as they are
4376 * processed.
4377 */
4378 /* Let's pretend we process descriptors. Write back with DD set. */
4379 /*
4380 * Prior to r71586 we tried to accomodate the case when write-back bursts
4381 * are enabled without actually implementing bursting by writing back all
4382 * descriptors, even the ones that do not have RS set. This caused kernel
4383 * panics with Linux SMP kernels, as the e1000 driver tried to free up skb
4384 * associated with written back descriptor if it happened to be a context
4385 * descriptor since context descriptors do not have skb associated to them.
4386 * Starting from r71586 we write back only the descriptors with RS set,
4387 * which is a little bit different from what the real hardware does in
4388 * case there is a chain of data descritors where some of them have RS set
4389 * and others do not. It is very uncommon scenario imho.
4390 * We need to check RPS as well since some legacy drivers use it instead of
4391 * RS even with newer cards.
4392 */
4393 if (pDesc->legacy.cmd.fRS || pDesc->legacy.cmd.fRPS)
4394 {
4395 pDesc->legacy.dw3.fDD = 1; /* Descriptor Done */
4396 e1kWriteBackDesc(pThis, pDesc, addr);
4397 if (pDesc->legacy.cmd.fEOP)
4398 {
4399#ifdef E1K_USE_TX_TIMERS
4400 if (pDesc->legacy.cmd.fIDE)
4401 {
4402 E1K_INC_ISTAT_CNT(pThis->uStatTxIDE);
4403 //if (pThis->fIntRaised)
4404 //{
4405 // /* Interrupt is already pending, no need for timers */
4406 // ICR |= ICR_TXDW;
4407 //}
4408 //else {
4409 /* Arm the timer to fire in TIVD usec (discard .024) */
4410 e1kArmTimer(pThis, pThis->CTX_SUFF(pTIDTimer), TIDV);
4411# ifndef E1K_NO_TAD
4412 /* If absolute timer delay is enabled and the timer is not running yet, arm it. */
4413 E1kLog2(("%s Checking if TAD timer is running\n",
4414 pThis->szPrf));
4415 if (TADV != 0 && !TMTimerIsActive(pThis->CTX_SUFF(pTADTimer)))
4416 e1kArmTimer(pThis, pThis->CTX_SUFF(pTADTimer), TADV);
4417# endif /* E1K_NO_TAD */
4418 }
4419 else
4420 {
4421 E1kLog2(("%s No IDE set, cancel TAD timer and raise interrupt\n",
4422 pThis->szPrf));
4423# ifndef E1K_NO_TAD
4424 /* Cancel both timers if armed and fire immediately. */
4425 e1kCancelTimer(pThis, pThis->CTX_SUFF(pTADTimer));
4426# endif /* E1K_NO_TAD */
4427#endif /* E1K_USE_TX_TIMERS */
4428 E1K_INC_ISTAT_CNT(pThis->uStatIntTx);
4429 e1kRaiseInterrupt(pThis, VERR_SEM_BUSY, ICR_TXDW);
4430#ifdef E1K_USE_TX_TIMERS
4431 }
4432#endif /* E1K_USE_TX_TIMERS */
4433 }
4434 }
4435 else
4436 {
4437 E1K_INC_ISTAT_CNT(pThis->uStatTxNoRS);
4438 }
4439}
4440
4441#ifndef E1K_WITH_TXD_CACHE
4442
4443/**
4444 * Process Transmit Descriptor.
4445 *
4446 * E1000 supports three types of transmit descriptors:
4447 * - legacy data descriptors of older format (context-less).
4448 * - data the same as legacy but providing new offloading capabilities.
4449 * - context sets up the context for following data descriptors.
4450 *
4451 * @param pThis The device state structure.
4452 * @param pDesc Pointer to descriptor union.
4453 * @param addr Physical address of descriptor in guest memory.
4454 * @param fOnWorkerThread Whether we're on a worker thread or an EMT.
4455 * @thread E1000_TX
4456 */
4457static int e1kXmitDesc(PE1KSTATE pThis, E1KTXDESC* pDesc, RTGCPHYS addr, bool fOnWorkerThread)
4458{
4459 int rc = VINF_SUCCESS;
4460 uint32_t cbVTag = 0;
4461
4462 e1kPrintTDesc(pThis, pDesc, "vvv");
4463
4464#ifdef E1K_USE_TX_TIMERS
4465 e1kCancelTimer(pThis, pThis->CTX_SUFF(pTIDTimer));
4466#endif /* E1K_USE_TX_TIMERS */
4467
4468 switch (e1kGetDescType(pDesc))
4469 {
4470 case E1K_DTYP_CONTEXT:
4471 if (pDesc->context.dw2.fTSE)
4472 {
4473 pThis->contextTSE = pDesc->context;
4474 pThis->u32PayRemain = pDesc->context.dw2.u20PAYLEN;
4475 pThis->u16HdrRemain = pDesc->context.dw3.u8HDRLEN;
4476 e1kSetupGsoCtx(&pThis->GsoCtx, &pDesc->context);
4477 STAM_COUNTER_INC(&pThis->StatTxDescCtxTSE);
4478 }
4479 else
4480 {
4481 pThis->contextNormal = pDesc->context;
4482 STAM_COUNTER_INC(&pThis->StatTxDescCtxNormal);
4483 }
4484 E1kLog2(("%s %s context updated: IP CSS=%02X, IP CSO=%02X, IP CSE=%04X"
4485 ", TU CSS=%02X, TU CSO=%02X, TU CSE=%04X\n", pThis->szPrf,
4486 pDesc->context.dw2.fTSE ? "TSE" : "Normal",
4487 pDesc->context.ip.u8CSS,
4488 pDesc->context.ip.u8CSO,
4489 pDesc->context.ip.u16CSE,
4490 pDesc->context.tu.u8CSS,
4491 pDesc->context.tu.u8CSO,
4492 pDesc->context.tu.u16CSE));
4493 E1K_INC_ISTAT_CNT(pThis->uStatDescCtx);
4494 e1kDescReport(pThis, pDesc, addr);
4495 break;
4496
4497 case E1K_DTYP_DATA:
4498 {
4499 if (pDesc->data.cmd.u20DTALEN == 0 || pDesc->data.u64BufAddr == 0)
4500 {
4501 E1kLog2(("% Empty data descriptor, skipped.\n", pThis->szPrf));
4502 /** @todo Same as legacy when !TSE. See below. */
4503 break;
4504 }
4505 STAM_COUNTER_INC(pDesc->data.cmd.fTSE?
4506 &pThis->StatTxDescTSEData:
4507 &pThis->StatTxDescData);
4508 STAM_PROFILE_ADV_START(&pThis->CTX_SUFF_Z(StatTransmit), a);
4509 E1K_INC_ISTAT_CNT(pThis->uStatDescDat);
4510
4511 /*
4512 * The last descriptor of non-TSE packet must contain VLE flag.
4513 * TSE packets have VLE flag in the first descriptor. The later
4514 * case is taken care of a bit later when cbVTag gets assigned.
4515 *
4516 * 1) pDesc->data.cmd.fEOP && !pDesc->data.cmd.fTSE
4517 */
4518 if (pDesc->data.cmd.fEOP && !pDesc->data.cmd.fTSE)
4519 {
4520 pThis->fVTag = pDesc->data.cmd.fVLE;
4521 pThis->u16VTagTCI = pDesc->data.dw3.u16Special;
4522 }
4523 /*
4524 * First fragment: Allocate new buffer and save the IXSM and TXSM
4525 * packet options as these are only valid in the first fragment.
4526 */
4527 if (pThis->u16TxPktLen == 0)
4528 {
4529 pThis->fIPcsum = pDesc->data.dw3.fIXSM;
4530 pThis->fTCPcsum = pDesc->data.dw3.fTXSM;
4531 E1kLog2(("%s Saving checksum flags:%s%s; \n", pThis->szPrf,
4532 pThis->fIPcsum ? " IP" : "",
4533 pThis->fTCPcsum ? " TCP/UDP" : ""));
4534 if (pDesc->data.cmd.fTSE)
4535 {
4536 /* 2) pDesc->data.cmd.fTSE && pThis->u16TxPktLen == 0 */
4537 pThis->fVTag = pDesc->data.cmd.fVLE;
4538 pThis->u16VTagTCI = pDesc->data.dw3.u16Special;
4539 cbVTag = pThis->fVTag ? 4 : 0;
4540 }
4541 else if (pDesc->data.cmd.fEOP)
4542 cbVTag = pDesc->data.cmd.fVLE ? 4 : 0;
4543 else
4544 cbVTag = 4;
4545 E1kLog3(("%s About to allocate TX buffer: cbVTag=%u\n", pThis->szPrf, cbVTag));
4546 if (e1kCanDoGso(pThis, &pThis->GsoCtx, &pDesc->data, &pThis->contextTSE))
4547 rc = e1kXmitAllocBuf(pThis, pThis->contextTSE.dw2.u20PAYLEN + pThis->contextTSE.dw3.u8HDRLEN + cbVTag,
4548 true /*fExactSize*/, true /*fGso*/);
4549 else if (pDesc->data.cmd.fTSE)
4550 rc = e1kXmitAllocBuf(pThis, pThis->contextTSE.dw3.u16MSS + pThis->contextTSE.dw3.u8HDRLEN + cbVTag,
4551 pDesc->data.cmd.fTSE /*fExactSize*/, false /*fGso*/);
4552 else
4553 rc = e1kXmitAllocBuf(pThis, pDesc->data.cmd.u20DTALEN + cbVTag,
4554 pDesc->data.cmd.fEOP /*fExactSize*/, false /*fGso*/);
4555
4556 /**
4557 * @todo: Perhaps it is not that simple for GSO packets! We may
4558 * need to unwind some changes.
4559 */
4560 if (RT_FAILURE(rc))
4561 {
4562 STAM_PROFILE_ADV_STOP(&pThis->CTX_SUFF_Z(StatTransmit), a);
4563 break;
4564 }
4565 /** @todo Is there any way to indicating errors other than collisions? Like
4566 * VERR_NET_DOWN. */
4567 }
4568
4569 /*
4570 * Add the descriptor data to the frame. If the frame is complete,
4571 * transmit it and reset the u16TxPktLen field.
4572 */
4573 if (e1kXmitIsGsoBuf(pThis->CTX_SUFF(pTxSg)))
4574 {
4575 STAM_COUNTER_INC(&pThis->StatTxPathGSO);
4576 bool fRc = e1kAddToFrame(pThis, pDesc->data.u64BufAddr, pDesc->data.cmd.u20DTALEN);
4577 if (pDesc->data.cmd.fEOP)
4578 {
4579 if ( fRc
4580 && pThis->CTX_SUFF(pTxSg)
4581 && pThis->CTX_SUFF(pTxSg)->cbUsed == (size_t)pThis->contextTSE.dw3.u8HDRLEN + pThis->contextTSE.dw2.u20PAYLEN)
4582 {
4583 e1kTransmitFrame(pThis, fOnWorkerThread);
4584 E1K_INC_CNT32(TSCTC);
4585 }
4586 else
4587 {
4588 if (fRc)
4589 E1kLog(("%s bad GSO/TSE %p or %u < %u\n" , pThis->szPrf,
4590 pThis->CTX_SUFF(pTxSg), pThis->CTX_SUFF(pTxSg) ? pThis->CTX_SUFF(pTxSg)->cbUsed : 0,
4591 pThis->contextTSE.dw3.u8HDRLEN + pThis->contextTSE.dw2.u20PAYLEN));
4592 e1kXmitFreeBuf(pThis);
4593 E1K_INC_CNT32(TSCTFC);
4594 }
4595 pThis->u16TxPktLen = 0;
4596 }
4597 }
4598 else if (!pDesc->data.cmd.fTSE)
4599 {
4600 STAM_COUNTER_INC(&pThis->StatTxPathRegular);
4601 bool fRc = e1kAddToFrame(pThis, pDesc->data.u64BufAddr, pDesc->data.cmd.u20DTALEN);
4602 if (pDesc->data.cmd.fEOP)
4603 {
4604 if (fRc && pThis->CTX_SUFF(pTxSg))
4605 {
4606 Assert(pThis->CTX_SUFF(pTxSg)->cSegs == 1);
4607 if (pThis->fIPcsum)
4608 e1kInsertChecksum(pThis, (uint8_t *)pThis->CTX_SUFF(pTxSg)->aSegs[0].pvSeg, pThis->u16TxPktLen,
4609 pThis->contextNormal.ip.u8CSO,
4610 pThis->contextNormal.ip.u8CSS,
4611 pThis->contextNormal.ip.u16CSE);
4612 if (pThis->fTCPcsum)
4613 e1kInsertChecksum(pThis, (uint8_t *)pThis->CTX_SUFF(pTxSg)->aSegs[0].pvSeg, pThis->u16TxPktLen,
4614 pThis->contextNormal.tu.u8CSO,
4615 pThis->contextNormal.tu.u8CSS,
4616 pThis->contextNormal.tu.u16CSE);
4617 e1kTransmitFrame(pThis, fOnWorkerThread);
4618 }
4619 else
4620 e1kXmitFreeBuf(pThis);
4621 pThis->u16TxPktLen = 0;
4622 }
4623 }
4624 else
4625 {
4626 STAM_COUNTER_INC(&pThis->StatTxPathFallback);
4627 e1kFallbackAddToFrame(pThis, pDesc, pDesc->data.cmd.u20DTALEN, fOnWorkerThread);
4628 }
4629
4630 e1kDescReport(pThis, pDesc, addr);
4631 STAM_PROFILE_ADV_STOP(&pThis->CTX_SUFF_Z(StatTransmit), a);
4632 break;
4633 }
4634
4635 case E1K_DTYP_LEGACY:
4636 if (pDesc->legacy.cmd.u16Length == 0 || pDesc->legacy.u64BufAddr == 0)
4637 {
4638 E1kLog(("%s Empty legacy descriptor, skipped.\n", pThis->szPrf));
4639 /** @todo 3.3.3, Length/Buffer Address: RS set -> write DD when processing. */
4640 break;
4641 }
4642 STAM_COUNTER_INC(&pThis->StatTxDescLegacy);
4643 STAM_PROFILE_ADV_START(&pThis->CTX_SUFF_Z(StatTransmit), a);
4644
4645 /* First fragment: allocate new buffer. */
4646 if (pThis->u16TxPktLen == 0)
4647 {
4648 if (pDesc->legacy.cmd.fEOP)
4649 cbVTag = pDesc->legacy.cmd.fVLE ? 4 : 0;
4650 else
4651 cbVTag = 4;
4652 E1kLog3(("%s About to allocate TX buffer: cbVTag=%u\n", pThis->szPrf, cbVTag));
4653 /** @todo reset status bits? */
4654 rc = e1kXmitAllocBuf(pThis, pDesc->legacy.cmd.u16Length + cbVTag, pDesc->legacy.cmd.fEOP, false /*fGso*/);
4655 if (RT_FAILURE(rc))
4656 {
4657 STAM_PROFILE_ADV_STOP(&pThis->CTX_SUFF_Z(StatTransmit), a);
4658 break;
4659 }
4660
4661 /** @todo Is there any way to indicating errors other than collisions? Like
4662 * VERR_NET_DOWN. */
4663 }
4664
4665 /* Add fragment to frame. */
4666 if (e1kAddToFrame(pThis, pDesc->data.u64BufAddr, pDesc->legacy.cmd.u16Length))
4667 {
4668 E1K_INC_ISTAT_CNT(pThis->uStatDescLeg);
4669
4670 /* Last fragment: Transmit and reset the packet storage counter. */
4671 if (pDesc->legacy.cmd.fEOP)
4672 {
4673 pThis->fVTag = pDesc->legacy.cmd.fVLE;
4674 pThis->u16VTagTCI = pDesc->legacy.dw3.u16Special;
4675 /** @todo Offload processing goes here. */
4676 e1kTransmitFrame(pThis, fOnWorkerThread);
4677 pThis->u16TxPktLen = 0;
4678 }
4679 }
4680 /* Last fragment + failure: free the buffer and reset the storage counter. */
4681 else if (pDesc->legacy.cmd.fEOP)
4682 {
4683 e1kXmitFreeBuf(pThis);
4684 pThis->u16TxPktLen = 0;
4685 }
4686
4687 e1kDescReport(pThis, pDesc, addr);
4688 STAM_PROFILE_ADV_STOP(&pThis->CTX_SUFF_Z(StatTransmit), a);
4689 break;
4690
4691 default:
4692 E1kLog(("%s ERROR Unsupported transmit descriptor type: 0x%04x\n",
4693 pThis->szPrf, e1kGetDescType(pDesc)));
4694 break;
4695 }
4696
4697 return rc;
4698}
4699
4700#else /* E1K_WITH_TXD_CACHE */
4701
4702/**
4703 * Process Transmit Descriptor.
4704 *
4705 * E1000 supports three types of transmit descriptors:
4706 * - legacy data descriptors of older format (context-less).
4707 * - data the same as legacy but providing new offloading capabilities.
4708 * - context sets up the context for following data descriptors.
4709 *
4710 * @param pThis The device state structure.
4711 * @param pDesc Pointer to descriptor union.
4712 * @param addr Physical address of descriptor in guest memory.
4713 * @param fOnWorkerThread Whether we're on a worker thread or an EMT.
4714 * @param cbPacketSize Size of the packet as previously computed.
4715 * @thread E1000_TX
4716 */
4717static int e1kXmitDesc(PE1KSTATE pThis, E1KTXDESC* pDesc, RTGCPHYS addr,
4718 bool fOnWorkerThread)
4719{
4720 int rc = VINF_SUCCESS;
4721 uint32_t cbVTag = 0;
4722
4723 e1kPrintTDesc(pThis, pDesc, "vvv");
4724
4725#ifdef E1K_USE_TX_TIMERS
4726 e1kCancelTimer(pThis, pThis->CTX_SUFF(pTIDTimer));
4727#endif /* E1K_USE_TX_TIMERS */
4728
4729 switch (e1kGetDescType(pDesc))
4730 {
4731 case E1K_DTYP_CONTEXT:
4732 /* The caller have already updated the context */
4733 E1K_INC_ISTAT_CNT(pThis->uStatDescCtx);
4734 e1kDescReport(pThis, pDesc, addr);
4735 break;
4736
4737 case E1K_DTYP_DATA:
4738 {
4739 STAM_COUNTER_INC(pDesc->data.cmd.fTSE?
4740 &pThis->StatTxDescTSEData:
4741 &pThis->StatTxDescData);
4742 E1K_INC_ISTAT_CNT(pThis->uStatDescDat);
4743 STAM_PROFILE_ADV_START(&pThis->CTX_SUFF_Z(StatTransmit), a);
4744 if (pDesc->data.cmd.u20DTALEN == 0 || pDesc->data.u64BufAddr == 0)
4745 {
4746 E1kLog2(("% Empty data descriptor, skipped.\n", pThis->szPrf));
4747 }
4748 else
4749 {
4750 /*
4751 * Add the descriptor data to the frame. If the frame is complete,
4752 * transmit it and reset the u16TxPktLen field.
4753 */
4754 if (e1kXmitIsGsoBuf(pThis->CTX_SUFF(pTxSg)))
4755 {
4756 STAM_COUNTER_INC(&pThis->StatTxPathGSO);
4757 bool fRc = e1kAddToFrame(pThis, pDesc->data.u64BufAddr, pDesc->data.cmd.u20DTALEN);
4758 if (pDesc->data.cmd.fEOP)
4759 {
4760 if ( fRc
4761 && pThis->CTX_SUFF(pTxSg)
4762 && pThis->CTX_SUFF(pTxSg)->cbUsed == (size_t)pThis->contextTSE.dw3.u8HDRLEN + pThis->contextTSE.dw2.u20PAYLEN)
4763 {
4764 e1kTransmitFrame(pThis, fOnWorkerThread);
4765 E1K_INC_CNT32(TSCTC);
4766 }
4767 else
4768 {
4769 if (fRc)
4770 E1kLog(("%s bad GSO/TSE %p or %u < %u\n" , pThis->szPrf,
4771 pThis->CTX_SUFF(pTxSg), pThis->CTX_SUFF(pTxSg) ? pThis->CTX_SUFF(pTxSg)->cbUsed : 0,
4772 pThis->contextTSE.dw3.u8HDRLEN + pThis->contextTSE.dw2.u20PAYLEN));
4773 e1kXmitFreeBuf(pThis);
4774 E1K_INC_CNT32(TSCTFC);
4775 }
4776 pThis->u16TxPktLen = 0;
4777 }
4778 }
4779 else if (!pDesc->data.cmd.fTSE)
4780 {
4781 STAM_COUNTER_INC(&pThis->StatTxPathRegular);
4782 bool fRc = e1kAddToFrame(pThis, pDesc->data.u64BufAddr, pDesc->data.cmd.u20DTALEN);
4783 if (pDesc->data.cmd.fEOP)
4784 {
4785 if (fRc && pThis->CTX_SUFF(pTxSg))
4786 {
4787 Assert(pThis->CTX_SUFF(pTxSg)->cSegs == 1);
4788 if (pThis->fIPcsum)
4789 e1kInsertChecksum(pThis, (uint8_t *)pThis->CTX_SUFF(pTxSg)->aSegs[0].pvSeg, pThis->u16TxPktLen,
4790 pThis->contextNormal.ip.u8CSO,
4791 pThis->contextNormal.ip.u8CSS,
4792 pThis->contextNormal.ip.u16CSE);
4793 if (pThis->fTCPcsum)
4794 e1kInsertChecksum(pThis, (uint8_t *)pThis->CTX_SUFF(pTxSg)->aSegs[0].pvSeg, pThis->u16TxPktLen,
4795 pThis->contextNormal.tu.u8CSO,
4796 pThis->contextNormal.tu.u8CSS,
4797 pThis->contextNormal.tu.u16CSE);
4798 e1kTransmitFrame(pThis, fOnWorkerThread);
4799 }
4800 else
4801 e1kXmitFreeBuf(pThis);
4802 pThis->u16TxPktLen = 0;
4803 }
4804 }
4805 else
4806 {
4807 STAM_COUNTER_INC(&pThis->StatTxPathFallback);
4808 rc = e1kFallbackAddToFrame(pThis, pDesc, fOnWorkerThread);
4809 }
4810 }
4811 e1kDescReport(pThis, pDesc, addr);
4812 STAM_PROFILE_ADV_STOP(&pThis->CTX_SUFF_Z(StatTransmit), a);
4813 break;
4814 }
4815
4816 case E1K_DTYP_LEGACY:
4817 STAM_COUNTER_INC(&pThis->StatTxDescLegacy);
4818 STAM_PROFILE_ADV_START(&pThis->CTX_SUFF_Z(StatTransmit), a);
4819 if (pDesc->legacy.cmd.u16Length == 0 || pDesc->legacy.u64BufAddr == 0)
4820 {
4821 E1kLog(("%s Empty legacy descriptor, skipped.\n", pThis->szPrf));
4822 }
4823 else
4824 {
4825 /* Add fragment to frame. */
4826 if (e1kAddToFrame(pThis, pDesc->data.u64BufAddr, pDesc->legacy.cmd.u16Length))
4827 {
4828 E1K_INC_ISTAT_CNT(pThis->uStatDescLeg);
4829
4830 /* Last fragment: Transmit and reset the packet storage counter. */
4831 if (pDesc->legacy.cmd.fEOP)
4832 {
4833 if (pDesc->legacy.cmd.fIC)
4834 {
4835 e1kInsertChecksum(pThis,
4836 (uint8_t *)pThis->CTX_SUFF(pTxSg)->aSegs[0].pvSeg,
4837 pThis->u16TxPktLen,
4838 pDesc->legacy.cmd.u8CSO,
4839 pDesc->legacy.dw3.u8CSS,
4840 0);
4841 }
4842 e1kTransmitFrame(pThis, fOnWorkerThread);
4843 pThis->u16TxPktLen = 0;
4844 }
4845 }
4846 /* Last fragment + failure: free the buffer and reset the storage counter. */
4847 else if (pDesc->legacy.cmd.fEOP)
4848 {
4849 e1kXmitFreeBuf(pThis);
4850 pThis->u16TxPktLen = 0;
4851 }
4852 }
4853 e1kDescReport(pThis, pDesc, addr);
4854 STAM_PROFILE_ADV_STOP(&pThis->CTX_SUFF_Z(StatTransmit), a);
4855 break;
4856
4857 default:
4858 E1kLog(("%s ERROR Unsupported transmit descriptor type: 0x%04x\n",
4859 pThis->szPrf, e1kGetDescType(pDesc)));
4860 break;
4861 }
4862
4863 return rc;
4864}
4865
4866DECLINLINE(void) e1kUpdateTxContext(PE1KSTATE pThis, E1KTXDESC* pDesc)
4867{
4868 if (pDesc->context.dw2.fTSE)
4869 {
4870 pThis->contextTSE = pDesc->context;
4871 pThis->u32PayRemain = pDesc->context.dw2.u20PAYLEN;
4872 pThis->u16HdrRemain = pDesc->context.dw3.u8HDRLEN;
4873 e1kSetupGsoCtx(&pThis->GsoCtx, &pDesc->context);
4874 STAM_COUNTER_INC(&pThis->StatTxDescCtxTSE);
4875 }
4876 else
4877 {
4878 pThis->contextNormal = pDesc->context;
4879 STAM_COUNTER_INC(&pThis->StatTxDescCtxNormal);
4880 }
4881 E1kLog2(("%s %s context updated: IP CSS=%02X, IP CSO=%02X, IP CSE=%04X"
4882 ", TU CSS=%02X, TU CSO=%02X, TU CSE=%04X\n", pThis->szPrf,
4883 pDesc->context.dw2.fTSE ? "TSE" : "Normal",
4884 pDesc->context.ip.u8CSS,
4885 pDesc->context.ip.u8CSO,
4886 pDesc->context.ip.u16CSE,
4887 pDesc->context.tu.u8CSS,
4888 pDesc->context.tu.u8CSO,
4889 pDesc->context.tu.u16CSE));
4890}
4891
4892static bool e1kLocateTxPacket(PE1KSTATE pThis)
4893{
4894 LogFlow(("%s e1kLocateTxPacket: ENTER cbTxAlloc=%d\n",
4895 pThis->szPrf, pThis->cbTxAlloc));
4896 /* Check if we have located the packet already. */
4897 if (pThis->cbTxAlloc)
4898 {
4899 LogFlow(("%s e1kLocateTxPacket: RET true cbTxAlloc=%d\n",
4900 pThis->szPrf, pThis->cbTxAlloc));
4901 return true;
4902 }
4903
4904 bool fTSE = false;
4905 uint32_t cbPacket = 0;
4906
4907 for (int i = pThis->iTxDCurrent; i < pThis->nTxDFetched; ++i)
4908 {
4909 E1KTXDESC *pDesc = &pThis->aTxDescriptors[i];
4910 switch (e1kGetDescType(pDesc))
4911 {
4912 case E1K_DTYP_CONTEXT:
4913 e1kUpdateTxContext(pThis, pDesc);
4914 continue;
4915 case E1K_DTYP_LEGACY:
4916 /* Skip empty descriptors. */
4917 if (!pDesc->legacy.u64BufAddr || !pDesc->legacy.cmd.u16Length)
4918 break;
4919 cbPacket += pDesc->legacy.cmd.u16Length;
4920 pThis->fGSO = false;
4921 break;
4922 case E1K_DTYP_DATA:
4923 /* Skip empty descriptors. */
4924 if (!pDesc->data.u64BufAddr || !pDesc->data.cmd.u20DTALEN)
4925 break;
4926 if (cbPacket == 0)
4927 {
4928 /*
4929 * The first fragment: save IXSM and TXSM options
4930 * as these are only valid in the first fragment.
4931 */
4932 pThis->fIPcsum = pDesc->data.dw3.fIXSM;
4933 pThis->fTCPcsum = pDesc->data.dw3.fTXSM;
4934 fTSE = pDesc->data.cmd.fTSE;
4935 /*
4936 * TSE descriptors have VLE bit properly set in
4937 * the first fragment.
4938 */
4939 if (fTSE)
4940 {
4941 pThis->fVTag = pDesc->data.cmd.fVLE;
4942 pThis->u16VTagTCI = pDesc->data.dw3.u16Special;
4943 }
4944 pThis->fGSO = e1kCanDoGso(pThis, &pThis->GsoCtx, &pDesc->data, &pThis->contextTSE);
4945 }
4946 cbPacket += pDesc->data.cmd.u20DTALEN;
4947 break;
4948 default:
4949 AssertMsgFailed(("Impossible descriptor type!"));
4950 }
4951 if (pDesc->legacy.cmd.fEOP)
4952 {
4953 /*
4954 * Non-TSE descriptors have VLE bit properly set in
4955 * the last fragment.
4956 */
4957 if (!fTSE)
4958 {
4959 pThis->fVTag = pDesc->data.cmd.fVLE;
4960 pThis->u16VTagTCI = pDesc->data.dw3.u16Special;
4961 }
4962 /*
4963 * Compute the required buffer size. If we cannot do GSO but still
4964 * have to do segmentation we allocate the first segment only.
4965 */
4966 pThis->cbTxAlloc = (!fTSE || pThis->fGSO) ?
4967 cbPacket :
4968 RT_MIN(cbPacket, pThis->contextTSE.dw3.u16MSS + pThis->contextTSE.dw3.u8HDRLEN);
4969 if (pThis->fVTag)
4970 pThis->cbTxAlloc += 4;
4971 LogFlow(("%s e1kLocateTxPacket: RET true cbTxAlloc=%d\n",
4972 pThis->szPrf, pThis->cbTxAlloc));
4973 return true;
4974 }
4975 }
4976
4977 if (cbPacket == 0 && pThis->nTxDFetched - pThis->iTxDCurrent > 0)
4978 {
4979 /* All descriptors were empty, we need to process them as a dummy packet */
4980 LogFlow(("%s e1kLocateTxPacket: RET true cbTxAlloc=%d, zero packet!\n",
4981 pThis->szPrf, pThis->cbTxAlloc));
4982 return true;
4983 }
4984 LogFlow(("%s e1kLocateTxPacket: RET false cbTxAlloc=%d\n",
4985 pThis->szPrf, pThis->cbTxAlloc));
4986 return false;
4987}
4988
4989static int e1kXmitPacket(PE1KSTATE pThis, bool fOnWorkerThread)
4990{
4991 int rc = VINF_SUCCESS;
4992
4993 LogFlow(("%s e1kXmitPacket: ENTER current=%d fetched=%d\n",
4994 pThis->szPrf, pThis->iTxDCurrent, pThis->nTxDFetched));
4995
4996 while (pThis->iTxDCurrent < pThis->nTxDFetched)
4997 {
4998 E1KTXDESC *pDesc = &pThis->aTxDescriptors[pThis->iTxDCurrent];
4999 E1kLog3(("%s About to process new TX descriptor at %08x%08x, TDLEN=%08x, TDH=%08x, TDT=%08x\n",
5000 pThis->szPrf, TDBAH, TDBAL + TDH * sizeof(E1KTXDESC), TDLEN, TDH, TDT));
5001 rc = e1kXmitDesc(pThis, pDesc, e1kDescAddr(TDBAH, TDBAL, TDH), fOnWorkerThread);
5002 if (RT_FAILURE(rc))
5003 break;
5004 if (++TDH * sizeof(E1KTXDESC) >= TDLEN)
5005 TDH = 0;
5006 uint32_t uLowThreshold = GET_BITS(TXDCTL, LWTHRESH)*8;
5007 if (uLowThreshold != 0 && e1kGetTxLen(pThis) <= uLowThreshold)
5008 {
5009 E1kLog2(("%s Low on transmit descriptors, raise ICR.TXD_LOW, len=%x thresh=%x\n",
5010 pThis->szPrf, e1kGetTxLen(pThis), GET_BITS(TXDCTL, LWTHRESH)*8));
5011 e1kRaiseInterrupt(pThis, VERR_SEM_BUSY, ICR_TXD_LOW);
5012 }
5013 ++pThis->iTxDCurrent;
5014 if (e1kGetDescType(pDesc) != E1K_DTYP_CONTEXT && pDesc->legacy.cmd.fEOP)
5015 break;
5016 }
5017
5018 LogFlow(("%s e1kXmitPacket: RET %Rrc current=%d fetched=%d\n",
5019 pThis->szPrf, rc, pThis->iTxDCurrent, pThis->nTxDFetched));
5020 return rc;
5021}
5022
5023#endif /* E1K_WITH_TXD_CACHE */
5024#ifndef E1K_WITH_TXD_CACHE
5025
5026/**
5027 * Transmit pending descriptors.
5028 *
5029 * @returns VBox status code. VERR_TRY_AGAIN is returned if we're busy.
5030 *
5031 * @param pThis The E1000 state.
5032 * @param fOnWorkerThread Whether we're on a worker thread or on an EMT.
5033 */
5034static int e1kXmitPending(PE1KSTATE pThis, bool fOnWorkerThread)
5035{
5036 int rc = VINF_SUCCESS;
5037
5038 /* Check if transmitter is enabled. */
5039 if (!(TCTL & TCTL_EN))
5040 return VINF_SUCCESS;
5041 /*
5042 * Grab the xmit lock of the driver as well as the E1K device state.
5043 */
5044 rc = e1kCsTxEnter(pThis, VERR_SEM_BUSY);
5045 if (RT_LIKELY(rc == VINF_SUCCESS))
5046 {
5047 PPDMINETWORKUP pDrv = pThis->CTX_SUFF(pDrv);
5048 if (pDrv)
5049 {
5050 rc = pDrv->pfnBeginXmit(pDrv, fOnWorkerThread);
5051 if (RT_FAILURE(rc))
5052 {
5053 e1kCsTxLeave(pThis);
5054 return rc;
5055 }
5056 }
5057 /*
5058 * Process all pending descriptors.
5059 * Note! Do not process descriptors in locked state
5060 */
5061 while (TDH != TDT && !pThis->fLocked)
5062 {
5063 E1KTXDESC desc;
5064 E1kLog3(("%s About to process new TX descriptor at %08x%08x, TDLEN=%08x, TDH=%08x, TDT=%08x\n",
5065 pThis->szPrf, TDBAH, TDBAL + TDH * sizeof(desc), TDLEN, TDH, TDT));
5066
5067 e1kLoadDesc(pThis, &desc, ((uint64_t)TDBAH << 32) + TDBAL + TDH * sizeof(desc));
5068 rc = e1kXmitDesc(pThis, &desc, e1kDescAddr(TDBAH, TDBAL, TDH), fOnWorkerThread);
5069 /* If we failed to transmit descriptor we will try it again later */
5070 if (RT_FAILURE(rc))
5071 break;
5072 if (++TDH * sizeof(desc) >= TDLEN)
5073 TDH = 0;
5074
5075 if (e1kGetTxLen(pThis) <= GET_BITS(TXDCTL, LWTHRESH)*8)
5076 {
5077 E1kLog2(("%s Low on transmit descriptors, raise ICR.TXD_LOW, len=%x thresh=%x\n",
5078 pThis->szPrf, e1kGetTxLen(pThis), GET_BITS(TXDCTL, LWTHRESH)*8));
5079 e1kRaiseInterrupt(pThis, VERR_SEM_BUSY, ICR_TXD_LOW);
5080 }
5081
5082 STAM_PROFILE_ADV_STOP(&pThis->CTX_SUFF_Z(StatTransmit), a);
5083 }
5084
5085 /// @todo: uncomment: pThis->uStatIntTXQE++;
5086 /// @todo: uncomment: e1kRaiseInterrupt(pThis, ICR_TXQE);
5087 /*
5088 * Release the lock.
5089 */
5090 if (pDrv)
5091 pDrv->pfnEndXmit(pDrv);
5092 e1kCsTxLeave(pThis);
5093 }
5094
5095 return rc;
5096}
5097
5098#else /* E1K_WITH_TXD_CACHE */
5099
5100static void e1kDumpTxDCache(PE1KSTATE pThis)
5101{
5102 unsigned i, cDescs = TDLEN / sizeof(E1KTXDESC);
5103 uint32_t tdh = TDH;
5104 LogRel(("-- Transmit Descriptors (%d total) --\n", cDescs));
5105 for (i = 0; i < cDescs; ++i)
5106 {
5107 E1KTXDESC desc;
5108 PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns), e1kDescAddr(TDBAH, TDBAL, i),
5109 &desc, sizeof(desc));
5110 if (i == tdh)
5111 LogRel((">>> "));
5112 LogRel(("%RGp: %R[e1ktxd]\n", e1kDescAddr(TDBAH, TDBAL, i), &desc));
5113 }
5114 LogRel(("-- Transmit Descriptors in Cache (at %d (TDH %d)/ fetched %d / max %d) --\n",
5115 pThis->iTxDCurrent, TDH, pThis->nTxDFetched, E1K_TXD_CACHE_SIZE));
5116 if (tdh > pThis->iTxDCurrent)
5117 tdh -= pThis->iTxDCurrent;
5118 else
5119 tdh = cDescs + tdh - pThis->iTxDCurrent;
5120 for (i = 0; i < pThis->nTxDFetched; ++i)
5121 {
5122 if (i == pThis->iTxDCurrent)
5123 LogRel((">>> "));
5124 LogRel(("%RGp: %R[e1ktxd]\n", e1kDescAddr(TDBAH, TDBAL, tdh++ % cDescs), &pThis->aTxDescriptors[i]));
5125 }
5126}
5127
5128/**
5129 * Transmit pending descriptors.
5130 *
5131 * @returns VBox status code. VERR_TRY_AGAIN is returned if we're busy.
5132 *
5133 * @param pThis The E1000 state.
5134 * @param fOnWorkerThread Whether we're on a worker thread or on an EMT.
5135 */
5136static int e1kXmitPending(PE1KSTATE pThis, bool fOnWorkerThread)
5137{
5138 int rc = VINF_SUCCESS;
5139
5140 /* Check if transmitter is enabled. */
5141 if (!(TCTL & TCTL_EN))
5142 return VINF_SUCCESS;
5143 /*
5144 * Grab the xmit lock of the driver as well as the E1K device state.
5145 */
5146 PPDMINETWORKUP pDrv = pThis->CTX_SUFF(pDrv);
5147 if (pDrv)
5148 {
5149 rc = pDrv->pfnBeginXmit(pDrv, fOnWorkerThread);
5150 if (RT_FAILURE(rc))
5151 return rc;
5152 }
5153
5154 /*
5155 * Process all pending descriptors.
5156 * Note! Do not process descriptors in locked state
5157 */
5158 rc = e1kCsTxEnter(pThis, VERR_SEM_BUSY);
5159 if (RT_LIKELY(rc == VINF_SUCCESS))
5160 {
5161 STAM_PROFILE_ADV_START(&pThis->CTX_SUFF_Z(StatTransmit), a);
5162 /*
5163 * fIncomplete is set whenever we try to fetch additional descriptors
5164 * for an incomplete packet. If fail to locate a complete packet on
5165 * the next iteration we need to reset the cache or we risk to get
5166 * stuck in this loop forever.
5167 */
5168 bool fIncomplete = false;
5169 while (!pThis->fLocked && e1kTxDLazyLoad(pThis))
5170 {
5171 while (e1kLocateTxPacket(pThis))
5172 {
5173 fIncomplete = false;
5174 /* Found a complete packet, allocate it. */
5175 rc = e1kXmitAllocBuf(pThis, pThis->fGSO);
5176 /* If we're out of bandwidth we'll come back later. */
5177 if (RT_FAILURE(rc))
5178 goto out;
5179 /* Copy the packet to allocated buffer and send it. */
5180 rc = e1kXmitPacket(pThis, fOnWorkerThread);
5181 /* If we're out of bandwidth we'll come back later. */
5182 if (RT_FAILURE(rc))
5183 goto out;
5184 }
5185 uint8_t u8Remain = pThis->nTxDFetched - pThis->iTxDCurrent;
5186 if (RT_UNLIKELY(fIncomplete))
5187 {
5188 static bool fTxDCacheDumped = false;
5189 /*
5190 * The descriptor cache is full, but we were unable to find
5191 * a complete packet in it. Drop the cache and hope that
5192 * the guest driver can recover from network card error.
5193 */
5194 LogRel(("%s No complete packets in%s TxD cache! "
5195 "Fetched=%d, current=%d, TX len=%d.\n",
5196 pThis->szPrf,
5197 u8Remain == E1K_TXD_CACHE_SIZE ? " full" : "",
5198 pThis->nTxDFetched, pThis->iTxDCurrent,
5199 e1kGetTxLen(pThis)));
5200 if (!fTxDCacheDumped)
5201 {
5202 fTxDCacheDumped = true;
5203 e1kDumpTxDCache(pThis);
5204 }
5205 pThis->iTxDCurrent = pThis->nTxDFetched = 0;
5206 /*
5207 * Returning an error at this point means Guru in R0
5208 * (see @bugref{6428}).
5209 */
5210# ifdef IN_RING3
5211 rc = VERR_NET_INCOMPLETE_TX_PACKET;
5212# else /* !IN_RING3 */
5213 rc = VINF_IOM_R3_IOPORT_WRITE;
5214# endif /* !IN_RING3 */
5215 goto out;
5216 }
5217 if (u8Remain > 0)
5218 {
5219 Log4(("%s Incomplete packet at %d. Already fetched %d, "
5220 "%d more are available\n",
5221 pThis->szPrf, pThis->iTxDCurrent, u8Remain,
5222 e1kGetTxLen(pThis) - u8Remain));
5223
5224 /*
5225 * A packet was partially fetched. Move incomplete packet to
5226 * the beginning of cache buffer, then load more descriptors.
5227 */
5228 memmove(pThis->aTxDescriptors,
5229 &pThis->aTxDescriptors[pThis->iTxDCurrent],
5230 u8Remain * sizeof(E1KTXDESC));
5231 pThis->iTxDCurrent = 0;
5232 pThis->nTxDFetched = u8Remain;
5233 e1kTxDLoadMore(pThis);
5234 fIncomplete = true;
5235 }
5236 else
5237 pThis->nTxDFetched = 0;
5238 pThis->iTxDCurrent = 0;
5239 }
5240 if (!pThis->fLocked && GET_BITS(TXDCTL, LWTHRESH) == 0)
5241 {
5242 E1kLog2(("%s Out of transmit descriptors, raise ICR.TXD_LOW\n",
5243 pThis->szPrf));
5244 e1kRaiseInterrupt(pThis, VERR_SEM_BUSY, ICR_TXD_LOW);
5245 }
5246out:
5247 STAM_PROFILE_ADV_STOP(&pThis->CTX_SUFF_Z(StatTransmit), a);
5248
5249 /// @todo: uncomment: pThis->uStatIntTXQE++;
5250 /// @todo: uncomment: e1kRaiseInterrupt(pThis, ICR_TXQE);
5251
5252 e1kCsTxLeave(pThis);
5253 }
5254
5255
5256 /*
5257 * Release the lock.
5258 */
5259 if (pDrv)
5260 pDrv->pfnEndXmit(pDrv);
5261 return rc;
5262}
5263
5264#endif /* E1K_WITH_TXD_CACHE */
5265#ifdef IN_RING3
5266
5267/**
5268 * @interface_method_impl{PDMINETWORKDOWN,pfnXmitPending}
5269 */
5270static DECLCALLBACK(void) e1kR3NetworkDown_XmitPending(PPDMINETWORKDOWN pInterface)
5271{
5272 PE1KSTATE pThis = RT_FROM_MEMBER(pInterface, E1KSTATE, INetworkDown);
5273 /* Resume suspended transmission */
5274 STATUS &= ~STATUS_TXOFF;
5275 e1kXmitPending(pThis, true /*fOnWorkerThread*/);
5276}
5277
5278/**
5279 * Callback for consuming from transmit queue. It gets called in R3 whenever
5280 * we enqueue something in R0/GC.
5281 *
5282 * @returns true
5283 * @param pDevIns Pointer to device instance structure.
5284 * @param pItem Pointer to the element being dequeued (not used).
5285 * @thread ???
5286 */
5287static DECLCALLBACK(bool) e1kTxQueueConsumer(PPDMDEVINS pDevIns, PPDMQUEUEITEMCORE pItem)
5288{
5289 NOREF(pItem);
5290 PE1KSTATE pThis = PDMINS_2_DATA(pDevIns, PE1KSTATE);
5291 E1kLog2(("%s e1kTxQueueConsumer:\n", pThis->szPrf));
5292
5293 int rc = e1kXmitPending(pThis, false /*fOnWorkerThread*/);
5294 AssertMsg(RT_SUCCESS(rc) || rc == VERR_TRY_AGAIN, ("%Rrc\n", rc));
5295
5296 return true;
5297}
5298
5299/**
5300 * Handler for the wakeup signaller queue.
5301 */
5302static DECLCALLBACK(bool) e1kCanRxQueueConsumer(PPDMDEVINS pDevIns, PPDMQUEUEITEMCORE pItem)
5303{
5304 e1kWakeupReceive(pDevIns);
5305 return true;
5306}
5307
5308#endif /* IN_RING3 */
5309
5310/**
5311 * Write handler for Transmit Descriptor Tail register.
5312 *
5313 * @param pThis The device state structure.
5314 * @param offset Register offset in memory-mapped frame.
5315 * @param index Register index in register array.
5316 * @param value The value to store.
5317 * @param mask Used to implement partial writes (8 and 16-bit).
5318 * @thread EMT
5319 */
5320static int e1kRegWriteTDT(PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t value)
5321{
5322 int rc = e1kRegWriteDefault(pThis, offset, index, value);
5323
5324 /* All descriptors starting with head and not including tail belong to us. */
5325 /* Process them. */
5326 E1kLog2(("%s e1kRegWriteTDT: TDBAL=%08x, TDBAH=%08x, TDLEN=%08x, TDH=%08x, TDT=%08x\n",
5327 pThis->szPrf, TDBAL, TDBAH, TDLEN, TDH, TDT));
5328
5329 /* Ignore TDT writes when the link is down. */
5330 if (TDH != TDT && (STATUS & STATUS_LU))
5331 {
5332 Log5(("E1000: TDT write: TDH=%08x, TDT=%08x, %d descriptors to process\n", TDH, TDT, e1kGetTxLen(pThis)));
5333 E1kLog(("%s e1kRegWriteTDT: %d descriptors to process\n",
5334 pThis->szPrf, e1kGetTxLen(pThis)));
5335
5336 /* Transmit pending packets if possible, defer it if we cannot do it
5337 in the current context. */
5338#ifdef E1K_TX_DELAY
5339 rc = e1kCsTxEnter(pThis, VERR_SEM_BUSY);
5340 if (RT_LIKELY(rc == VINF_SUCCESS))
5341 {
5342 if (!TMTimerIsActive(pThis->CTX_SUFF(pTXDTimer)))
5343 {
5344#ifdef E1K_INT_STATS
5345 pThis->u64ArmedAt = RTTimeNanoTS();
5346#endif
5347 e1kArmTimer(pThis, pThis->CTX_SUFF(pTXDTimer), E1K_TX_DELAY);
5348 }
5349 E1K_INC_ISTAT_CNT(pThis->uStatTxDelayed);
5350 e1kCsTxLeave(pThis);
5351 return rc;
5352 }
5353 /* We failed to enter the TX critical section -- transmit as usual. */
5354#endif /* E1K_TX_DELAY */
5355#ifndef IN_RING3
5356 if (!pThis->CTX_SUFF(pDrv))
5357 {
5358 PPDMQUEUEITEMCORE pItem = PDMQueueAlloc(pThis->CTX_SUFF(pTxQueue));
5359 if (RT_UNLIKELY(pItem))
5360 PDMQueueInsert(pThis->CTX_SUFF(pTxQueue), pItem);
5361 }
5362 else
5363#endif
5364 {
5365 rc = e1kXmitPending(pThis, false /*fOnWorkerThread*/);
5366 if (rc == VERR_TRY_AGAIN)
5367 rc = VINF_SUCCESS;
5368 else if (rc == VERR_SEM_BUSY)
5369 rc = VINF_IOM_R3_IOPORT_WRITE;
5370 AssertRC(rc);
5371 }
5372 }
5373
5374 return rc;
5375}
5376
5377/**
5378 * Write handler for Multicast Table Array registers.
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 * @param value The value to store.
5384 * @thread EMT
5385 */
5386static int e1kRegWriteMTA(PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t value)
5387{
5388 AssertReturn(offset - g_aE1kRegMap[index].offset < sizeof(pThis->auMTA), VERR_DEV_IO_ERROR);
5389 pThis->auMTA[(offset - g_aE1kRegMap[index].offset)/sizeof(pThis->auMTA[0])] = value;
5390
5391 return VINF_SUCCESS;
5392}
5393
5394/**
5395 * Read handler for Multicast Table Array registers.
5396 *
5397 * @returns VBox status code.
5398 *
5399 * @param pThis The device state structure.
5400 * @param offset Register offset in memory-mapped frame.
5401 * @param index Register index in register array.
5402 * @thread EMT
5403 */
5404static int e1kRegReadMTA(PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t *pu32Value)
5405{
5406 AssertReturn(offset - g_aE1kRegMap[index].offset< sizeof(pThis->auMTA), VERR_DEV_IO_ERROR);
5407 *pu32Value = pThis->auMTA[(offset - g_aE1kRegMap[index].offset)/sizeof(pThis->auMTA[0])];
5408
5409 return VINF_SUCCESS;
5410}
5411
5412/**
5413 * Write handler for Receive Address registers.
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 * @param value The value to store.
5419 * @thread EMT
5420 */
5421static int e1kRegWriteRA(PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t value)
5422{
5423 AssertReturn(offset - g_aE1kRegMap[index].offset < sizeof(pThis->aRecAddr.au32), VERR_DEV_IO_ERROR);
5424 pThis->aRecAddr.au32[(offset - g_aE1kRegMap[index].offset)/sizeof(pThis->aRecAddr.au32[0])] = value;
5425
5426 return VINF_SUCCESS;
5427}
5428
5429/**
5430 * Read handler for Receive Address registers.
5431 *
5432 * @returns VBox status code.
5433 *
5434 * @param pThis The device state structure.
5435 * @param offset Register offset in memory-mapped frame.
5436 * @param index Register index in register array.
5437 * @thread EMT
5438 */
5439static int e1kRegReadRA(PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t *pu32Value)
5440{
5441 AssertReturn(offset - g_aE1kRegMap[index].offset< sizeof(pThis->aRecAddr.au32), VERR_DEV_IO_ERROR);
5442 *pu32Value = pThis->aRecAddr.au32[(offset - g_aE1kRegMap[index].offset)/sizeof(pThis->aRecAddr.au32[0])];
5443
5444 return VINF_SUCCESS;
5445}
5446
5447/**
5448 * Write handler for VLAN Filter Table Array registers.
5449 *
5450 * @param pThis The device state structure.
5451 * @param offset Register offset in memory-mapped frame.
5452 * @param index Register index in register array.
5453 * @param value The value to store.
5454 * @thread EMT
5455 */
5456static int e1kRegWriteVFTA(PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t value)
5457{
5458 AssertReturn(offset - g_aE1kRegMap[index].offset < sizeof(pThis->auVFTA), VINF_SUCCESS);
5459 pThis->auVFTA[(offset - g_aE1kRegMap[index].offset)/sizeof(pThis->auVFTA[0])] = value;
5460
5461 return VINF_SUCCESS;
5462}
5463
5464/**
5465 * Read handler for VLAN Filter Table Array registers.
5466 *
5467 * @returns VBox status code.
5468 *
5469 * @param pThis The device state structure.
5470 * @param offset Register offset in memory-mapped frame.
5471 * @param index Register index in register array.
5472 * @thread EMT
5473 */
5474static int e1kRegReadVFTA(PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t *pu32Value)
5475{
5476 AssertReturn(offset - g_aE1kRegMap[index].offset< sizeof(pThis->auVFTA), VERR_DEV_IO_ERROR);
5477 *pu32Value = pThis->auVFTA[(offset - g_aE1kRegMap[index].offset)/sizeof(pThis->auVFTA[0])];
5478
5479 return VINF_SUCCESS;
5480}
5481
5482/**
5483 * Read handler for unimplemented registers.
5484 *
5485 * Merely reports reads from unimplemented registers.
5486 *
5487 * @returns VBox status code.
5488 *
5489 * @param pThis The device state structure.
5490 * @param offset Register offset in memory-mapped frame.
5491 * @param index Register index in register array.
5492 * @thread EMT
5493 */
5494static int e1kRegReadUnimplemented(PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t *pu32Value)
5495{
5496 E1kLog(("%s At %08X read (00000000) attempt from unimplemented register %s (%s)\n",
5497 pThis->szPrf, offset, g_aE1kRegMap[index].abbrev, g_aE1kRegMap[index].name));
5498 *pu32Value = 0;
5499
5500 return VINF_SUCCESS;
5501}
5502
5503/**
5504 * Default register read handler with automatic clear operation.
5505 *
5506 * Retrieves the value of register from register array in device state structure.
5507 * Then resets all bits.
5508 *
5509 * @remarks The 'mask' parameter is simply ignored as masking and shifting is
5510 * done in the caller.
5511 *
5512 * @returns VBox status code.
5513 *
5514 * @param pThis The device state structure.
5515 * @param offset Register offset in memory-mapped frame.
5516 * @param index Register index in register array.
5517 * @thread EMT
5518 */
5519static int e1kRegReadAutoClear(PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t *pu32Value)
5520{
5521 AssertReturn(index < E1K_NUM_OF_32BIT_REGS, VERR_DEV_IO_ERROR);
5522 int rc = e1kRegReadDefault(pThis, offset, index, pu32Value);
5523 pThis->auRegs[index] = 0;
5524
5525 return rc;
5526}
5527
5528/**
5529 * Default register read handler.
5530 *
5531 * Retrieves the value of register from register array in device state structure.
5532 * Bits corresponding to 0s in 'readable' mask will always read as 0s.
5533 *
5534 * @remarks The 'mask' parameter is simply ignored as masking and shifting is
5535 * done in the caller.
5536 *
5537 * @returns VBox status code.
5538 *
5539 * @param pThis The device state structure.
5540 * @param offset Register offset in memory-mapped frame.
5541 * @param index Register index in register array.
5542 * @thread EMT
5543 */
5544static int e1kRegReadDefault(PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t *pu32Value)
5545{
5546 AssertReturn(index < E1K_NUM_OF_32BIT_REGS, VERR_DEV_IO_ERROR);
5547 *pu32Value = pThis->auRegs[index] & g_aE1kRegMap[index].readable;
5548
5549 return VINF_SUCCESS;
5550}
5551
5552/**
5553 * Write handler for unimplemented registers.
5554 *
5555 * Merely reports writes to unimplemented registers.
5556 *
5557 * @param pThis The device state structure.
5558 * @param offset Register offset in memory-mapped frame.
5559 * @param index Register index in register array.
5560 * @param value The value to store.
5561 * @thread EMT
5562 */
5563
5564 static int e1kRegWriteUnimplemented(PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t value)
5565{
5566 E1kLog(("%s At %08X write attempt (%08X) to unimplemented register %s (%s)\n",
5567 pThis->szPrf, offset, value, g_aE1kRegMap[index].abbrev, g_aE1kRegMap[index].name));
5568
5569 return VINF_SUCCESS;
5570}
5571
5572/**
5573 * Default register write handler.
5574 *
5575 * Stores the value to the register array in device state structure. Only bits
5576 * corresponding to 1s both in 'writable' and 'mask' will be stored.
5577 *
5578 * @returns VBox status code.
5579 *
5580 * @param pThis The device state structure.
5581 * @param offset Register offset in memory-mapped frame.
5582 * @param index Register index in register array.
5583 * @param value The value to store.
5584 * @param mask Used to implement partial writes (8 and 16-bit).
5585 * @thread EMT
5586 */
5587
5588static int e1kRegWriteDefault(PE1KSTATE pThis, uint32_t offset, uint32_t index, uint32_t value)
5589{
5590 AssertReturn(index < E1K_NUM_OF_32BIT_REGS, VERR_DEV_IO_ERROR);
5591 pThis->auRegs[index] = (value & g_aE1kRegMap[index].writable)
5592 | (pThis->auRegs[index] & ~g_aE1kRegMap[index].writable);
5593
5594 return VINF_SUCCESS;
5595}
5596
5597/**
5598 * Search register table for matching register.
5599 *
5600 * @returns Index in the register table or -1 if not found.
5601 *
5602 * @param pThis The device state structure.
5603 * @param offReg Register offset in memory-mapped region.
5604 * @thread EMT
5605 */
5606static int e1kRegLookup(PE1KSTATE pThis, uint32_t offReg)
5607{
5608#if 0
5609 int index;
5610
5611 for (index = 0; index < E1K_NUM_OF_REGS; index++)
5612 {
5613 if (g_aE1kRegMap[index].offset <= offReg && offReg < g_aE1kRegMap[index].offset + g_aE1kRegMap[index].size)
5614 {
5615 return index;
5616 }
5617 }
5618#else
5619 int iStart = 0;
5620 int iEnd = E1K_NUM_OF_BINARY_SEARCHABLE;
5621 for (;;)
5622 {
5623 int i = (iEnd - iStart) / 2 + iStart;
5624 uint32_t offCur = g_aE1kRegMap[i].offset;
5625 if (offReg < offCur)
5626 {
5627 if (i == iStart)
5628 break;
5629 iEnd = i;
5630 }
5631 else if (offReg >= offCur + g_aE1kRegMap[i].size)
5632 {
5633 i++;
5634 if (i == iEnd)
5635 break;
5636 iStart = i;
5637 }
5638 else
5639 return i;
5640 Assert(iEnd > iStart);
5641 }
5642
5643 for (unsigned i = E1K_NUM_OF_BINARY_SEARCHABLE; i < RT_ELEMENTS(g_aE1kRegMap); i++)
5644 if (offReg - g_aE1kRegMap[i].offset < g_aE1kRegMap[i].size)
5645 return i;
5646
5647# ifdef VBOX_STRICT
5648 for (unsigned i = 0; i < RT_ELEMENTS(g_aE1kRegMap); i++)
5649 Assert(offReg - g_aE1kRegMap[i].offset >= g_aE1kRegMap[i].size);
5650# endif
5651
5652#endif
5653
5654 return -1;
5655}
5656
5657/**
5658 * Handle unaligned register read operation.
5659 *
5660 * Looks up and calls appropriate handler.
5661 *
5662 * @returns VBox status code.
5663 *
5664 * @param pThis The device state structure.
5665 * @param offReg Register offset in memory-mapped frame.
5666 * @param pv Where to store the result.
5667 * @param cb Number of bytes to read.
5668 * @thread EMT
5669 * @remarks IOM takes care of unaligned and small reads via MMIO. For I/O port
5670 * accesses we have to take care of that ourselves.
5671 */
5672static int e1kRegReadUnaligned(PE1KSTATE pThis, uint32_t offReg, void *pv, uint32_t cb)
5673{
5674 uint32_t u32 = 0;
5675 uint32_t shift;
5676 int rc = VINF_SUCCESS;
5677 int index = e1kRegLookup(pThis, offReg);
5678#ifdef DEBUG
5679 char buf[9];
5680#endif
5681
5682 /*
5683 * From the spec:
5684 * For registers that should be accessed as 32-bit double words, partial writes (less than a 32-bit
5685 * double word) is ignored. Partial reads return all 32 bits of data regardless of the byte enables.
5686 */
5687
5688 /*
5689 * To be able to read bytes and short word we convert them to properly
5690 * shifted 32-bit words and masks. The idea is to keep register-specific
5691 * handlers simple. Most accesses will be 32-bit anyway.
5692 */
5693 uint32_t mask;
5694 switch (cb)
5695 {
5696 case 4: mask = 0xFFFFFFFF; break;
5697 case 2: mask = 0x0000FFFF; break;
5698 case 1: mask = 0x000000FF; break;
5699 default:
5700 return PDMDevHlpDBGFStop(pThis->CTX_SUFF(pDevIns), RT_SRC_POS,
5701 "unsupported op size: offset=%#10x cb=%#10x\n", offReg, cb);
5702 }
5703 if (index != -1)
5704 {
5705 if (g_aE1kRegMap[index].readable)
5706 {
5707 /* Make the mask correspond to the bits we are about to read. */
5708 shift = (offReg - g_aE1kRegMap[index].offset) % sizeof(uint32_t) * 8;
5709 mask <<= shift;
5710 if (!mask)
5711 return PDMDevHlpDBGFStop(pThis->CTX_SUFF(pDevIns), RT_SRC_POS, "Zero mask: offset=%#10x cb=%#10x\n", offReg, cb);
5712 /*
5713 * Read it. Pass the mask so the handler knows what has to be read.
5714 * Mask out irrelevant bits.
5715 */
5716 //rc = e1kCsEnter(pThis, VERR_SEM_BUSY, RT_SRC_POS);
5717 if (RT_UNLIKELY(rc != VINF_SUCCESS))
5718 return rc;
5719 //pThis->fDelayInts = false;
5720 //pThis->iStatIntLost += pThis->iStatIntLostOne;
5721 //pThis->iStatIntLostOne = 0;
5722 rc = g_aE1kRegMap[index].pfnRead(pThis, offReg & 0xFFFFFFFC, index, &u32);
5723 u32 &= mask;
5724 //e1kCsLeave(pThis);
5725 E1kLog2(("%s At %08X read %s from %s (%s)\n",
5726 pThis->szPrf, offReg, e1kU32toHex(u32, mask, buf), g_aE1kRegMap[index].abbrev, g_aE1kRegMap[index].name));
5727 Log6(("%s At %08X read %s from %s (%s) [UNALIGNED]\n",
5728 pThis->szPrf, offReg, e1kU32toHex(u32, mask, buf), g_aE1kRegMap[index].abbrev, g_aE1kRegMap[index].name));
5729 /* Shift back the result. */
5730 u32 >>= shift;
5731 }
5732 else
5733 E1kLog(("%s At %08X read (%s) attempt from write-only register %s (%s)\n",
5734 pThis->szPrf, offReg, e1kU32toHex(u32, mask, buf), g_aE1kRegMap[index].abbrev, g_aE1kRegMap[index].name));
5735 if (IOM_SUCCESS(rc))
5736 STAM_COUNTER_INC(&pThis->aStatRegReads[index]);
5737 }
5738 else
5739 E1kLog(("%s At %08X read (%s) attempt from non-existing register\n",
5740 pThis->szPrf, offReg, e1kU32toHex(u32, mask, buf)));
5741
5742 memcpy(pv, &u32, cb);
5743 return rc;
5744}
5745
5746/**
5747 * Handle 4 byte aligned and sized read operation.
5748 *
5749 * Looks up and calls appropriate handler.
5750 *
5751 * @returns VBox status code.
5752 *
5753 * @param pThis The device state structure.
5754 * @param offReg Register offset in memory-mapped frame.
5755 * @param pu32 Where to store the result.
5756 * @thread EMT
5757 */
5758static int e1kRegReadAlignedU32(PE1KSTATE pThis, uint32_t offReg, uint32_t *pu32)
5759{
5760 Assert(!(offReg & 3));
5761
5762 /*
5763 * Lookup the register and check that it's readable.
5764 */
5765 int rc = VINF_SUCCESS;
5766 int idxReg = e1kRegLookup(pThis, offReg);
5767 if (RT_LIKELY(idxReg != -1))
5768 {
5769 if (RT_UNLIKELY(g_aE1kRegMap[idxReg].readable))
5770 {
5771 /*
5772 * Read it. Pass the mask so the handler knows what has to be read.
5773 * Mask out irrelevant bits.
5774 */
5775 //rc = e1kCsEnter(pThis, VERR_SEM_BUSY, RT_SRC_POS);
5776 //if (RT_UNLIKELY(rc != VINF_SUCCESS))
5777 // return rc;
5778 //pThis->fDelayInts = false;
5779 //pThis->iStatIntLost += pThis->iStatIntLostOne;
5780 //pThis->iStatIntLostOne = 0;
5781 rc = g_aE1kRegMap[idxReg].pfnRead(pThis, offReg & 0xFFFFFFFC, idxReg, pu32);
5782 //e1kCsLeave(pThis);
5783 Log6(("%s At %08X read %08X from %s (%s)\n",
5784 pThis->szPrf, offReg, *pu32, g_aE1kRegMap[idxReg].abbrev, g_aE1kRegMap[idxReg].name));
5785 if (IOM_SUCCESS(rc))
5786 STAM_COUNTER_INC(&pThis->aStatRegReads[idxReg]);
5787 }
5788 else
5789 E1kLog(("%s At %08X read (%s) attempt from non-existing register\n", pThis->szPrf, offReg));
5790 }
5791 else
5792 E1kLog(("%s At %08X read attempt from non-existing register\n", pThis->szPrf, offReg));
5793 return rc;
5794}
5795
5796/**
5797 * Handle 4 byte sized and aligned register write operation.
5798 *
5799 * Looks up and calls appropriate handler.
5800 *
5801 * @returns VBox status code.
5802 *
5803 * @param pThis The device state structure.
5804 * @param offReg Register offset in memory-mapped frame.
5805 * @param u32Value The value to write.
5806 * @thread EMT
5807 */
5808static int e1kRegWriteAlignedU32(PE1KSTATE pThis, uint32_t offReg, uint32_t u32Value)
5809{
5810 int rc = VINF_SUCCESS;
5811 int index = e1kRegLookup(pThis, offReg);
5812 if (RT_LIKELY(index != -1))
5813 {
5814 if (RT_LIKELY(g_aE1kRegMap[index].writable))
5815 {
5816 /*
5817 * Write it. Pass the mask so the handler knows what has to be written.
5818 * Mask out irrelevant bits.
5819 */
5820 Log6(("%s At %08X write %08X to %s (%s)\n",
5821 pThis->szPrf, offReg, u32Value, g_aE1kRegMap[index].abbrev, g_aE1kRegMap[index].name));
5822 //rc = e1kCsEnter(pThis, VERR_SEM_BUSY, RT_SRC_POS);
5823 //if (RT_UNLIKELY(rc != VINF_SUCCESS))
5824 // return rc;
5825 //pThis->fDelayInts = false;
5826 //pThis->iStatIntLost += pThis->iStatIntLostOne;
5827 //pThis->iStatIntLostOne = 0;
5828 rc = g_aE1kRegMap[index].pfnWrite(pThis, offReg, index, u32Value);
5829 //e1kCsLeave(pThis);
5830 }
5831 else
5832 E1kLog(("%s At %08X write attempt (%08X) to read-only register %s (%s)\n",
5833 pThis->szPrf, offReg, u32Value, g_aE1kRegMap[index].abbrev, g_aE1kRegMap[index].name));
5834 if (IOM_SUCCESS(rc))
5835 STAM_COUNTER_INC(&pThis->aStatRegWrites[index]);
5836 }
5837 else
5838 E1kLog(("%s At %08X write attempt (%08X) to non-existing register\n",
5839 pThis->szPrf, offReg, u32Value));
5840 return rc;
5841}
5842
5843
5844/* -=-=-=-=- MMIO and I/O Port Callbacks -=-=-=-=- */
5845
5846/**
5847 * @callback_method_impl{FNIOMMMIOREAD}
5848 */
5849PDMBOTHCBDECL(int) e1kMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
5850{
5851 NOREF(pvUser);
5852 PE1KSTATE pThis = PDMINS_2_DATA(pDevIns, PE1KSTATE);
5853 STAM_PROFILE_ADV_START(&pThis->CTX_SUFF_Z(StatMMIORead), a);
5854
5855 uint32_t offReg = GCPhysAddr - pThis->addrMMReg;
5856 Assert(offReg < E1K_MM_SIZE);
5857 Assert(cb == 4);
5858 Assert(!(GCPhysAddr & 3));
5859
5860 int rc = e1kRegReadAlignedU32(pThis, offReg, (uint32_t *)pv);
5861
5862 STAM_PROFILE_ADV_STOP(&pThis->CTX_SUFF_Z(StatMMIORead), a);
5863 return rc;
5864}
5865
5866/**
5867 * @callback_method_impl{FNIOMMMIOWRITE}
5868 */
5869PDMBOTHCBDECL(int) e1kMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void const *pv, unsigned cb)
5870{
5871 NOREF(pvUser);
5872 PE1KSTATE pThis = PDMINS_2_DATA(pDevIns, PE1KSTATE);
5873 STAM_PROFILE_ADV_START(&pThis->CTX_SUFF_Z(StatMMIOWrite), a);
5874
5875 uint32_t offReg = GCPhysAddr - pThis->addrMMReg;
5876 Assert(offReg < E1K_MM_SIZE);
5877 Assert(cb == 4);
5878 Assert(!(GCPhysAddr & 3));
5879
5880 int rc = e1kRegWriteAlignedU32(pThis, offReg, *(uint32_t const *)pv);
5881
5882 STAM_PROFILE_ADV_STOP(&pThis->CTX_SUFF_Z(StatMMIOWrite), a);
5883 return rc;
5884}
5885
5886/**
5887 * @callback_method_impl{FNIOMIOPORTIN}
5888 */
5889PDMBOTHCBDECL(int) e1kIOPortIn(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT uPort, uint32_t *pu32, unsigned cb)
5890{
5891 PE1KSTATE pThis = PDMINS_2_DATA(pDevIns, PE1KSTATE);
5892 int rc;
5893 STAM_PROFILE_ADV_START(&pThis->CTX_SUFF_Z(StatIORead), a);
5894
5895 uPort -= pThis->IOPortBase;
5896 if (RT_LIKELY(cb == 4))
5897 switch (uPort)
5898 {
5899 case 0x00: /* IOADDR */
5900 *pu32 = pThis->uSelectedReg;
5901 E1kLog2(("%s e1kIOPortIn: IOADDR(0), selecting register %#010x, val=%#010x\n", pThis->szPrf, pThis->uSelectedReg, *pu32));
5902 rc = VINF_SUCCESS;
5903 break;
5904
5905 case 0x04: /* IODATA */
5906 if (!(pThis->uSelectedReg & 3))
5907 rc = e1kRegReadAlignedU32(pThis, pThis->uSelectedReg, pu32);
5908 else /** @todo r=bird: I wouldn't be surprised if this unaligned branch wasn't necessary. */
5909 rc = e1kRegReadUnaligned(pThis, pThis->uSelectedReg, pu32, cb);
5910 if (rc == VINF_IOM_R3_MMIO_READ)
5911 rc = VINF_IOM_R3_IOPORT_READ;
5912 E1kLog2(("%s e1kIOPortIn: IODATA(4), reading from selected register %#010x, val=%#010x\n", pThis->szPrf, pThis->uSelectedReg, *pu32));
5913 break;
5914
5915 default:
5916 E1kLog(("%s e1kIOPortIn: invalid port %#010x\n", pThis->szPrf, uPort));
5917 //rc = VERR_IOM_IOPORT_UNUSED; /* Why not? */
5918 rc = VINF_SUCCESS;
5919 }
5920 else
5921 {
5922 E1kLog(("%s e1kIOPortIn: invalid op size: uPort=%RTiop cb=%08x", pThis->szPrf, uPort, cb));
5923 rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "%s e1kIOPortIn: invalid op size: uPort=%RTiop cb=%08x\n", pThis->szPrf, uPort, cb);
5924 }
5925 STAM_PROFILE_ADV_STOP(&pThis->CTX_SUFF_Z(StatIORead), a);
5926 return rc;
5927}
5928
5929
5930/**
5931 * @callback_method_impl{FNIOMIOPORTOUT}
5932 */
5933PDMBOTHCBDECL(int) e1kIOPortOut(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT uPort, uint32_t u32, unsigned cb)
5934{
5935 PE1KSTATE pThis = PDMINS_2_DATA(pDevIns, PE1KSTATE);
5936 int rc;
5937 STAM_PROFILE_ADV_START(&pThis->CTX_SUFF_Z(StatIOWrite), a);
5938
5939 E1kLog2(("%s e1kIOPortOut: uPort=%RTiop value=%08x\n", pThis->szPrf, uPort, u32));
5940 if (RT_LIKELY(cb == 4))
5941 {
5942 uPort -= pThis->IOPortBase;
5943 switch (uPort)
5944 {
5945 case 0x00: /* IOADDR */
5946 pThis->uSelectedReg = u32;
5947 E1kLog2(("%s e1kIOPortOut: IOADDR(0), selected register %08x\n", pThis->szPrf, pThis->uSelectedReg));
5948 rc = VINF_SUCCESS;
5949 break;
5950
5951 case 0x04: /* IODATA */
5952 E1kLog2(("%s e1kIOPortOut: IODATA(4), writing to selected register %#010x, value=%#010x\n", pThis->szPrf, pThis->uSelectedReg, u32));
5953 if (RT_LIKELY(!(pThis->uSelectedReg & 3)))
5954 {
5955 rc = e1kRegWriteAlignedU32(pThis, pThis->uSelectedReg, u32);
5956 if (rc == VINF_IOM_R3_MMIO_WRITE)
5957 rc = VINF_IOM_R3_IOPORT_WRITE;
5958 }
5959 else
5960 rc = PDMDevHlpDBGFStop(pThis->CTX_SUFF(pDevIns), RT_SRC_POS,
5961 "Spec violation: misaligned offset: %#10x, ignored.\n", pThis->uSelectedReg);
5962 break;
5963
5964 default:
5965 E1kLog(("%s e1kIOPortOut: invalid port %#010x\n", pThis->szPrf, uPort));
5966 rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "invalid port %#010x\n", uPort);
5967 }
5968 }
5969 else
5970 {
5971 E1kLog(("%s e1kIOPortOut: invalid op size: uPort=%RTiop cb=%08x\n", pThis->szPrf, uPort, cb));
5972 rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "invalid op size: uPort=%RTiop cb=%#x\n", pThis->szPrf, uPort, cb);
5973 }
5974
5975 STAM_PROFILE_ADV_STOP(&pThis->CTX_SUFF_Z(StatIOWrite), a);
5976 return rc;
5977}
5978
5979#ifdef IN_RING3
5980
5981/**
5982 * Dump complete device state to log.
5983 *
5984 * @param pThis Pointer to device state.
5985 */
5986static void e1kDumpState(PE1KSTATE pThis)
5987{
5988 for (int i = 0; i < E1K_NUM_OF_32BIT_REGS; ++i)
5989 {
5990 E1kLog2(("%s %8.8s = %08x\n", pThis->szPrf,
5991 g_aE1kRegMap[i].abbrev, pThis->auRegs[i]));
5992 }
5993# ifdef E1K_INT_STATS
5994 LogRel(("%s Interrupt attempts: %d\n", pThis->szPrf, pThis->uStatIntTry));
5995 LogRel(("%s Interrupts raised : %d\n", pThis->szPrf, pThis->uStatInt));
5996 LogRel(("%s Interrupts lowered: %d\n", pThis->szPrf, pThis->uStatIntLower));
5997 LogRel(("%s Interrupts delayed: %d\n", pThis->szPrf, pThis->uStatIntDly));
5998 LogRel(("%s Disabled delayed: %d\n", pThis->szPrf, pThis->uStatDisDly));
5999 LogRel(("%s Interrupts skipped: %d\n", pThis->szPrf, pThis->uStatIntSkip));
6000 LogRel(("%s Masked interrupts : %d\n", pThis->szPrf, pThis->uStatIntMasked));
6001 LogRel(("%s Early interrupts : %d\n", pThis->szPrf, pThis->uStatIntEarly));
6002 LogRel(("%s Late interrupts : %d\n", pThis->szPrf, pThis->uStatIntLate));
6003 LogRel(("%s Lost interrupts : %d\n", pThis->szPrf, pThis->iStatIntLost));
6004 LogRel(("%s Interrupts by RX : %d\n", pThis->szPrf, pThis->uStatIntRx));
6005 LogRel(("%s Interrupts by TX : %d\n", pThis->szPrf, pThis->uStatIntTx));
6006 LogRel(("%s Interrupts by ICS : %d\n", pThis->szPrf, pThis->uStatIntICS));
6007 LogRel(("%s Interrupts by RDTR: %d\n", pThis->szPrf, pThis->uStatIntRDTR));
6008 LogRel(("%s Interrupts by RDMT: %d\n", pThis->szPrf, pThis->uStatIntRXDMT0));
6009 LogRel(("%s Interrupts by TXQE: %d\n", pThis->szPrf, pThis->uStatIntTXQE));
6010 LogRel(("%s TX int delay asked: %d\n", pThis->szPrf, pThis->uStatTxIDE));
6011 LogRel(("%s TX delayed: %d\n", pThis->szPrf, pThis->uStatTxDelayed));
6012 LogRel(("%s TX delay expired: %d\n", pThis->szPrf, pThis->uStatTxDelayExp));
6013 LogRel(("%s TX no report asked: %d\n", pThis->szPrf, pThis->uStatTxNoRS));
6014 LogRel(("%s TX abs timer expd : %d\n", pThis->szPrf, pThis->uStatTAD));
6015 LogRel(("%s TX int timer expd : %d\n", pThis->szPrf, pThis->uStatTID));
6016 LogRel(("%s RX abs timer expd : %d\n", pThis->szPrf, pThis->uStatRAD));
6017 LogRel(("%s RX int timer expd : %d\n", pThis->szPrf, pThis->uStatRID));
6018 LogRel(("%s TX CTX descriptors: %d\n", pThis->szPrf, pThis->uStatDescCtx));
6019 LogRel(("%s TX DAT descriptors: %d\n", pThis->szPrf, pThis->uStatDescDat));
6020 LogRel(("%s TX LEG descriptors: %d\n", pThis->szPrf, pThis->uStatDescLeg));
6021 LogRel(("%s Received frames : %d\n", pThis->szPrf, pThis->uStatRxFrm));
6022 LogRel(("%s Transmitted frames: %d\n", pThis->szPrf, pThis->uStatTxFrm));
6023 LogRel(("%s TX frames up to 1514: %d\n", pThis->szPrf, pThis->uStatTx1514));
6024 LogRel(("%s TX frames up to 2962: %d\n", pThis->szPrf, pThis->uStatTx2962));
6025 LogRel(("%s TX frames up to 4410: %d\n", pThis->szPrf, pThis->uStatTx4410));
6026 LogRel(("%s TX frames up to 5858: %d\n", pThis->szPrf, pThis->uStatTx5858));
6027 LogRel(("%s TX frames up to 7306: %d\n", pThis->szPrf, pThis->uStatTx7306));
6028 LogRel(("%s TX frames up to 8754: %d\n", pThis->szPrf, pThis->uStatTx8754));
6029 LogRel(("%s TX frames up to 16384: %d\n", pThis->szPrf, pThis->uStatTx16384));
6030 LogRel(("%s TX frames up to 32768: %d\n", pThis->szPrf, pThis->uStatTx32768));
6031 LogRel(("%s Larger TX frames : %d\n", pThis->szPrf, pThis->uStatTxLarge));
6032 LogRel(("%s Max TX Delay : %lld\n", pThis->szPrf, pThis->uStatMaxTxDelay));
6033# endif /* E1K_INT_STATS */
6034}
6035
6036/**
6037 * @callback_method_impl{FNPCIIOREGIONMAP}
6038 */
6039static DECLCALLBACK(int) e1kMap(PPCIDEVICE pPciDev, int iRegion, RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
6040{
6041 PE1KSTATE pThis = PDMINS_2_DATA(pPciDev->pDevIns, E1KSTATE*);
6042 int rc;
6043
6044 switch (enmType)
6045 {
6046 case PCI_ADDRESS_SPACE_IO:
6047 pThis->IOPortBase = (RTIOPORT)GCPhysAddress;
6048 rc = PDMDevHlpIOPortRegister(pPciDev->pDevIns, pThis->IOPortBase, cb, NULL /*pvUser*/,
6049 e1kIOPortOut, e1kIOPortIn, NULL, NULL, "E1000");
6050 if (pThis->fR0Enabled && RT_SUCCESS(rc))
6051 rc = PDMDevHlpIOPortRegisterR0(pPciDev->pDevIns, pThis->IOPortBase, cb, NIL_RTR0PTR /*pvUser*/,
6052 "e1kIOPortOut", "e1kIOPortIn", NULL, NULL, "E1000");
6053 if (pThis->fRCEnabled && RT_SUCCESS(rc))
6054 rc = PDMDevHlpIOPortRegisterRC(pPciDev->pDevIns, pThis->IOPortBase, cb, NIL_RTRCPTR /*pvUser*/,
6055 "e1kIOPortOut", "e1kIOPortIn", NULL, NULL, "E1000");
6056 break;
6057
6058 case PCI_ADDRESS_SPACE_MEM:
6059 /*
6060 * From the spec:
6061 * For registers that should be accessed as 32-bit double words,
6062 * partial writes (less than a 32-bit double word) is ignored.
6063 * Partial reads return all 32 bits of data regardless of the
6064 * byte enables.
6065 */
6066 pThis->addrMMReg = GCPhysAddress; Assert(!(GCPhysAddress & 7));
6067 rc = PDMDevHlpMMIORegister(pPciDev->pDevIns, GCPhysAddress, cb, NULL /*pvUser*/,
6068 IOMMMIO_FLAGS_READ_DWORD | IOMMMIO_FLAGS_WRITE_ONLY_DWORD,
6069 e1kMMIOWrite, e1kMMIORead, "E1000");
6070 if (pThis->fR0Enabled && RT_SUCCESS(rc))
6071 rc = PDMDevHlpMMIORegisterR0(pPciDev->pDevIns, GCPhysAddress, cb, NIL_RTR0PTR /*pvUser*/,
6072 "e1kMMIOWrite", "e1kMMIORead");
6073 if (pThis->fRCEnabled && RT_SUCCESS(rc))
6074 rc = PDMDevHlpMMIORegisterRC(pPciDev->pDevIns, GCPhysAddress, cb, NIL_RTRCPTR /*pvUser*/,
6075 "e1kMMIOWrite", "e1kMMIORead");
6076 break;
6077
6078 default:
6079 /* We should never get here */
6080 AssertMsgFailed(("Invalid PCI address space param in map callback"));
6081 rc = VERR_INTERNAL_ERROR;
6082 break;
6083 }
6084 return rc;
6085}
6086
6087
6088/* -=-=-=-=- PDMINETWORKDOWN -=-=-=-=- */
6089
6090/**
6091 * Check if the device can receive data now.
6092 * This must be called before the pfnRecieve() method is called.
6093 *
6094 * @returns Number of bytes the device can receive.
6095 * @param pInterface Pointer to the interface structure containing the called function pointer.
6096 * @thread EMT
6097 */
6098static int e1kCanReceive(PE1KSTATE pThis)
6099{
6100#ifndef E1K_WITH_RXD_CACHE
6101 size_t cb;
6102
6103 if (RT_UNLIKELY(e1kCsRxEnter(pThis, VERR_SEM_BUSY) != VINF_SUCCESS))
6104 return VERR_NET_NO_BUFFER_SPACE;
6105
6106 if (RT_UNLIKELY(RDLEN == sizeof(E1KRXDESC)))
6107 {
6108 E1KRXDESC desc;
6109 PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns), e1kDescAddr(RDBAH, RDBAL, RDH),
6110 &desc, sizeof(desc));
6111 if (desc.status.fDD)
6112 cb = 0;
6113 else
6114 cb = pThis->u16RxBSize;
6115 }
6116 else if (RDH < RDT)
6117 cb = (RDT - RDH) * pThis->u16RxBSize;
6118 else if (RDH > RDT)
6119 cb = (RDLEN/sizeof(E1KRXDESC) - RDH + RDT) * pThis->u16RxBSize;
6120 else
6121 {
6122 cb = 0;
6123 E1kLogRel(("E1000: OUT of RX descriptors!\n"));
6124 }
6125 E1kLog2(("%s e1kCanReceive: at exit RDH=%d RDT=%d RDLEN=%d u16RxBSize=%d cb=%lu\n",
6126 pThis->szPrf, RDH, RDT, RDLEN, pThis->u16RxBSize, cb));
6127
6128 e1kCsRxLeave(pThis);
6129 return cb > 0 ? VINF_SUCCESS : VERR_NET_NO_BUFFER_SPACE;
6130#else /* E1K_WITH_RXD_CACHE */
6131 int rc = VINF_SUCCESS;
6132
6133 if (RT_UNLIKELY(e1kCsRxEnter(pThis, VERR_SEM_BUSY) != VINF_SUCCESS))
6134 return VERR_NET_NO_BUFFER_SPACE;
6135
6136 if (RT_UNLIKELY(RDLEN == sizeof(E1KRXDESC)))
6137 {
6138 E1KRXDESC desc;
6139 PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns), e1kDescAddr(RDBAH, RDBAL, RDH),
6140 &desc, sizeof(desc));
6141 if (desc.status.fDD)
6142 rc = VERR_NET_NO_BUFFER_SPACE;
6143 }
6144 else if (e1kRxDIsCacheEmpty(pThis) && RDH == RDT)
6145 {
6146 /* Cache is empty, so is the RX ring. */
6147 rc = VERR_NET_NO_BUFFER_SPACE;
6148 }
6149 E1kLog2(("%s e1kCanReceive: at exit in_cache=%d RDH=%d RDT=%d RDLEN=%d"
6150 " u16RxBSize=%d rc=%Rrc\n", pThis->szPrf,
6151 e1kRxDInCache(pThis), RDH, RDT, RDLEN, pThis->u16RxBSize, rc));
6152
6153 e1kCsRxLeave(pThis);
6154 return rc;
6155#endif /* E1K_WITH_RXD_CACHE */
6156}
6157
6158/**
6159 * @interface_method_impl{PDMINETWORKDOWN,pfnWaitReceiveAvail}
6160 */
6161static DECLCALLBACK(int) e1kR3NetworkDown_WaitReceiveAvail(PPDMINETWORKDOWN pInterface, RTMSINTERVAL cMillies)
6162{
6163 PE1KSTATE pThis = RT_FROM_MEMBER(pInterface, E1KSTATE, INetworkDown);
6164 int rc = e1kCanReceive(pThis);
6165
6166 if (RT_SUCCESS(rc))
6167 return VINF_SUCCESS;
6168 if (RT_UNLIKELY(cMillies == 0))
6169 return VERR_NET_NO_BUFFER_SPACE;
6170
6171 rc = VERR_INTERRUPTED;
6172 ASMAtomicXchgBool(&pThis->fMaybeOutOfSpace, true);
6173 STAM_PROFILE_START(&pThis->StatRxOverflow, a);
6174 VMSTATE enmVMState;
6175 while (RT_LIKELY( (enmVMState = PDMDevHlpVMState(pThis->CTX_SUFF(pDevIns))) == VMSTATE_RUNNING
6176 || enmVMState == VMSTATE_RUNNING_LS))
6177 {
6178 int rc2 = e1kCanReceive(pThis);
6179 if (RT_SUCCESS(rc2))
6180 {
6181 rc = VINF_SUCCESS;
6182 break;
6183 }
6184 E1kLogRel(("E1000 e1kR3NetworkDown_WaitReceiveAvail: waiting cMillies=%u...\n", cMillies));
6185 E1kLog(("%s e1kR3NetworkDown_WaitReceiveAvail: waiting cMillies=%u...\n", pThis->szPrf, cMillies));
6186 RTSemEventWait(pThis->hEventMoreRxDescAvail, cMillies);
6187 }
6188 STAM_PROFILE_STOP(&pThis->StatRxOverflow, a);
6189 ASMAtomicXchgBool(&pThis->fMaybeOutOfSpace, false);
6190
6191 return rc;
6192}
6193
6194
6195/**
6196 * Matches the packet addresses against Receive Address table. Looks for
6197 * exact matches only.
6198 *
6199 * @returns true if address matches.
6200 * @param pThis Pointer to the state structure.
6201 * @param pvBuf The ethernet packet.
6202 * @param cb Number of bytes available in the packet.
6203 * @thread EMT
6204 */
6205static bool e1kPerfectMatch(PE1KSTATE pThis, const void *pvBuf)
6206{
6207 for (unsigned i = 0; i < RT_ELEMENTS(pThis->aRecAddr.array); i++)
6208 {
6209 E1KRAELEM* ra = pThis->aRecAddr.array + i;
6210
6211 /* Valid address? */
6212 if (ra->ctl & RA_CTL_AV)
6213 {
6214 Assert((ra->ctl & RA_CTL_AS) < 2);
6215 //unsigned char *pAddr = (unsigned char*)pvBuf + sizeof(ra->addr)*(ra->ctl & RA_CTL_AS);
6216 //E1kLog3(("%s Matching %02x:%02x:%02x:%02x:%02x:%02x against %02x:%02x:%02x:%02x:%02x:%02x...\n",
6217 // pThis->szPrf, pAddr[0], pAddr[1], pAddr[2], pAddr[3], pAddr[4], pAddr[5],
6218 // ra->addr[0], ra->addr[1], ra->addr[2], ra->addr[3], ra->addr[4], ra->addr[5]));
6219 /*
6220 * Address Select:
6221 * 00b = Destination address
6222 * 01b = Source address
6223 * 10b = Reserved
6224 * 11b = Reserved
6225 * Since ethernet header is (DA, SA, len) we can use address
6226 * select as index.
6227 */
6228 if (memcmp((char*)pvBuf + sizeof(ra->addr)*(ra->ctl & RA_CTL_AS),
6229 ra->addr, sizeof(ra->addr)) == 0)
6230 return true;
6231 }
6232 }
6233
6234 return false;
6235}
6236
6237/**
6238 * Matches the packet addresses against Multicast Table Array.
6239 *
6240 * @remarks This is imperfect match since it matches not exact address but
6241 * a subset of addresses.
6242 *
6243 * @returns true if address matches.
6244 * @param pThis Pointer to the state structure.
6245 * @param pvBuf The ethernet packet.
6246 * @param cb Number of bytes available in the packet.
6247 * @thread EMT
6248 */
6249static bool e1kImperfectMatch(PE1KSTATE pThis, const void *pvBuf)
6250{
6251 /* Get bits 32..47 of destination address */
6252 uint16_t u16Bit = ((uint16_t*)pvBuf)[2];
6253
6254 unsigned offset = GET_BITS(RCTL, MO);
6255 /*
6256 * offset means:
6257 * 00b = bits 36..47
6258 * 01b = bits 35..46
6259 * 10b = bits 34..45
6260 * 11b = bits 32..43
6261 */
6262 if (offset < 3)
6263 u16Bit = u16Bit >> (4 - offset);
6264 return ASMBitTest(pThis->auMTA, u16Bit & 0xFFF);
6265}
6266
6267/**
6268 * Determines if the packet is to be delivered to upper layer.
6269 *
6270 * The following filters supported:
6271 * - Exact Unicast/Multicast
6272 * - Promiscuous Unicast/Multicast
6273 * - Multicast
6274 * - VLAN
6275 *
6276 * @returns true if packet is intended for this node.
6277 * @param pThis Pointer to the state structure.
6278 * @param pvBuf The ethernet packet.
6279 * @param cb Number of bytes available in the packet.
6280 * @param pStatus Bit field to store status bits.
6281 * @thread EMT
6282 */
6283static bool e1kAddressFilter(PE1KSTATE pThis, const void *pvBuf, size_t cb, E1KRXDST *pStatus)
6284{
6285 Assert(cb > 14);
6286 /* Assume that we fail to pass exact filter. */
6287 pStatus->fPIF = false;
6288 pStatus->fVP = false;
6289 /* Discard oversized packets */
6290 if (cb > E1K_MAX_RX_PKT_SIZE)
6291 {
6292 E1kLog(("%s ERROR: Incoming packet is too big, cb=%d > max=%d\n",
6293 pThis->szPrf, cb, E1K_MAX_RX_PKT_SIZE));
6294 E1K_INC_CNT32(ROC);
6295 return false;
6296 }
6297 else if (!(RCTL & RCTL_LPE) && cb > 1522)
6298 {
6299 /* When long packet reception is disabled packets over 1522 are discarded */
6300 E1kLog(("%s Discarding incoming packet (LPE=0), cb=%d\n",
6301 pThis->szPrf, cb));
6302 E1K_INC_CNT32(ROC);
6303 return false;
6304 }
6305
6306 uint16_t *u16Ptr = (uint16_t*)pvBuf;
6307 /* Compare TPID with VLAN Ether Type */
6308 if (RT_BE2H_U16(u16Ptr[6]) == VET)
6309 {
6310 pStatus->fVP = true;
6311 /* Is VLAN filtering enabled? */
6312 if (RCTL & RCTL_VFE)
6313 {
6314 /* It is 802.1q packet indeed, let's filter by VID */
6315 if (RCTL & RCTL_CFIEN)
6316 {
6317 E1kLog3(("%s VLAN filter: VLAN=%d CFI=%d RCTL_CFI=%d\n", pThis->szPrf,
6318 E1K_SPEC_VLAN(RT_BE2H_U16(u16Ptr[7])),
6319 E1K_SPEC_CFI(RT_BE2H_U16(u16Ptr[7])),
6320 !!(RCTL & RCTL_CFI)));
6321 if (E1K_SPEC_CFI(RT_BE2H_U16(u16Ptr[7])) != !!(RCTL & RCTL_CFI))
6322 {
6323 E1kLog2(("%s Packet filter: CFIs do not match in packet and RCTL (%d!=%d)\n",
6324 pThis->szPrf, E1K_SPEC_CFI(RT_BE2H_U16(u16Ptr[7])), !!(RCTL & RCTL_CFI)));
6325 return false;
6326 }
6327 }
6328 else
6329 E1kLog3(("%s VLAN filter: VLAN=%d\n", pThis->szPrf,
6330 E1K_SPEC_VLAN(RT_BE2H_U16(u16Ptr[7]))));
6331 if (!ASMBitTest(pThis->auVFTA, E1K_SPEC_VLAN(RT_BE2H_U16(u16Ptr[7]))))
6332 {
6333 E1kLog2(("%s Packet filter: no VLAN match (id=%d)\n",
6334 pThis->szPrf, E1K_SPEC_VLAN(RT_BE2H_U16(u16Ptr[7]))));
6335 return false;
6336 }
6337 }
6338 }
6339 /* Broadcast filtering */
6340 if (e1kIsBroadcast(pvBuf) && (RCTL & RCTL_BAM))
6341 return true;
6342 E1kLog2(("%s Packet filter: not a broadcast\n", pThis->szPrf));
6343 if (e1kIsMulticast(pvBuf))
6344 {
6345 /* Is multicast promiscuous enabled? */
6346 if (RCTL & RCTL_MPE)
6347 return true;
6348 E1kLog2(("%s Packet filter: no promiscuous multicast\n", pThis->szPrf));
6349 /* Try perfect matches first */
6350 if (e1kPerfectMatch(pThis, pvBuf))
6351 {
6352 pStatus->fPIF = true;
6353 return true;
6354 }
6355 E1kLog2(("%s Packet filter: no perfect match\n", pThis->szPrf));
6356 if (e1kImperfectMatch(pThis, pvBuf))
6357 return true;
6358 E1kLog2(("%s Packet filter: no imperfect match\n", pThis->szPrf));
6359 }
6360 else {
6361 /* Is unicast promiscuous enabled? */
6362 if (RCTL & RCTL_UPE)
6363 return true;
6364 E1kLog2(("%s Packet filter: no promiscuous unicast\n", pThis->szPrf));
6365 if (e1kPerfectMatch(pThis, pvBuf))
6366 {
6367 pStatus->fPIF = true;
6368 return true;
6369 }
6370 E1kLog2(("%s Packet filter: no perfect match\n", pThis->szPrf));
6371 }
6372 E1kLog2(("%s Packet filter: packet discarded\n", pThis->szPrf));
6373 return false;
6374}
6375
6376/**
6377 * @interface_method_impl{PDMINETWORKDOWN,pfnReceive}
6378 */
6379static DECLCALLBACK(int) e1kR3NetworkDown_Receive(PPDMINETWORKDOWN pInterface, const void *pvBuf, size_t cb)
6380{
6381 PE1KSTATE pThis = RT_FROM_MEMBER(pInterface, E1KSTATE, INetworkDown);
6382 int rc = VINF_SUCCESS;
6383
6384 /*
6385 * Drop packets if the VM is not running yet/anymore.
6386 */
6387 VMSTATE enmVMState = PDMDevHlpVMState(STATE_TO_DEVINS(pThis));
6388 if ( enmVMState != VMSTATE_RUNNING
6389 && enmVMState != VMSTATE_RUNNING_LS)
6390 {
6391 E1kLog(("%s Dropping incoming packet as VM is not running.\n", pThis->szPrf));
6392 return VINF_SUCCESS;
6393 }
6394
6395 /* Discard incoming packets in locked state */
6396 if (!(RCTL & RCTL_EN) || pThis->fLocked || !(STATUS & STATUS_LU))
6397 {
6398 E1kLog(("%s Dropping incoming packet as receive operation is disabled.\n", pThis->szPrf));
6399 return VINF_SUCCESS;
6400 }
6401
6402 STAM_PROFILE_ADV_START(&pThis->StatReceive, a);
6403
6404 //if (!e1kCsEnter(pThis, RT_SRC_POS))
6405 // return VERR_PERMISSION_DENIED;
6406
6407 e1kPacketDump(pThis, (const uint8_t*)pvBuf, cb, "<-- Incoming");
6408
6409 /* Update stats */
6410 if (RT_LIKELY(e1kCsEnter(pThis, VERR_SEM_BUSY) == VINF_SUCCESS))
6411 {
6412 E1K_INC_CNT32(TPR);
6413 E1K_ADD_CNT64(TORL, TORH, cb < 64? 64 : cb);
6414 e1kCsLeave(pThis);
6415 }
6416 STAM_PROFILE_ADV_START(&pThis->StatReceiveFilter, a);
6417 E1KRXDST status;
6418 RT_ZERO(status);
6419 bool fPassed = e1kAddressFilter(pThis, pvBuf, cb, &status);
6420 STAM_PROFILE_ADV_STOP(&pThis->StatReceiveFilter, a);
6421 if (fPassed)
6422 {
6423 rc = e1kHandleRxPacket(pThis, pvBuf, cb, status);
6424 }
6425 //e1kCsLeave(pThis);
6426 STAM_PROFILE_ADV_STOP(&pThis->StatReceive, a);
6427
6428 return rc;
6429}
6430
6431
6432/* -=-=-=-=- PDMILEDPORTS -=-=-=-=- */
6433
6434/**
6435 * @interface_method_impl{PDMILEDPORTS,pfnQueryStatusLed}
6436 */
6437static DECLCALLBACK(int) e1kR3QueryStatusLed(PPDMILEDPORTS pInterface, unsigned iLUN, PPDMLED *ppLed)
6438{
6439 PE1KSTATE pThis = RT_FROM_MEMBER(pInterface, E1KSTATE, ILeds);
6440 int rc = VERR_PDM_LUN_NOT_FOUND;
6441
6442 if (iLUN == 0)
6443 {
6444 *ppLed = &pThis->led;
6445 rc = VINF_SUCCESS;
6446 }
6447 return rc;
6448}
6449
6450
6451/* -=-=-=-=- PDMINETWORKCONFIG -=-=-=-=- */
6452
6453/**
6454 * @interface_method_impl{PDMINETWORKCONFIG,pfnGetMac}
6455 */
6456static DECLCALLBACK(int) e1kR3GetMac(PPDMINETWORKCONFIG pInterface, PRTMAC pMac)
6457{
6458 PE1KSTATE pThis = RT_FROM_MEMBER(pInterface, E1KSTATE, INetworkConfig);
6459 pThis->eeprom.getMac(pMac);
6460 return VINF_SUCCESS;
6461}
6462
6463/**
6464 * @interface_method_impl{PDMINETWORKCONFIG,pfnGetLinkState}
6465 */
6466static DECLCALLBACK(PDMNETWORKLINKSTATE) e1kR3GetLinkState(PPDMINETWORKCONFIG pInterface)
6467{
6468 PE1KSTATE pThis = RT_FROM_MEMBER(pInterface, E1KSTATE, INetworkConfig);
6469 if (STATUS & STATUS_LU)
6470 return PDMNETWORKLINKSTATE_UP;
6471 return PDMNETWORKLINKSTATE_DOWN;
6472}
6473
6474/**
6475 * @interface_method_impl{PDMINETWORKCONFIG,pfnSetLinkState}
6476 */
6477static DECLCALLBACK(int) e1kR3SetLinkState(PPDMINETWORKCONFIG pInterface, PDMNETWORKLINKSTATE enmState)
6478{
6479 PE1KSTATE pThis = RT_FROM_MEMBER(pInterface, E1KSTATE, INetworkConfig);
6480
6481 E1kLog(("%s e1kR3SetLinkState: enmState=%d\n", pThis->szPrf, enmState));
6482 switch (enmState)
6483 {
6484 case PDMNETWORKLINKSTATE_UP:
6485 pThis->fCableConnected = true;
6486 /* If link was down, bring it up after a while. */
6487 if (!(STATUS & STATUS_LU))
6488 e1kBringLinkUpDelayed(pThis);
6489 break;
6490 case PDMNETWORKLINKSTATE_DOWN:
6491 pThis->fCableConnected = false;
6492 /* If link was up, bring it down. */
6493 if (STATUS & STATUS_LU)
6494 e1kR3LinkDown(pThis);
6495 break;
6496 case PDMNETWORKLINKSTATE_DOWN_RESUME:
6497 /*
6498 * There is not much sense in bringing down the link if it has not come up yet.
6499 * If it is up though, we bring it down temporarely, then bring it up again.
6500 */
6501 if (STATUS & STATUS_LU)
6502 e1kR3LinkDownTemp(pThis);
6503 break;
6504 default:
6505 ;
6506 }
6507 return VINF_SUCCESS;
6508}
6509
6510
6511/* -=-=-=-=- PDMIBASE -=-=-=-=- */
6512
6513/**
6514 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
6515 */
6516static DECLCALLBACK(void *) e1kR3QueryInterface(struct PDMIBASE *pInterface, const char *pszIID)
6517{
6518 PE1KSTATE pThis = RT_FROM_MEMBER(pInterface, E1KSTATE, IBase);
6519 Assert(&pThis->IBase == pInterface);
6520
6521 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase);
6522 PDMIBASE_RETURN_INTERFACE(pszIID, PDMINETWORKDOWN, &pThis->INetworkDown);
6523 PDMIBASE_RETURN_INTERFACE(pszIID, PDMINETWORKCONFIG, &pThis->INetworkConfig);
6524 PDMIBASE_RETURN_INTERFACE(pszIID, PDMILEDPORTS, &pThis->ILeds);
6525 return NULL;
6526}
6527
6528
6529/* -=-=-=-=- Saved State -=-=-=-=- */
6530
6531/**
6532 * Saves the configuration.
6533 *
6534 * @param pThis The E1K state.
6535 * @param pSSM The handle to the saved state.
6536 */
6537static void e1kSaveConfig(PE1KSTATE pThis, PSSMHANDLE pSSM)
6538{
6539 SSMR3PutMem(pSSM, &pThis->macConfigured, sizeof(pThis->macConfigured));
6540 SSMR3PutU32(pSSM, pThis->eChip);
6541}
6542
6543/**
6544 * @callback_method_impl{FNSSMDEVLIVEEXEC,Save basic configuration.}
6545 */
6546static DECLCALLBACK(int) e1kLiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
6547{
6548 PE1KSTATE pThis = PDMINS_2_DATA(pDevIns, E1KSTATE*);
6549 e1kSaveConfig(pThis, pSSM);
6550 return VINF_SSM_DONT_CALL_AGAIN;
6551}
6552
6553/**
6554 * @callback_method_impl{FNSSMDEVSAVEPREP,Synchronize.}
6555 */
6556static DECLCALLBACK(int) e1kSavePrep(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
6557{
6558 PE1KSTATE pThis = PDMINS_2_DATA(pDevIns, E1KSTATE*);
6559
6560 int rc = e1kCsEnter(pThis, VERR_SEM_BUSY);
6561 if (RT_UNLIKELY(rc != VINF_SUCCESS))
6562 return rc;
6563 e1kCsLeave(pThis);
6564 return VINF_SUCCESS;
6565#if 0
6566 /* 1) Prevent all threads from modifying the state and memory */
6567 //pThis->fLocked = true;
6568 /* 2) Cancel all timers */
6569#ifdef E1K_TX_DELAY
6570 e1kCancelTimer(pThis, pThis->CTX_SUFF(pTXDTimer));
6571#endif /* E1K_TX_DELAY */
6572#ifdef E1K_USE_TX_TIMERS
6573 e1kCancelTimer(pThis, pThis->CTX_SUFF(pTIDTimer));
6574#ifndef E1K_NO_TAD
6575 e1kCancelTimer(pThis, pThis->CTX_SUFF(pTADTimer));
6576#endif /* E1K_NO_TAD */
6577#endif /* E1K_USE_TX_TIMERS */
6578#ifdef E1K_USE_RX_TIMERS
6579 e1kCancelTimer(pThis, pThis->CTX_SUFF(pRIDTimer));
6580 e1kCancelTimer(pThis, pThis->CTX_SUFF(pRADTimer));
6581#endif /* E1K_USE_RX_TIMERS */
6582 e1kCancelTimer(pThis, pThis->CTX_SUFF(pIntTimer));
6583 /* 3) Did I forget anything? */
6584 E1kLog(("%s Locked\n", pThis->szPrf));
6585 return VINF_SUCCESS;
6586#endif
6587}
6588
6589/**
6590 * @callback_method_impl{FNSSMDEVSAVEEXEC}
6591 */
6592static DECLCALLBACK(int) e1kSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
6593{
6594 PE1KSTATE pThis = PDMINS_2_DATA(pDevIns, E1KSTATE*);
6595
6596 e1kSaveConfig(pThis, pSSM);
6597 pThis->eeprom.save(pSSM);
6598 e1kDumpState(pThis);
6599 SSMR3PutMem(pSSM, pThis->auRegs, sizeof(pThis->auRegs));
6600 SSMR3PutBool(pSSM, pThis->fIntRaised);
6601 Phy::saveState(pSSM, &pThis->phy);
6602 SSMR3PutU32(pSSM, pThis->uSelectedReg);
6603 SSMR3PutMem(pSSM, pThis->auMTA, sizeof(pThis->auMTA));
6604 SSMR3PutMem(pSSM, &pThis->aRecAddr, sizeof(pThis->aRecAddr));
6605 SSMR3PutMem(pSSM, pThis->auVFTA, sizeof(pThis->auVFTA));
6606 SSMR3PutU64(pSSM, pThis->u64AckedAt);
6607 SSMR3PutU16(pSSM, pThis->u16RxBSize);
6608 //SSMR3PutBool(pSSM, pThis->fDelayInts);
6609 //SSMR3PutBool(pSSM, pThis->fIntMaskUsed);
6610 SSMR3PutU16(pSSM, pThis->u16TxPktLen);
6611/** @todo State wrt to the TSE buffer is incomplete, so little point in
6612 * saving this actually. */
6613 SSMR3PutMem(pSSM, pThis->aTxPacketFallback, pThis->u16TxPktLen);
6614 SSMR3PutBool(pSSM, pThis->fIPcsum);
6615 SSMR3PutBool(pSSM, pThis->fTCPcsum);
6616 SSMR3PutMem(pSSM, &pThis->contextTSE, sizeof(pThis->contextTSE));
6617 SSMR3PutMem(pSSM, &pThis->contextNormal, sizeof(pThis->contextNormal));
6618 SSMR3PutBool(pSSM, pThis->fVTag);
6619 SSMR3PutU16(pSSM, pThis->u16VTagTCI);
6620#ifdef E1K_WITH_TXD_CACHE
6621#if 0
6622 SSMR3PutU8(pSSM, pThis->nTxDFetched);
6623 SSMR3PutMem(pSSM, pThis->aTxDescriptors,
6624 pThis->nTxDFetched * sizeof(pThis->aTxDescriptors[0]));
6625#else
6626 /*
6627 * There is no point in storing TX descriptor cache entries as we can simply
6628 * fetch them again. Moreover, normally the cache is always empty when we
6629 * save the state. Store zero entries for compatibility.
6630 */
6631 SSMR3PutU8(pSSM, 0);
6632#endif
6633#endif /* E1K_WITH_TXD_CACHE */
6634/**@todo GSO requires some more state here. */
6635 E1kLog(("%s State has been saved\n", pThis->szPrf));
6636 return VINF_SUCCESS;
6637}
6638
6639#if 0
6640/**
6641 * @callback_method_impl{FNSSMDEVSAVEDONE}
6642 */
6643static DECLCALLBACK(int) e1kSaveDone(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
6644{
6645 PE1KSTATE pThis = PDMINS_2_DATA(pDevIns, E1KSTATE*);
6646
6647 /* If VM is being powered off unlocking will result in assertions in PGM */
6648 if (PDMDevHlpGetVM(pDevIns)->enmVMState == VMSTATE_RUNNING)
6649 pThis->fLocked = false;
6650 else
6651 E1kLog(("%s VM is not running -- remain locked\n", pThis->szPrf));
6652 E1kLog(("%s Unlocked\n", pThis->szPrf));
6653 return VINF_SUCCESS;
6654}
6655#endif
6656
6657/**
6658 * @callback_method_impl{FNSSMDEVLOADPREP,Synchronize.}
6659 */
6660static DECLCALLBACK(int) e1kLoadPrep(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
6661{
6662 PE1KSTATE pThis = PDMINS_2_DATA(pDevIns, E1KSTATE*);
6663
6664 int rc = e1kCsEnter(pThis, VERR_SEM_BUSY);
6665 if (RT_UNLIKELY(rc != VINF_SUCCESS))
6666 return rc;
6667 e1kCsLeave(pThis);
6668 return VINF_SUCCESS;
6669}
6670
6671/**
6672 * @callback_method_impl{FNSSMDEVLOADEXEC}
6673 */
6674static DECLCALLBACK(int) e1kLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
6675{
6676 PE1KSTATE pThis = PDMINS_2_DATA(pDevIns, E1KSTATE*);
6677 int rc;
6678
6679 if ( uVersion != E1K_SAVEDSTATE_VERSION
6680#ifdef E1K_WITH_TXD_CACHE
6681 && uVersion != E1K_SAVEDSTATE_VERSION_VBOX_42_VTAG
6682#endif /* E1K_WITH_TXD_CACHE */
6683 && uVersion != E1K_SAVEDSTATE_VERSION_VBOX_41
6684 && uVersion != E1K_SAVEDSTATE_VERSION_VBOX_30)
6685 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
6686
6687 if ( uVersion > E1K_SAVEDSTATE_VERSION_VBOX_30
6688 || uPass != SSM_PASS_FINAL)
6689 {
6690 /* config checks */
6691 RTMAC macConfigured;
6692 rc = SSMR3GetMem(pSSM, &macConfigured, sizeof(macConfigured));
6693 AssertRCReturn(rc, rc);
6694 if ( memcmp(&macConfigured, &pThis->macConfigured, sizeof(macConfigured))
6695 && (uPass == 0 || !PDMDevHlpVMTeleportedAndNotFullyResumedYet(pDevIns)) )
6696 LogRel(("%s: The mac address differs: config=%RTmac saved=%RTmac\n", pThis->szPrf, &pThis->macConfigured, &macConfigured));
6697
6698 E1KCHIP eChip;
6699 rc = SSMR3GetU32(pSSM, &eChip);
6700 AssertRCReturn(rc, rc);
6701 if (eChip != pThis->eChip)
6702 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("The chip type differs: config=%u saved=%u"), pThis->eChip, eChip);
6703 }
6704
6705 if (uPass == SSM_PASS_FINAL)
6706 {
6707 if (uVersion > E1K_SAVEDSTATE_VERSION_VBOX_30)
6708 {
6709 rc = pThis->eeprom.load(pSSM);
6710 AssertRCReturn(rc, rc);
6711 }
6712 /* the state */
6713 SSMR3GetMem(pSSM, &pThis->auRegs, sizeof(pThis->auRegs));
6714 SSMR3GetBool(pSSM, &pThis->fIntRaised);
6715 /** @todo: PHY could be made a separate device with its own versioning */
6716 Phy::loadState(pSSM, &pThis->phy);
6717 SSMR3GetU32(pSSM, &pThis->uSelectedReg);
6718 SSMR3GetMem(pSSM, &pThis->auMTA, sizeof(pThis->auMTA));
6719 SSMR3GetMem(pSSM, &pThis->aRecAddr, sizeof(pThis->aRecAddr));
6720 SSMR3GetMem(pSSM, &pThis->auVFTA, sizeof(pThis->auVFTA));
6721 SSMR3GetU64(pSSM, &pThis->u64AckedAt);
6722 SSMR3GetU16(pSSM, &pThis->u16RxBSize);
6723 //SSMR3GetBool(pSSM, pThis->fDelayInts);
6724 //SSMR3GetBool(pSSM, pThis->fIntMaskUsed);
6725 SSMR3GetU16(pSSM, &pThis->u16TxPktLen);
6726 SSMR3GetMem(pSSM, &pThis->aTxPacketFallback[0], pThis->u16TxPktLen);
6727 SSMR3GetBool(pSSM, &pThis->fIPcsum);
6728 SSMR3GetBool(pSSM, &pThis->fTCPcsum);
6729 SSMR3GetMem(pSSM, &pThis->contextTSE, sizeof(pThis->contextTSE));
6730 rc = SSMR3GetMem(pSSM, &pThis->contextNormal, sizeof(pThis->contextNormal));
6731 AssertRCReturn(rc, rc);
6732 if (uVersion > E1K_SAVEDSTATE_VERSION_VBOX_41)
6733 {
6734 SSMR3GetBool(pSSM, &pThis->fVTag);
6735 rc = SSMR3GetU16(pSSM, &pThis->u16VTagTCI);
6736 AssertRCReturn(rc, rc);
6737 }
6738 else
6739 {
6740 pThis->fVTag = false;
6741 pThis->u16VTagTCI = 0;
6742 }
6743#ifdef E1K_WITH_TXD_CACHE
6744 if (uVersion > E1K_SAVEDSTATE_VERSION_VBOX_42_VTAG)
6745 {
6746 rc = SSMR3GetU8(pSSM, &pThis->nTxDFetched);
6747 AssertRCReturn(rc, rc);
6748 if (pThis->nTxDFetched)
6749 SSMR3GetMem(pSSM, pThis->aTxDescriptors,
6750 pThis->nTxDFetched * sizeof(pThis->aTxDescriptors[0]));
6751 }
6752 else
6753 pThis->nTxDFetched = 0;
6754 /*
6755 * @todo: Perhaps we should not store TXD cache as the entries can be
6756 * simply fetched again from guest's memory. Or can't they?
6757 */
6758#endif /* E1K_WITH_TXD_CACHE */
6759#ifdef E1K_WITH_RXD_CACHE
6760 /*
6761 * There is no point in storing the RX descriptor cache in the saved
6762 * state, we just need to make sure it is empty.
6763 */
6764 pThis->iRxDCurrent = pThis->nRxDFetched = 0;
6765#endif /* E1K_WITH_RXD_CACHE */
6766 /* derived state */
6767 e1kSetupGsoCtx(&pThis->GsoCtx, &pThis->contextTSE);
6768
6769 E1kLog(("%s State has been restored\n", pThis->szPrf));
6770 e1kDumpState(pThis);
6771 }
6772 return VINF_SUCCESS;
6773}
6774
6775/**
6776 * @callback_method_impl{FNSSMDEVLOADDONE, Link status adjustments after loading.}
6777 */
6778static DECLCALLBACK(int) e1kLoadDone(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
6779{
6780 PE1KSTATE pThis = PDMINS_2_DATA(pDevIns, E1KSTATE*);
6781
6782 /* Update promiscuous mode */
6783 if (pThis->pDrvR3)
6784 pThis->pDrvR3->pfnSetPromiscuousMode(pThis->pDrvR3,
6785 !!(RCTL & (RCTL_UPE | RCTL_MPE)));
6786
6787 /*
6788 * Force the link down here, since PDMNETWORKLINKSTATE_DOWN_RESUME is never
6789 * passed to us. We go through all this stuff if the link was up and we
6790 * wasn't teleported.
6791 */
6792 if ( (STATUS & STATUS_LU)
6793 && !PDMDevHlpVMTeleportedAndNotFullyResumedYet(pDevIns)
6794 && pThis->cMsLinkUpDelay)
6795 {
6796 e1kR3LinkDownTemp(pThis);
6797 }
6798 return VINF_SUCCESS;
6799}
6800
6801
6802
6803/* -=-=-=-=- Debug Info + Log Types -=-=-=-=- */
6804
6805/**
6806 * @callback_method_impl{FNRTSTRFORMATTYPE}
6807 */
6808static DECLCALLBACK(size_t) e1kFmtRxDesc(PFNRTSTROUTPUT pfnOutput,
6809 void *pvArgOutput,
6810 const char *pszType,
6811 void const *pvValue,
6812 int cchWidth,
6813 int cchPrecision,
6814 unsigned fFlags,
6815 void *pvUser)
6816{
6817 AssertReturn(strcmp(pszType, "e1krxd") == 0, 0);
6818 E1KRXDESC* pDesc = (E1KRXDESC*)pvValue;
6819 if (!pDesc)
6820 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "NULL_RXD");
6821
6822 size_t cbPrintf = 0;
6823 cbPrintf += RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "Address=%16LX Length=%04X Csum=%04X\n",
6824 pDesc->u64BufAddr, pDesc->u16Length, pDesc->u16Checksum);
6825 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",
6826 pDesc->status.fPIF ? "PIF" : "pif",
6827 pDesc->status.fIPCS ? "IPCS" : "ipcs",
6828 pDesc->status.fTCPCS ? "TCPCS" : "tcpcs",
6829 pDesc->status.fVP ? "VP" : "vp",
6830 pDesc->status.fIXSM ? "IXSM" : "ixsm",
6831 pDesc->status.fEOP ? "EOP" : "eop",
6832 pDesc->status.fDD ? "DD" : "dd",
6833 pDesc->status.fRXE ? "RXE" : "rxe",
6834 pDesc->status.fIPE ? "IPE" : "ipe",
6835 pDesc->status.fTCPE ? "TCPE" : "tcpe",
6836 pDesc->status.fCE ? "CE" : "ce",
6837 E1K_SPEC_CFI(pDesc->status.u16Special) ? "CFI" :"cfi",
6838 E1K_SPEC_VLAN(pDesc->status.u16Special),
6839 E1K_SPEC_PRI(pDesc->status.u16Special));
6840 return cbPrintf;
6841}
6842
6843/**
6844 * @callback_method_impl{FNRTSTRFORMATTYPE}
6845 */
6846static DECLCALLBACK(size_t) e1kFmtTxDesc(PFNRTSTROUTPUT pfnOutput,
6847 void *pvArgOutput,
6848 const char *pszType,
6849 void const *pvValue,
6850 int cchWidth,
6851 int cchPrecision,
6852 unsigned fFlags,
6853 void *pvUser)
6854{
6855 AssertReturn(strcmp(pszType, "e1ktxd") == 0, 0);
6856 E1KTXDESC* pDesc = (E1KTXDESC*)pvValue;
6857 if (!pDesc)
6858 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "NULL_TXD");
6859
6860 size_t cbPrintf = 0;
6861 switch (e1kGetDescType(pDesc))
6862 {
6863 case E1K_DTYP_CONTEXT:
6864 cbPrintf += RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "Type=Context\n"
6865 " IPCSS=%02X IPCSO=%02X IPCSE=%04X TUCSS=%02X TUCSO=%02X TUCSE=%04X\n"
6866 " TUCMD:%s%s%s %s %s PAYLEN=%04x HDRLEN=%04x MSS=%04x STA: %s",
6867 pDesc->context.ip.u8CSS, pDesc->context.ip.u8CSO, pDesc->context.ip.u16CSE,
6868 pDesc->context.tu.u8CSS, pDesc->context.tu.u8CSO, pDesc->context.tu.u16CSE,
6869 pDesc->context.dw2.fIDE ? " IDE":"",
6870 pDesc->context.dw2.fRS ? " RS" :"",
6871 pDesc->context.dw2.fTSE ? " TSE":"",
6872 pDesc->context.dw2.fIP ? "IPv4":"IPv6",
6873 pDesc->context.dw2.fTCP ? "TCP":"UDP",
6874 pDesc->context.dw2.u20PAYLEN,
6875 pDesc->context.dw3.u8HDRLEN,
6876 pDesc->context.dw3.u16MSS,
6877 pDesc->context.dw3.fDD?"DD":"");
6878 break;
6879 case E1K_DTYP_DATA:
6880 cbPrintf += RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "Type=Data Address=%16LX DTALEN=%05X\n"
6881 " DCMD:%s%s%s%s%s%s%s STA:%s%s%s POPTS:%s%s SPECIAL:%s VLAN=%03x PRI=%x",
6882 pDesc->data.u64BufAddr,
6883 pDesc->data.cmd.u20DTALEN,
6884 pDesc->data.cmd.fIDE ? " IDE" :"",
6885 pDesc->data.cmd.fVLE ? " VLE" :"",
6886 pDesc->data.cmd.fRPS ? " RPS" :"",
6887 pDesc->data.cmd.fRS ? " RS" :"",
6888 pDesc->data.cmd.fTSE ? " TSE" :"",
6889 pDesc->data.cmd.fIFCS? " IFCS":"",
6890 pDesc->data.cmd.fEOP ? " EOP" :"",
6891 pDesc->data.dw3.fDD ? " DD" :"",
6892 pDesc->data.dw3.fEC ? " EC" :"",
6893 pDesc->data.dw3.fLC ? " LC" :"",
6894 pDesc->data.dw3.fTXSM? " TXSM":"",
6895 pDesc->data.dw3.fIXSM? " IXSM":"",
6896 E1K_SPEC_CFI(pDesc->data.dw3.u16Special) ? "CFI" :"cfi",
6897 E1K_SPEC_VLAN(pDesc->data.dw3.u16Special),
6898 E1K_SPEC_PRI(pDesc->data.dw3.u16Special));
6899 break;
6900 case E1K_DTYP_LEGACY:
6901 cbPrintf += RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "Type=Legacy Address=%16LX DTALEN=%05X\n"
6902 " CMD:%s%s%s%s%s%s%s STA:%s%s%s CSO=%02x CSS=%02x SPECIAL:%s VLAN=%03x PRI=%x",
6903 pDesc->data.u64BufAddr,
6904 pDesc->legacy.cmd.u16Length,
6905 pDesc->legacy.cmd.fIDE ? " IDE" :"",
6906 pDesc->legacy.cmd.fVLE ? " VLE" :"",
6907 pDesc->legacy.cmd.fRPS ? " RPS" :"",
6908 pDesc->legacy.cmd.fRS ? " RS" :"",
6909 pDesc->legacy.cmd.fIC ? " IC" :"",
6910 pDesc->legacy.cmd.fIFCS? " IFCS":"",
6911 pDesc->legacy.cmd.fEOP ? " EOP" :"",
6912 pDesc->legacy.dw3.fDD ? " DD" :"",
6913 pDesc->legacy.dw3.fEC ? " EC" :"",
6914 pDesc->legacy.dw3.fLC ? " LC" :"",
6915 pDesc->legacy.cmd.u8CSO,
6916 pDesc->legacy.dw3.u8CSS,
6917 E1K_SPEC_CFI(pDesc->legacy.dw3.u16Special) ? "CFI" :"cfi",
6918 E1K_SPEC_VLAN(pDesc->legacy.dw3.u16Special),
6919 E1K_SPEC_PRI(pDesc->legacy.dw3.u16Special));
6920 break;
6921 default:
6922 cbPrintf += RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "Invalid Transmit Descriptor");
6923 break;
6924 }
6925
6926 return cbPrintf;
6927}
6928
6929/** Initializes debug helpers (logging format types). */
6930static int e1kInitDebugHelpers(void)
6931{
6932 int rc = VINF_SUCCESS;
6933 static bool s_fHelpersRegistered = false;
6934 if (!s_fHelpersRegistered)
6935 {
6936 s_fHelpersRegistered = true;
6937 rc = RTStrFormatTypeRegister("e1krxd", e1kFmtRxDesc, NULL);
6938 AssertRCReturn(rc, rc);
6939 rc = RTStrFormatTypeRegister("e1ktxd", e1kFmtTxDesc, NULL);
6940 AssertRCReturn(rc, rc);
6941 }
6942 return rc;
6943}
6944
6945/**
6946 * Status info callback.
6947 *
6948 * @param pDevIns The device instance.
6949 * @param pHlp The output helpers.
6950 * @param pszArgs The arguments.
6951 */
6952static DECLCALLBACK(void) e1kInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
6953{
6954 PE1KSTATE pThis = PDMINS_2_DATA(pDevIns, E1KSTATE*);
6955 unsigned i;
6956 // bool fRcvRing = false;
6957 // bool fXmtRing = false;
6958
6959 /*
6960 * Parse args.
6961 if (pszArgs)
6962 {
6963 fRcvRing = strstr(pszArgs, "verbose") || strstr(pszArgs, "rcv");
6964 fXmtRing = strstr(pszArgs, "verbose") || strstr(pszArgs, "xmt");
6965 }
6966 */
6967
6968 /*
6969 * Show info.
6970 */
6971 pHlp->pfnPrintf(pHlp, "E1000 #%d: port=%RTiop mmio=%RGp mac-cfg=%RTmac %s%s%s\n",
6972 pDevIns->iInstance, pThis->IOPortBase, pThis->addrMMReg,
6973 &pThis->macConfigured, g_Chips[pThis->eChip].pcszName,
6974 pThis->fRCEnabled ? " GC" : "", pThis->fR0Enabled ? " R0" : "");
6975
6976 e1kCsEnter(pThis, VERR_INTERNAL_ERROR); /* Not sure why but PCNet does it */
6977
6978 for (i = 0; i < E1K_NUM_OF_32BIT_REGS; ++i)
6979 pHlp->pfnPrintf(pHlp, "%8.8s = %08x\n", g_aE1kRegMap[i].abbrev, pThis->auRegs[i]);
6980
6981 for (i = 0; i < RT_ELEMENTS(pThis->aRecAddr.array); i++)
6982 {
6983 E1KRAELEM* ra = pThis->aRecAddr.array + i;
6984 if (ra->ctl & RA_CTL_AV)
6985 {
6986 const char *pcszTmp;
6987 switch (ra->ctl & RA_CTL_AS)
6988 {
6989 case 0: pcszTmp = "DST"; break;
6990 case 1: pcszTmp = "SRC"; break;
6991 default: pcszTmp = "reserved";
6992 }
6993 pHlp->pfnPrintf(pHlp, "RA%02d: %s %RTmac\n", i, pcszTmp, ra->addr);
6994 }
6995 }
6996 unsigned cDescs = RDLEN / sizeof(E1KRXDESC);
6997 uint32_t rdh = RDH;
6998 pHlp->pfnPrintf(pHlp, "\n-- Receive Descriptors (%d total) --\n", cDescs);
6999 for (i = 0; i < cDescs; ++i)
7000 {
7001 E1KRXDESC desc;
7002 PDMDevHlpPhysRead(pDevIns, e1kDescAddr(RDBAH, RDBAL, i),
7003 &desc, sizeof(desc));
7004 if (i == rdh)
7005 pHlp->pfnPrintf(pHlp, ">>> ");
7006 pHlp->pfnPrintf(pHlp, "%RGp: %R[e1krxd]\n", e1kDescAddr(RDBAH, RDBAL, i), &desc);
7007 }
7008#ifdef E1K_WITH_RXD_CACHE
7009 pHlp->pfnPrintf(pHlp, "\n-- Receive Descriptors in Cache (at %d (RDH %d)/ fetched %d / max %d) --\n",
7010 pThis->iRxDCurrent, RDH, pThis->nRxDFetched, E1K_RXD_CACHE_SIZE);
7011 if (rdh > pThis->iRxDCurrent)
7012 rdh -= pThis->iRxDCurrent;
7013 else
7014 rdh = cDescs + rdh - pThis->iRxDCurrent;
7015 for (i = 0; i < pThis->nRxDFetched; ++i)
7016 {
7017 if (i == pThis->iRxDCurrent)
7018 pHlp->pfnPrintf(pHlp, ">>> ");
7019 pHlp->pfnPrintf(pHlp, "%RGp: %R[e1krxd]\n",
7020 e1kDescAddr(RDBAH, RDBAL, rdh++ % cDescs),
7021 &pThis->aRxDescriptors[i]);
7022 }
7023#endif /* E1K_WITH_RXD_CACHE */
7024
7025 cDescs = TDLEN / sizeof(E1KTXDESC);
7026 uint32_t tdh = TDH;
7027 pHlp->pfnPrintf(pHlp, "\n-- Transmit Descriptors (%d total) --\n", cDescs);
7028 for (i = 0; i < cDescs; ++i)
7029 {
7030 E1KTXDESC desc;
7031 PDMDevHlpPhysRead(pDevIns, e1kDescAddr(TDBAH, TDBAL, i),
7032 &desc, sizeof(desc));
7033 if (i == tdh)
7034 pHlp->pfnPrintf(pHlp, ">>> ");
7035 pHlp->pfnPrintf(pHlp, "%RGp: %R[e1ktxd]\n", e1kDescAddr(TDBAH, TDBAL, i), &desc);
7036 }
7037#ifdef E1K_WITH_TXD_CACHE
7038 pHlp->pfnPrintf(pHlp, "\n-- Transmit Descriptors in Cache (at %d (TDH %d)/ fetched %d / max %d) --\n",
7039 pThis->iTxDCurrent, TDH, pThis->nTxDFetched, E1K_TXD_CACHE_SIZE);
7040 if (tdh > pThis->iTxDCurrent)
7041 tdh -= pThis->iTxDCurrent;
7042 else
7043 tdh = cDescs + tdh - pThis->iTxDCurrent;
7044 for (i = 0; i < pThis->nTxDFetched; ++i)
7045 {
7046 if (i == pThis->iTxDCurrent)
7047 pHlp->pfnPrintf(pHlp, ">>> ");
7048 pHlp->pfnPrintf(pHlp, "%RGp: %R[e1ktxd]\n",
7049 e1kDescAddr(TDBAH, TDBAL, tdh++ % cDescs),
7050 &pThis->aTxDescriptors[i]);
7051 }
7052#endif /* E1K_WITH_TXD_CACHE */
7053
7054
7055#ifdef E1K_INT_STATS
7056 pHlp->pfnPrintf(pHlp, "Interrupt attempts: %d\n", pThis->uStatIntTry);
7057 pHlp->pfnPrintf(pHlp, "Interrupts raised : %d\n", pThis->uStatInt);
7058 pHlp->pfnPrintf(pHlp, "Interrupts lowered: %d\n", pThis->uStatIntLower);
7059 pHlp->pfnPrintf(pHlp, "Interrupts delayed: %d\n", pThis->uStatIntDly);
7060 pHlp->pfnPrintf(pHlp, "Disabled delayed: %d\n", pThis->uStatDisDly);
7061 pHlp->pfnPrintf(pHlp, "Interrupts skipped: %d\n", pThis->uStatIntSkip);
7062 pHlp->pfnPrintf(pHlp, "Masked interrupts : %d\n", pThis->uStatIntMasked);
7063 pHlp->pfnPrintf(pHlp, "Early interrupts : %d\n", pThis->uStatIntEarly);
7064 pHlp->pfnPrintf(pHlp, "Late interrupts : %d\n", pThis->uStatIntLate);
7065 pHlp->pfnPrintf(pHlp, "Lost interrupts : %d\n", pThis->iStatIntLost);
7066 pHlp->pfnPrintf(pHlp, "Interrupts by RX : %d\n", pThis->uStatIntRx);
7067 pHlp->pfnPrintf(pHlp, "Interrupts by TX : %d\n", pThis->uStatIntTx);
7068 pHlp->pfnPrintf(pHlp, "Interrupts by ICS : %d\n", pThis->uStatIntICS);
7069 pHlp->pfnPrintf(pHlp, "Interrupts by RDTR: %d\n", pThis->uStatIntRDTR);
7070 pHlp->pfnPrintf(pHlp, "Interrupts by RDMT: %d\n", pThis->uStatIntRXDMT0);
7071 pHlp->pfnPrintf(pHlp, "Interrupts by TXQE: %d\n", pThis->uStatIntTXQE);
7072 pHlp->pfnPrintf(pHlp, "TX int delay asked: %d\n", pThis->uStatTxIDE);
7073 pHlp->pfnPrintf(pHlp, "TX delayed: %d\n", pThis->uStatTxDelayed);
7074 pHlp->pfnPrintf(pHlp, "TX delayed expired: %d\n", pThis->uStatTxDelayExp);
7075 pHlp->pfnPrintf(pHlp, "TX no report asked: %d\n", pThis->uStatTxNoRS);
7076 pHlp->pfnPrintf(pHlp, "TX abs timer expd : %d\n", pThis->uStatTAD);
7077 pHlp->pfnPrintf(pHlp, "TX int timer expd : %d\n", pThis->uStatTID);
7078 pHlp->pfnPrintf(pHlp, "RX abs timer expd : %d\n", pThis->uStatRAD);
7079 pHlp->pfnPrintf(pHlp, "RX int timer expd : %d\n", pThis->uStatRID);
7080 pHlp->pfnPrintf(pHlp, "TX CTX descriptors: %d\n", pThis->uStatDescCtx);
7081 pHlp->pfnPrintf(pHlp, "TX DAT descriptors: %d\n", pThis->uStatDescDat);
7082 pHlp->pfnPrintf(pHlp, "TX LEG descriptors: %d\n", pThis->uStatDescLeg);
7083 pHlp->pfnPrintf(pHlp, "Received frames : %d\n", pThis->uStatRxFrm);
7084 pHlp->pfnPrintf(pHlp, "Transmitted frames: %d\n", pThis->uStatTxFrm);
7085 pHlp->pfnPrintf(pHlp, "TX frames up to 1514: %d\n", pThis->uStatTx1514);
7086 pHlp->pfnPrintf(pHlp, "TX frames up to 2962: %d\n", pThis->uStatTx2962);
7087 pHlp->pfnPrintf(pHlp, "TX frames up to 4410: %d\n", pThis->uStatTx4410);
7088 pHlp->pfnPrintf(pHlp, "TX frames up to 5858: %d\n", pThis->uStatTx5858);
7089 pHlp->pfnPrintf(pHlp, "TX frames up to 7306: %d\n", pThis->uStatTx7306);
7090 pHlp->pfnPrintf(pHlp, "TX frames up to 8754: %d\n", pThis->uStatTx8754);
7091 pHlp->pfnPrintf(pHlp, "TX frames up to 16384: %d\n", pThis->uStatTx16384);
7092 pHlp->pfnPrintf(pHlp, "TX frames up to 32768: %d\n", pThis->uStatTx32768);
7093 pHlp->pfnPrintf(pHlp, "Larger TX frames : %d\n", pThis->uStatTxLarge);
7094#endif /* E1K_INT_STATS */
7095
7096 e1kCsLeave(pThis);
7097}
7098
7099
7100
7101/* -=-=-=-=- PDMDEVREG -=-=-=-=- */
7102
7103/**
7104 * Detach notification.
7105 *
7106 * One port on the network card has been disconnected from the network.
7107 *
7108 * @param pDevIns The device instance.
7109 * @param iLUN The logical unit which is being detached.
7110 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
7111 */
7112static DECLCALLBACK(void) e1kR3Detach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
7113{
7114 PE1KSTATE pThis = PDMINS_2_DATA(pDevIns, E1KSTATE*);
7115 Log(("%s e1kR3Detach:\n", pThis->szPrf));
7116
7117 AssertLogRelReturnVoid(iLUN == 0);
7118
7119 PDMCritSectEnter(&pThis->cs, VERR_SEM_BUSY);
7120
7121 /** @todo: r=pritesh still need to check if i missed
7122 * to clean something in this function
7123 */
7124
7125 /*
7126 * Zero some important members.
7127 */
7128 pThis->pDrvBase = NULL;
7129 pThis->pDrvR3 = NULL;
7130 pThis->pDrvR0 = NIL_RTR0PTR;
7131 pThis->pDrvRC = NIL_RTRCPTR;
7132
7133 PDMCritSectLeave(&pThis->cs);
7134}
7135
7136/**
7137 * Attach the Network attachment.
7138 *
7139 * One port on the network card has been connected to a network.
7140 *
7141 * @returns VBox status code.
7142 * @param pDevIns The device instance.
7143 * @param iLUN The logical unit which is being attached.
7144 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
7145 *
7146 * @remarks This code path is not used during construction.
7147 */
7148static DECLCALLBACK(int) e1kR3Attach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
7149{
7150 PE1KSTATE pThis = PDMINS_2_DATA(pDevIns, E1KSTATE*);
7151 LogFlow(("%s e1kR3Attach:\n", pThis->szPrf));
7152
7153 AssertLogRelReturn(iLUN == 0, VERR_PDM_NO_SUCH_LUN);
7154
7155 PDMCritSectEnter(&pThis->cs, VERR_SEM_BUSY);
7156
7157 /*
7158 * Attach the driver.
7159 */
7160 int rc = PDMDevHlpDriverAttach(pDevIns, 0, &pThis->IBase, &pThis->pDrvBase, "Network Port");
7161 if (RT_SUCCESS(rc))
7162 {
7163 if (rc == VINF_NAT_DNS)
7164 {
7165#ifdef RT_OS_LINUX
7166 PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "NoDNSforNAT",
7167 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"));
7168#else
7169 PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "NoDNSforNAT",
7170 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"));
7171#endif
7172 }
7173 pThis->pDrvR3 = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMINETWORKUP);
7174 AssertMsgStmt(pThis->pDrvR3, ("Failed to obtain the PDMINETWORKUP interface!\n"),
7175 rc = VERR_PDM_MISSING_INTERFACE_BELOW);
7176 if (RT_SUCCESS(rc))
7177 {
7178 PPDMIBASER0 pBaseR0 = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMIBASER0);
7179 pThis->pDrvR0 = pBaseR0 ? pBaseR0->pfnQueryInterface(pBaseR0, PDMINETWORKUP_IID) : NIL_RTR0PTR;
7180
7181 PPDMIBASERC pBaseRC = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMIBASERC);
7182 pThis->pDrvRC = pBaseRC ? pBaseRC->pfnQueryInterface(pBaseRC, PDMINETWORKUP_IID) : NIL_RTR0PTR;
7183 }
7184 }
7185 else if ( rc == VERR_PDM_NO_ATTACHED_DRIVER
7186 || rc == VERR_PDM_CFG_MISSING_DRIVER_NAME)
7187 {
7188 /* This should never happen because this function is not called
7189 * if there is no driver to attach! */
7190 Log(("%s No attached driver!\n", pThis->szPrf));
7191 }
7192
7193 /*
7194 * Temporary set the link down if it was up so that the guest
7195 * will know that we have change the configuration of the
7196 * network card
7197 */
7198 if ((STATUS & STATUS_LU) && RT_SUCCESS(rc))
7199 e1kR3LinkDownTemp(pThis);
7200
7201 PDMCritSectLeave(&pThis->cs);
7202 return rc;
7203
7204}
7205
7206/**
7207 * @copydoc FNPDMDEVPOWEROFF
7208 */
7209static DECLCALLBACK(void) e1kR3PowerOff(PPDMDEVINS pDevIns)
7210{
7211 /* Poke thread waiting for buffer space. */
7212 e1kWakeupReceive(pDevIns);
7213}
7214
7215/**
7216 * @copydoc FNPDMDEVRESET
7217 */
7218static DECLCALLBACK(void) e1kR3Reset(PPDMDEVINS pDevIns)
7219{
7220 PE1KSTATE pThis = PDMINS_2_DATA(pDevIns, E1KSTATE*);
7221#ifdef E1K_TX_DELAY
7222 e1kCancelTimer(pThis, pThis->CTX_SUFF(pTXDTimer));
7223#endif /* E1K_TX_DELAY */
7224 e1kCancelTimer(pThis, pThis->CTX_SUFF(pIntTimer));
7225 e1kCancelTimer(pThis, pThis->CTX_SUFF(pLUTimer));
7226 e1kXmitFreeBuf(pThis);
7227 pThis->u16TxPktLen = 0;
7228 pThis->fIPcsum = false;
7229 pThis->fTCPcsum = false;
7230 pThis->fIntMaskUsed = false;
7231 pThis->fDelayInts = false;
7232 pThis->fLocked = false;
7233 pThis->u64AckedAt = 0;
7234 e1kHardReset(pThis);
7235}
7236
7237/**
7238 * @copydoc FNPDMDEVSUSPEND
7239 */
7240static DECLCALLBACK(void) e1kR3Suspend(PPDMDEVINS pDevIns)
7241{
7242 /* Poke thread waiting for buffer space. */
7243 e1kWakeupReceive(pDevIns);
7244}
7245
7246/**
7247 * Device relocation callback.
7248 *
7249 * When this callback is called the device instance data, and if the
7250 * device have a GC component, is being relocated, or/and the selectors
7251 * have been changed. The device must use the chance to perform the
7252 * necessary pointer relocations and data updates.
7253 *
7254 * Before the GC code is executed the first time, this function will be
7255 * called with a 0 delta so GC pointer calculations can be one in one place.
7256 *
7257 * @param pDevIns Pointer to the device instance.
7258 * @param offDelta The relocation delta relative to the old location.
7259 *
7260 * @remark A relocation CANNOT fail.
7261 */
7262static DECLCALLBACK(void) e1kR3Relocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
7263{
7264 PE1KSTATE pThis = PDMINS_2_DATA(pDevIns, E1KSTATE*);
7265 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
7266 pThis->pTxQueueRC = PDMQueueRCPtr(pThis->pTxQueueR3);
7267 pThis->pCanRxQueueRC = PDMQueueRCPtr(pThis->pCanRxQueueR3);
7268#ifdef E1K_USE_RX_TIMERS
7269 pThis->pRIDTimerRC = TMTimerRCPtr(pThis->pRIDTimerR3);
7270 pThis->pRADTimerRC = TMTimerRCPtr(pThis->pRADTimerR3);
7271#endif /* E1K_USE_RX_TIMERS */
7272#ifdef E1K_USE_TX_TIMERS
7273 pThis->pTIDTimerRC = TMTimerRCPtr(pThis->pTIDTimerR3);
7274# ifndef E1K_NO_TAD
7275 pThis->pTADTimerRC = TMTimerRCPtr(pThis->pTADTimerR3);
7276# endif /* E1K_NO_TAD */
7277#endif /* E1K_USE_TX_TIMERS */
7278#ifdef E1K_TX_DELAY
7279 pThis->pTXDTimerRC = TMTimerRCPtr(pThis->pTXDTimerR3);
7280#endif /* E1K_TX_DELAY */
7281 pThis->pIntTimerRC = TMTimerRCPtr(pThis->pIntTimerR3);
7282 pThis->pLUTimerRC = TMTimerRCPtr(pThis->pLUTimerR3);
7283}
7284
7285/**
7286 * Destruct a device instance.
7287 *
7288 * We need to free non-VM resources only.
7289 *
7290 * @returns VBox status.
7291 * @param pDevIns The device instance data.
7292 * @thread EMT
7293 */
7294static DECLCALLBACK(int) e1kR3Destruct(PPDMDEVINS pDevIns)
7295{
7296 PE1KSTATE pThis = PDMINS_2_DATA(pDevIns, E1KSTATE*);
7297 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
7298
7299 e1kDumpState(pThis);
7300 E1kLog(("%s Destroying instance\n", pThis->szPrf));
7301 if (PDMCritSectIsInitialized(&pThis->cs))
7302 {
7303 if (pThis->hEventMoreRxDescAvail != NIL_RTSEMEVENT)
7304 {
7305 RTSemEventSignal(pThis->hEventMoreRxDescAvail);
7306 RTSemEventDestroy(pThis->hEventMoreRxDescAvail);
7307 pThis->hEventMoreRxDescAvail = NIL_RTSEMEVENT;
7308 }
7309#ifdef E1K_WITH_TX_CS
7310 PDMR3CritSectDelete(&pThis->csTx);
7311#endif /* E1K_WITH_TX_CS */
7312 PDMR3CritSectDelete(&pThis->csRx);
7313 PDMR3CritSectDelete(&pThis->cs);
7314 }
7315 return VINF_SUCCESS;
7316}
7317
7318
7319/**
7320 * Set PCI configuration space registers.
7321 *
7322 * @param pci Reference to PCI device structure.
7323 * @thread EMT
7324 */
7325static DECLCALLBACK(void) e1kConfigurePciDev(PPCIDEVICE pPciDev, E1KCHIP eChip)
7326{
7327 Assert(eChip < RT_ELEMENTS(g_Chips));
7328 /* Configure PCI Device, assume 32-bit mode ******************************/
7329 PCIDevSetVendorId(pPciDev, g_Chips[eChip].uPCIVendorId);
7330 PCIDevSetDeviceId(pPciDev, g_Chips[eChip].uPCIDeviceId);
7331 PCIDevSetWord( pPciDev, VBOX_PCI_SUBSYSTEM_VENDOR_ID, g_Chips[eChip].uPCISubsystemVendorId);
7332 PCIDevSetWord( pPciDev, VBOX_PCI_SUBSYSTEM_ID, g_Chips[eChip].uPCISubsystemId);
7333
7334 PCIDevSetWord( pPciDev, VBOX_PCI_COMMAND, 0x0000);
7335 /* DEVSEL Timing (medium device), 66 MHz Capable, New capabilities */
7336 PCIDevSetWord( pPciDev, VBOX_PCI_STATUS,
7337 VBOX_PCI_STATUS_DEVSEL_MEDIUM | VBOX_PCI_STATUS_CAP_LIST | VBOX_PCI_STATUS_66MHZ);
7338 /* Stepping A2 */
7339 PCIDevSetByte( pPciDev, VBOX_PCI_REVISION_ID, 0x02);
7340 /* Ethernet adapter */
7341 PCIDevSetByte( pPciDev, VBOX_PCI_CLASS_PROG, 0x00);
7342 PCIDevSetWord( pPciDev, VBOX_PCI_CLASS_DEVICE, 0x0200);
7343 /* normal single function Ethernet controller */
7344 PCIDevSetByte( pPciDev, VBOX_PCI_HEADER_TYPE, 0x00);
7345 /* Memory Register Base Address */
7346 PCIDevSetDWord(pPciDev, VBOX_PCI_BASE_ADDRESS_0, 0x00000000);
7347 /* Memory Flash Base Address */
7348 PCIDevSetDWord(pPciDev, VBOX_PCI_BASE_ADDRESS_1, 0x00000000);
7349 /* IO Register Base Address */
7350 PCIDevSetDWord(pPciDev, VBOX_PCI_BASE_ADDRESS_2, 0x00000001);
7351 /* Expansion ROM Base Address */
7352 PCIDevSetDWord(pPciDev, VBOX_PCI_ROM_ADDRESS, 0x00000000);
7353 /* Capabilities Pointer */
7354 PCIDevSetByte( pPciDev, VBOX_PCI_CAPABILITY_LIST, 0xDC);
7355 /* Interrupt Pin: INTA# */
7356 PCIDevSetByte( pPciDev, VBOX_PCI_INTERRUPT_PIN, 0x01);
7357 /* Max_Lat/Min_Gnt: very high priority and time slice */
7358 PCIDevSetByte( pPciDev, VBOX_PCI_MIN_GNT, 0xFF);
7359 PCIDevSetByte( pPciDev, VBOX_PCI_MAX_LAT, 0x00);
7360
7361 /* PCI Power Management Registers ****************************************/
7362 /* Capability ID: PCI Power Management Registers */
7363 PCIDevSetByte( pPciDev, 0xDC, VBOX_PCI_CAP_ID_PM);
7364 /* Next Item Pointer: PCI-X */
7365 PCIDevSetByte( pPciDev, 0xDC + 1, 0xE4);
7366 /* Power Management Capabilities: PM disabled, DSI */
7367 PCIDevSetWord( pPciDev, 0xDC + 2,
7368 0x0002 | VBOX_PCI_PM_CAP_DSI);
7369 /* Power Management Control / Status Register: PM disabled */
7370 PCIDevSetWord( pPciDev, 0xDC + 4, 0x0000);
7371 /* PMCSR_BSE Bridge Support Extensions: Not supported */
7372 PCIDevSetByte( pPciDev, 0xDC + 6, 0x00);
7373 /* Data Register: PM disabled, always 0 */
7374 PCIDevSetByte( pPciDev, 0xDC + 7, 0x00);
7375
7376 /* PCI-X Configuration Registers *****************************************/
7377 /* Capability ID: PCI-X Configuration Registers */
7378 PCIDevSetByte( pPciDev, 0xE4, VBOX_PCI_CAP_ID_PCIX);
7379#ifdef E1K_WITH_MSI
7380 PCIDevSetByte( pPciDev, 0xE4 + 1, 0x80);
7381#else
7382 /* Next Item Pointer: None (Message Signalled Interrupts are disabled) */
7383 PCIDevSetByte( pPciDev, 0xE4 + 1, 0x00);
7384#endif
7385 /* PCI-X Command: Enable Relaxed Ordering */
7386 PCIDevSetWord( pPciDev, 0xE4 + 2, VBOX_PCI_X_CMD_ERO);
7387 /* PCI-X Status: 32-bit, 66MHz*/
7388 /** @todo is this value really correct? fff8 doesn't look like actual PCI address */
7389 PCIDevSetDWord(pPciDev, 0xE4 + 4, 0x0040FFF8);
7390}
7391
7392/**
7393 * @interface_method_impl{PDMDEVREG,pfnConstruct}
7394 */
7395static DECLCALLBACK(int) e1kR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
7396{
7397 PE1KSTATE pThis = PDMINS_2_DATA(pDevIns, E1KSTATE*);
7398 int rc;
7399 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
7400
7401 /*
7402 * Initialize the instance data (state).
7403 * Note! Caller has initialized it to ZERO already.
7404 */
7405 RTStrPrintf(pThis->szPrf, sizeof(pThis->szPrf), "E1000#%d", iInstance);
7406 E1kLog(("%s Constructing new instance sizeof(E1KRXDESC)=%d\n", pThis->szPrf, sizeof(E1KRXDESC)));
7407 pThis->hEventMoreRxDescAvail = NIL_RTSEMEVENT;
7408 pThis->pDevInsR3 = pDevIns;
7409 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
7410 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
7411 pThis->u16TxPktLen = 0;
7412 pThis->fIPcsum = false;
7413 pThis->fTCPcsum = false;
7414 pThis->fIntMaskUsed = false;
7415 pThis->fDelayInts = false;
7416 pThis->fLocked = false;
7417 pThis->u64AckedAt = 0;
7418 pThis->led.u32Magic = PDMLED_MAGIC;
7419 pThis->u32PktNo = 1;
7420
7421 /* Interfaces */
7422 pThis->IBase.pfnQueryInterface = e1kR3QueryInterface;
7423
7424 pThis->INetworkDown.pfnWaitReceiveAvail = e1kR3NetworkDown_WaitReceiveAvail;
7425 pThis->INetworkDown.pfnReceive = e1kR3NetworkDown_Receive;
7426 pThis->INetworkDown.pfnXmitPending = e1kR3NetworkDown_XmitPending;
7427
7428 pThis->ILeds.pfnQueryStatusLed = e1kR3QueryStatusLed;
7429
7430 pThis->INetworkConfig.pfnGetMac = e1kR3GetMac;
7431 pThis->INetworkConfig.pfnGetLinkState = e1kR3GetLinkState;
7432 pThis->INetworkConfig.pfnSetLinkState = e1kR3SetLinkState;
7433
7434 /*
7435 * Internal validations.
7436 */
7437 for (uint32_t iReg = 1; iReg < E1K_NUM_OF_BINARY_SEARCHABLE; iReg++)
7438 AssertLogRelMsgReturn( g_aE1kRegMap[iReg].offset > g_aE1kRegMap[iReg - 1].offset
7439 && g_aE1kRegMap[iReg].offset + g_aE1kRegMap[iReg].size
7440 >= g_aE1kRegMap[iReg - 1].offset + g_aE1kRegMap[iReg - 1].size,
7441 ("%s@%#xLB%#x vs %s@%#xLB%#x\n",
7442 g_aE1kRegMap[iReg].abbrev, g_aE1kRegMap[iReg].offset, g_aE1kRegMap[iReg].size,
7443 g_aE1kRegMap[iReg - 1].abbrev, g_aE1kRegMap[iReg - 1].offset, g_aE1kRegMap[iReg - 1].size),
7444 VERR_INTERNAL_ERROR_4);
7445
7446 /*
7447 * Validate configuration.
7448 */
7449 if (!CFGMR3AreValuesValid(pCfg, "MAC\0" "CableConnected\0" "AdapterType\0"
7450 "LineSpeed\0" "GCEnabled\0" "R0Enabled\0"
7451 "EthernetCRC\0" "GSOEnabled\0" "LinkUpDelay\0"))
7452 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
7453 N_("Invalid configuration for E1000 device"));
7454
7455 /** @todo: LineSpeed unused! */
7456
7457 pThis->fR0Enabled = true;
7458 pThis->fRCEnabled = true;
7459 pThis->fEthernetCRC = true;
7460 pThis->fGSOEnabled = true;
7461
7462 /* Get config params */
7463 rc = CFGMR3QueryBytes(pCfg, "MAC", pThis->macConfigured.au8, sizeof(pThis->macConfigured.au8));
7464 if (RT_FAILURE(rc))
7465 return PDMDEV_SET_ERROR(pDevIns, rc,
7466 N_("Configuration error: Failed to get MAC address"));
7467 rc = CFGMR3QueryBool(pCfg, "CableConnected", &pThis->fCableConnected);
7468 if (RT_FAILURE(rc))
7469 return PDMDEV_SET_ERROR(pDevIns, rc,
7470 N_("Configuration error: Failed to get the value of 'CableConnected'"));
7471 rc = CFGMR3QueryU32(pCfg, "AdapterType", (uint32_t*)&pThis->eChip);
7472 if (RT_FAILURE(rc))
7473 return PDMDEV_SET_ERROR(pDevIns, rc,
7474 N_("Configuration error: Failed to get the value of 'AdapterType'"));
7475 Assert(pThis->eChip <= E1K_CHIP_82545EM);
7476 rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &pThis->fRCEnabled, true);
7477 if (RT_FAILURE(rc))
7478 return PDMDEV_SET_ERROR(pDevIns, rc,
7479 N_("Configuration error: Failed to get the value of 'GCEnabled'"));
7480
7481 rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &pThis->fR0Enabled, true);
7482 if (RT_FAILURE(rc))
7483 return PDMDEV_SET_ERROR(pDevIns, rc,
7484 N_("Configuration error: Failed to get the value of 'R0Enabled'"));
7485
7486 rc = CFGMR3QueryBoolDef(pCfg, "EthernetCRC", &pThis->fEthernetCRC, true);
7487 if (RT_FAILURE(rc))
7488 return PDMDEV_SET_ERROR(pDevIns, rc,
7489 N_("Configuration error: Failed to get the value of 'EthernetCRC'"));
7490
7491 rc = CFGMR3QueryBoolDef(pCfg, "GSOEnabled", &pThis->fGSOEnabled, true);
7492 if (RT_FAILURE(rc))
7493 return PDMDEV_SET_ERROR(pDevIns, rc,
7494 N_("Configuration error: Failed to get the value of 'GSOEnabled'"));
7495
7496 rc = CFGMR3QueryU32Def(pCfg, "LinkUpDelay", (uint32_t*)&pThis->cMsLinkUpDelay, 5000); /* ms */
7497 if (RT_FAILURE(rc))
7498 return PDMDEV_SET_ERROR(pDevIns, rc,
7499 N_("Configuration error: Failed to get the value of 'LinkUpDelay'"));
7500 Assert(pThis->cMsLinkUpDelay <= 300000); /* less than 5 minutes */
7501 if (pThis->cMsLinkUpDelay > 5000)
7502 LogRel(("%s WARNING! Link up delay is set to %u seconds!\n", pThis->szPrf, pThis->cMsLinkUpDelay / 1000));
7503 else if (pThis->cMsLinkUpDelay == 0)
7504 LogRel(("%s WARNING! Link up delay is disabled!\n", pThis->szPrf));
7505
7506 E1kLog(("%s Chip=%s LinkUpDelay=%ums EthernetCRC=%s GSO=%s R0=%s GC=%s\n", pThis->szPrf,
7507 g_Chips[pThis->eChip].pcszName, pThis->cMsLinkUpDelay,
7508 pThis->fEthernetCRC ? "on" : "off",
7509 pThis->fGSOEnabled ? "enabled" : "disabled",
7510 pThis->fR0Enabled ? "enabled" : "disabled",
7511 pThis->fRCEnabled ? "enabled" : "disabled"));
7512
7513 /* Initialize the EEPROM. */
7514 pThis->eeprom.init(pThis->macConfigured);
7515
7516 /* Initialize internal PHY. */
7517 Phy::init(&pThis->phy, iInstance, pThis->eChip == E1K_CHIP_82543GC ? PHY_EPID_M881000 : PHY_EPID_M881011);
7518 Phy::setLinkStatus(&pThis->phy, pThis->fCableConnected);
7519
7520 /* Initialize critical sections. We do our own locking. */
7521 rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
7522 AssertRCReturn(rc, rc);
7523
7524 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->cs, RT_SRC_POS, "E1000#%d", iInstance);
7525 if (RT_FAILURE(rc))
7526 return rc;
7527 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->csRx, RT_SRC_POS, "E1000#%dRX", iInstance);
7528 if (RT_FAILURE(rc))
7529 return rc;
7530#ifdef E1K_WITH_TX_CS
7531 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->csTx, RT_SRC_POS, "E1000#%dTX", iInstance);
7532 if (RT_FAILURE(rc))
7533 return rc;
7534#endif /* E1K_WITH_TX_CS */
7535
7536 /* Saved state registration. */
7537 rc = PDMDevHlpSSMRegisterEx(pDevIns, E1K_SAVEDSTATE_VERSION, sizeof(E1KSTATE), NULL,
7538 NULL, e1kLiveExec, NULL,
7539 e1kSavePrep, e1kSaveExec, NULL,
7540 e1kLoadPrep, e1kLoadExec, e1kLoadDone);
7541 if (RT_FAILURE(rc))
7542 return rc;
7543
7544 /* Set PCI config registers and register ourselves with the PCI bus. */
7545 e1kConfigurePciDev(&pThis->pciDevice, pThis->eChip);
7546 rc = PDMDevHlpPCIRegister(pDevIns, &pThis->pciDevice);
7547 if (RT_FAILURE(rc))
7548 return rc;
7549
7550#ifdef E1K_WITH_MSI
7551 PDMMSIREG MsiReg;
7552 RT_ZERO(MsiReg);
7553 MsiReg.cMsiVectors = 1;
7554 MsiReg.iMsiCapOffset = 0x80;
7555 MsiReg.iMsiNextOffset = 0x0;
7556 MsiReg.fMsi64bit = false;
7557 rc = PDMDevHlpPCIRegisterMsi(pDevIns, &MsiReg);
7558 AssertRCReturn(rc, rc);
7559#endif
7560
7561
7562 /* Map our registers to memory space (region 0, see e1kConfigurePCI)*/
7563 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0, E1K_MM_SIZE, PCI_ADDRESS_SPACE_MEM, e1kMap);
7564 if (RT_FAILURE(rc))
7565 return rc;
7566 /* Map our registers to IO space (region 2, see e1kConfigurePCI) */
7567 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 2, E1K_IOPORT_SIZE, PCI_ADDRESS_SPACE_IO, e1kMap);
7568 if (RT_FAILURE(rc))
7569 return rc;
7570
7571 /* Create transmit queue */
7572 rc = PDMDevHlpQueueCreate(pDevIns, sizeof(PDMQUEUEITEMCORE), 1, 0,
7573 e1kTxQueueConsumer, true, "E1000-Xmit", &pThis->pTxQueueR3);
7574 if (RT_FAILURE(rc))
7575 return rc;
7576 pThis->pTxQueueR0 = PDMQueueR0Ptr(pThis->pTxQueueR3);
7577 pThis->pTxQueueRC = PDMQueueRCPtr(pThis->pTxQueueR3);
7578
7579 /* Create the RX notifier signaller. */
7580 rc = PDMDevHlpQueueCreate(pDevIns, sizeof(PDMQUEUEITEMCORE), 1, 0,
7581 e1kCanRxQueueConsumer, true, "E1000-Rcv", &pThis->pCanRxQueueR3);
7582 if (RT_FAILURE(rc))
7583 return rc;
7584 pThis->pCanRxQueueR0 = PDMQueueR0Ptr(pThis->pCanRxQueueR3);
7585 pThis->pCanRxQueueRC = PDMQueueRCPtr(pThis->pCanRxQueueR3);
7586
7587#ifdef E1K_TX_DELAY
7588 /* Create Transmit Delay Timer */
7589 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, e1kTxDelayTimer, pThis,
7590 TMTIMER_FLAGS_NO_CRIT_SECT,
7591 "E1000 Transmit Delay Timer", &pThis->pTXDTimerR3);
7592 if (RT_FAILURE(rc))
7593 return rc;
7594 pThis->pTXDTimerR0 = TMTimerR0Ptr(pThis->pTXDTimerR3);
7595 pThis->pTXDTimerRC = TMTimerRCPtr(pThis->pTXDTimerR3);
7596 TMR3TimerSetCritSect(pThis->pTXDTimerR3, &pThis->csTx);
7597#endif /* E1K_TX_DELAY */
7598
7599#ifdef E1K_USE_TX_TIMERS
7600 /* Create Transmit Interrupt Delay Timer */
7601 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, e1kTxIntDelayTimer, pThis,
7602 TMTIMER_FLAGS_NO_CRIT_SECT,
7603 "E1000 Transmit Interrupt Delay Timer", &pThis->pTIDTimerR3);
7604 if (RT_FAILURE(rc))
7605 return rc;
7606 pThis->pTIDTimerR0 = TMTimerR0Ptr(pThis->pTIDTimerR3);
7607 pThis->pTIDTimerRC = TMTimerRCPtr(pThis->pTIDTimerR3);
7608
7609# ifndef E1K_NO_TAD
7610 /* Create Transmit Absolute Delay Timer */
7611 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, e1kTxAbsDelayTimer, pThis,
7612 TMTIMER_FLAGS_NO_CRIT_SECT,
7613 "E1000 Transmit Absolute Delay Timer", &pThis->pTADTimerR3);
7614 if (RT_FAILURE(rc))
7615 return rc;
7616 pThis->pTADTimerR0 = TMTimerR0Ptr(pThis->pTADTimerR3);
7617 pThis->pTADTimerRC = TMTimerRCPtr(pThis->pTADTimerR3);
7618# endif /* E1K_NO_TAD */
7619#endif /* E1K_USE_TX_TIMERS */
7620
7621#ifdef E1K_USE_RX_TIMERS
7622 /* Create Receive Interrupt Delay Timer */
7623 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, e1kRxIntDelayTimer, pThis,
7624 TMTIMER_FLAGS_NO_CRIT_SECT,
7625 "E1000 Receive Interrupt Delay Timer", &pThis->pRIDTimerR3);
7626 if (RT_FAILURE(rc))
7627 return rc;
7628 pThis->pRIDTimerR0 = TMTimerR0Ptr(pThis->pRIDTimerR3);
7629 pThis->pRIDTimerRC = TMTimerRCPtr(pThis->pRIDTimerR3);
7630
7631 /* Create Receive Absolute Delay Timer */
7632 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, e1kRxAbsDelayTimer, pThis,
7633 TMTIMER_FLAGS_NO_CRIT_SECT,
7634 "E1000 Receive Absolute Delay Timer", &pThis->pRADTimerR3);
7635 if (RT_FAILURE(rc))
7636 return rc;
7637 pThis->pRADTimerR0 = TMTimerR0Ptr(pThis->pRADTimerR3);
7638 pThis->pRADTimerRC = TMTimerRCPtr(pThis->pRADTimerR3);
7639#endif /* E1K_USE_RX_TIMERS */
7640
7641 /* Create Late Interrupt Timer */
7642 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, e1kLateIntTimer, pThis,
7643 TMTIMER_FLAGS_NO_CRIT_SECT,
7644 "E1000 Late Interrupt Timer", &pThis->pIntTimerR3);
7645 if (RT_FAILURE(rc))
7646 return rc;
7647 pThis->pIntTimerR0 = TMTimerR0Ptr(pThis->pIntTimerR3);
7648 pThis->pIntTimerRC = TMTimerRCPtr(pThis->pIntTimerR3);
7649
7650 /* Create Link Up Timer */
7651 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, e1kLinkUpTimer, pThis,
7652 TMTIMER_FLAGS_NO_CRIT_SECT,
7653 "E1000 Link Up Timer", &pThis->pLUTimerR3);
7654 if (RT_FAILURE(rc))
7655 return rc;
7656 pThis->pLUTimerR0 = TMTimerR0Ptr(pThis->pLUTimerR3);
7657 pThis->pLUTimerRC = TMTimerRCPtr(pThis->pLUTimerR3);
7658
7659 /* Register the info item */
7660 char szTmp[20];
7661 RTStrPrintf(szTmp, sizeof(szTmp), "e1k%d", iInstance);
7662 PDMDevHlpDBGFInfoRegister(pDevIns, szTmp, "E1000 info.", e1kInfo);
7663
7664 /* Status driver */
7665 PPDMIBASE pBase;
7666 rc = PDMDevHlpDriverAttach(pDevIns, PDM_STATUS_LUN, &pThis->IBase, &pBase, "Status Port");
7667 if (RT_FAILURE(rc))
7668 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to attach the status LUN"));
7669 pThis->pLedsConnector = PDMIBASE_QUERY_INTERFACE(pBase, PDMILEDCONNECTORS);
7670
7671 /* Network driver */
7672 rc = PDMDevHlpDriverAttach(pDevIns, 0, &pThis->IBase, &pThis->pDrvBase, "Network Port");
7673 if (RT_SUCCESS(rc))
7674 {
7675 if (rc == VINF_NAT_DNS)
7676 PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "NoDNSforNAT",
7677 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"));
7678 pThis->pDrvR3 = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMINETWORKUP);
7679 AssertMsgReturn(pThis->pDrvR3, ("Failed to obtain the PDMINETWORKUP interface!\n"), VERR_PDM_MISSING_INTERFACE_BELOW);
7680
7681 pThis->pDrvR0 = PDMIBASER0_QUERY_INTERFACE(PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMIBASER0), PDMINETWORKUP);
7682 pThis->pDrvRC = PDMIBASERC_QUERY_INTERFACE(PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMIBASERC), PDMINETWORKUP);
7683 }
7684 else if ( rc == VERR_PDM_NO_ATTACHED_DRIVER
7685 || rc == VERR_PDM_CFG_MISSING_DRIVER_NAME)
7686 {
7687 /* No error! */
7688 E1kLog(("%s This adapter is not attached to any network!\n", pThis->szPrf));
7689 }
7690 else
7691 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to attach the network LUN"));
7692
7693 rc = RTSemEventCreate(&pThis->hEventMoreRxDescAvail);
7694 if (RT_FAILURE(rc))
7695 return rc;
7696
7697 rc = e1kInitDebugHelpers();
7698 if (RT_FAILURE(rc))
7699 return rc;
7700
7701 e1kHardReset(pThis);
7702
7703 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatReceiveBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Amount of data received", "/Public/Net/E1k%u/BytesReceived", iInstance);
7704 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatTransmitBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Amount of data transmitted", "/Public/Net/E1k%u/BytesTransmitted", iInstance);
7705
7706 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatReceiveBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Amount of data received", "/Devices/E1k%d/ReceiveBytes", iInstance);
7707 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatTransmitBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Amount of data transmitted", "/Devices/E1k%d/TransmitBytes", iInstance);
7708
7709#if defined(VBOX_WITH_STATISTICS)
7710 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatMMIOReadRZ, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling MMIO reads in RZ", "/Devices/E1k%d/MMIO/ReadRZ", iInstance);
7711 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatMMIOReadR3, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling MMIO reads in R3", "/Devices/E1k%d/MMIO/ReadR3", iInstance);
7712 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatMMIOWriteRZ, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling MMIO writes in RZ", "/Devices/E1k%d/MMIO/WriteRZ", iInstance);
7713 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatMMIOWriteR3, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling MMIO writes in R3", "/Devices/E1k%d/MMIO/WriteR3", iInstance);
7714 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatEEPROMRead, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling EEPROM reads", "/Devices/E1k%d/EEPROM/Read", iInstance);
7715 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatEEPROMWrite, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling EEPROM writes", "/Devices/E1k%d/EEPROM/Write", iInstance);
7716 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatIOReadRZ, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling IO reads in RZ", "/Devices/E1k%d/IO/ReadRZ", iInstance);
7717 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatIOReadR3, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling IO reads in R3", "/Devices/E1k%d/IO/ReadR3", iInstance);
7718 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatIOWriteRZ, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling IO writes in RZ", "/Devices/E1k%d/IO/WriteRZ", iInstance);
7719 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatIOWriteR3, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling IO writes in R3", "/Devices/E1k%d/IO/WriteR3", iInstance);
7720 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatLateIntTimer, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling late int timer", "/Devices/E1k%d/LateInt/Timer", iInstance);
7721 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatLateInts, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of late interrupts", "/Devices/E1k%d/LateInt/Occured", iInstance);
7722 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatIntsRaised, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of raised interrupts", "/Devices/E1k%d/Interrupts/Raised", iInstance);
7723 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatIntsPrevented, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of prevented interrupts", "/Devices/E1k%d/Interrupts/Prevented", iInstance);
7724 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatReceive, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling receive", "/Devices/E1k%d/Receive/Total", iInstance);
7725 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatReceiveCRC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling receive checksumming", "/Devices/E1k%d/Receive/CRC", iInstance);
7726 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatReceiveFilter, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling receive filtering", "/Devices/E1k%d/Receive/Filter", iInstance);
7727 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatReceiveStore, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling receive storing", "/Devices/E1k%d/Receive/Store", iInstance);
7728 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatRxOverflow, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_OCCURENCE, "Profiling RX overflows", "/Devices/E1k%d/RxOverflow", iInstance);
7729 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatRxOverflowWakeup, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of RX overflow wakeups", "/Devices/E1k%d/RxOverflowWakeup", iInstance);
7730 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatTransmitRZ, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling transmits in RZ", "/Devices/E1k%d/Transmit/TotalRZ", iInstance);
7731 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatTransmitR3, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling transmits in R3", "/Devices/E1k%d/Transmit/TotalR3", iInstance);
7732 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatTransmitSendRZ, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling send transmit in RZ", "/Devices/E1k%d/Transmit/SendRZ", iInstance);
7733 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatTransmitSendR3, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling send transmit in R3", "/Devices/E1k%d/Transmit/SendR3", iInstance);
7734
7735 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatTxDescCtxNormal, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of normal context descriptors","/Devices/E1k%d/TxDesc/ContexNormal", iInstance);
7736 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatTxDescCtxTSE, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of TSE context descriptors", "/Devices/E1k%d/TxDesc/ContextTSE", iInstance);
7737 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatTxDescData, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of TX data descriptors", "/Devices/E1k%d/TxDesc/Data", iInstance);
7738 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatTxDescLegacy, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of TX legacy descriptors", "/Devices/E1k%d/TxDesc/Legacy", iInstance);
7739 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatTxDescTSEData, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of TX TSE data descriptors", "/Devices/E1k%d/TxDesc/TSEData", iInstance);
7740 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatTxPathFallback, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Fallback TSE descriptor path", "/Devices/E1k%d/TxPath/Fallback", iInstance);
7741 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatTxPathGSO, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "GSO TSE descriptor path", "/Devices/E1k%d/TxPath/GSO", iInstance);
7742 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatTxPathRegular, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Regular descriptor path", "/Devices/E1k%d/TxPath/Normal", iInstance);
7743 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatPHYAccesses, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of PHY accesses", "/Devices/E1k%d/PHYAccesses", iInstance);
7744 for (unsigned iReg = 0; iReg < E1K_NUM_OF_REGS; iReg++)
7745 {
7746 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->aStatRegReads[iReg], STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
7747 g_aE1kRegMap[iReg].name, "/Devices/E1k%d/Regs/%s-Reads", iInstance, g_aE1kRegMap[iReg].abbrev);
7748 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->aStatRegWrites[iReg], STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
7749 g_aE1kRegMap[iReg].name, "/Devices/E1k%d/Regs/%s-Writes", iInstance, g_aE1kRegMap[iReg].abbrev);
7750 }
7751#endif /* VBOX_WITH_STATISTICS */
7752
7753#ifdef E1K_INT_STATS
7754 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->u64ArmedAt, STAMTYPE_U64, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "u64ArmedAt", "/Devices/E1k%d/u64ArmedAt", iInstance);
7755 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatMaxTxDelay, STAMTYPE_U64, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatMaxTxDelay", "/Devices/E1k%d/uStatMaxTxDelay", iInstance);
7756 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatInt, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatInt", "/Devices/E1k%d/uStatInt", iInstance);
7757 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatIntTry, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatIntTry", "/Devices/E1k%d/uStatIntTry", iInstance);
7758 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatIntLower, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatIntLower", "/Devices/E1k%d/uStatIntLower", iInstance);
7759 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatIntDly, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatIntDly", "/Devices/E1k%d/uStatIntDly", iInstance);
7760 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->iStatIntLost, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "iStatIntLost", "/Devices/E1k%d/iStatIntLost", iInstance);
7761 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->iStatIntLostOne, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "iStatIntLostOne", "/Devices/E1k%d/iStatIntLostOne", iInstance);
7762 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatDisDly, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatDisDly", "/Devices/E1k%d/uStatDisDly", iInstance);
7763 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatIntSkip, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatIntSkip", "/Devices/E1k%d/uStatIntSkip", iInstance);
7764 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatIntLate, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatIntLate", "/Devices/E1k%d/uStatIntLate", iInstance);
7765 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatIntMasked, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatIntMasked", "/Devices/E1k%d/uStatIntMasked", iInstance);
7766 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatIntEarly, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatIntEarly", "/Devices/E1k%d/uStatIntEarly", iInstance);
7767 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatIntRx, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatIntRx", "/Devices/E1k%d/uStatIntRx", iInstance);
7768 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatIntTx, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatIntTx", "/Devices/E1k%d/uStatIntTx", iInstance);
7769 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatIntICS, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatIntICS", "/Devices/E1k%d/uStatIntICS", iInstance);
7770 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatIntRDTR, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatIntRDTR", "/Devices/E1k%d/uStatIntRDTR", iInstance);
7771 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatIntRXDMT0, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatIntRXDMT0", "/Devices/E1k%d/uStatIntRXDMT0", iInstance);
7772 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatIntTXQE, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatIntTXQE", "/Devices/E1k%d/uStatIntTXQE", iInstance);
7773 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatTxNoRS, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatTxNoRS", "/Devices/E1k%d/uStatTxNoRS", iInstance);
7774 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatTxIDE, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatTxIDE", "/Devices/E1k%d/uStatTxIDE", iInstance);
7775 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatTxDelayed, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatTxDelayed", "/Devices/E1k%d/uStatTxDelayed", iInstance);
7776 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatTxDelayExp, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatTxDelayExp", "/Devices/E1k%d/uStatTxDelayExp", iInstance);
7777 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatTAD, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatTAD", "/Devices/E1k%d/uStatTAD", iInstance);
7778 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatTID, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatTID", "/Devices/E1k%d/uStatTID", iInstance);
7779 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatRAD, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatRAD", "/Devices/E1k%d/uStatRAD", iInstance);
7780 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatRID, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatRID", "/Devices/E1k%d/uStatRID", iInstance);
7781 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatRxFrm, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatRxFrm", "/Devices/E1k%d/uStatRxFrm", iInstance);
7782 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatTxFrm, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatTxFrm", "/Devices/E1k%d/uStatTxFrm", iInstance);
7783 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatDescCtx, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatDescCtx", "/Devices/E1k%d/uStatDescCtx", iInstance);
7784 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatDescDat, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatDescDat", "/Devices/E1k%d/uStatDescDat", iInstance);
7785 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatDescLeg, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatDescLeg", "/Devices/E1k%d/uStatDescLeg", iInstance);
7786 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatTx1514, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatTx1514", "/Devices/E1k%d/uStatTx1514", iInstance);
7787 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatTx2962, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatTx2962", "/Devices/E1k%d/uStatTx2962", iInstance);
7788 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatTx4410, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatTx4410", "/Devices/E1k%d/uStatTx4410", iInstance);
7789 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatTx5858, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatTx5858", "/Devices/E1k%d/uStatTx5858", iInstance);
7790 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatTx7306, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatTx7306", "/Devices/E1k%d/uStatTx7306", iInstance);
7791 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatTx8754, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatTx8754", "/Devices/E1k%d/uStatTx8754", iInstance);
7792 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatTx16384, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatTx16384", "/Devices/E1k%d/uStatTx16384", iInstance);
7793 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatTx32768, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatTx32768", "/Devices/E1k%d/uStatTx32768", iInstance);
7794 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->uStatTxLarge, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_NS, "uStatTxLarge", "/Devices/E1k%d/uStatTxLarge", iInstance);
7795#endif /* E1K_INT_STATS */
7796
7797 return VINF_SUCCESS;
7798}
7799
7800/**
7801 * The device registration structure.
7802 */
7803const PDMDEVREG g_DeviceE1000 =
7804{
7805 /* Structure version. PDM_DEVREG_VERSION defines the current version. */
7806 PDM_DEVREG_VERSION,
7807 /* Device name. */
7808 "e1000",
7809 /* Name of guest context module (no path).
7810 * Only evalutated if PDM_DEVREG_FLAGS_RC is set. */
7811 "VBoxDDGC.gc",
7812 /* Name of ring-0 module (no path).
7813 * Only evalutated if PDM_DEVREG_FLAGS_RC is set. */
7814 "VBoxDDR0.r0",
7815 /* The description of the device. The UTF-8 string pointed to shall, like this structure,
7816 * remain unchanged from registration till VM destruction. */
7817 "Intel PRO/1000 MT Desktop Ethernet.\n",
7818
7819 /* Flags, combination of the PDM_DEVREG_FLAGS_* \#defines. */
7820 PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
7821 /* Device class(es), combination of the PDM_DEVREG_CLASS_* \#defines. */
7822 PDM_DEVREG_CLASS_NETWORK,
7823 /* Maximum number of instances (per VM). */
7824 ~0U,
7825 /* Size of the instance data. */
7826 sizeof(E1KSTATE),
7827
7828 /* pfnConstruct */
7829 e1kR3Construct,
7830 /* pfnDestruct */
7831 e1kR3Destruct,
7832 /* pfnRelocate */
7833 e1kR3Relocate,
7834 /* pfnMemSetup */
7835 NULL,
7836 /* pfnPowerOn */
7837 NULL,
7838 /* pfnReset */
7839 e1kR3Reset,
7840 /* pfnSuspend */
7841 e1kR3Suspend,
7842 /* pfnResume */
7843 NULL,
7844 /* pfnAttach */
7845 e1kR3Attach,
7846 /* pfnDeatch */
7847 e1kR3Detach,
7848 /* pfnQueryInterface */
7849 NULL,
7850 /* pfnInitComplete */
7851 NULL,
7852 /* pfnPowerOff */
7853 e1kR3PowerOff,
7854 /* pfnSoftReset */
7855 NULL,
7856
7857 /* u32VersionEnd */
7858 PDM_DEVREG_VERSION
7859};
7860
7861#endif /* IN_RING3 */
7862#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