VirtualBox

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

Last change on this file since 41438 was 41431, checked in by vboxsync, 13 years ago

Use proper format specifier.

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

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