VirtualBox

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

Last change on this file since 23584 was 23520, checked in by vboxsync, 15 years ago

E1K: STAM counters alignment fix

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