VirtualBox

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

Last change on this file since 61691 was 61691, checked in by vboxsync, 9 years ago

bugref:8319: Devices/E1000: Interrupt throttling re-worked

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

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