VirtualBox

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

Last change on this file since 23913 was 23867, checked in by vboxsync, 16 years ago

E1000: Proper padding (with zeros) of short packets.

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

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