VirtualBox

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

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

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