VirtualBox

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

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

e1000: applied e1kRegRead fix suggested by Vasily

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