VirtualBox

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

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

pdmifs.h: Moved the network interfaces to a separate header called pdmnetifs.h.

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

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