VirtualBox

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

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

PDM: s/pCfgHandle/pCfg/g - part 2.

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