VirtualBox

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

Last change on this file since 35346 was 35346, checked in by vboxsync, 14 years ago

VMM reorg: Moving the public include files from include/VBox to include/VBox/vmm.

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

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