VirtualBox

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

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

Networking: Preparing to make the driver return a send buffer to the device emulation.

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