VirtualBox

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

Last change on this file since 44542 was 44542, checked in by vboxsync, 12 years ago

DevE1000: More cleanups, changing it to use pThis instead of pState as we do in most other devices and drivers.

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

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