VirtualBox

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

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

e1000: added EthernetCRC CFGM parameter to make calculation of CRC optional (#6152)

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