VirtualBox

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

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

NetShaper,E1000: Basic framework and partial implementation for network shaper

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

© 2023 Oracle
ContactPrivacy policyTerms of Use