VirtualBox

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

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

DevE1000: typo.

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