VirtualBox

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

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

Devices: warnings (gcc)

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