VirtualBox

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

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

e1000: A fix for regression caused by r58311.

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