VirtualBox

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

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

SSM,*: Renamed phase to pass (uPhase/SSM_PHASE_FINAL) and wrote the remainder of the live snapshot / migration SSM code.

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