VirtualBox

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

Last change on this file since 24455 was 24430, checked in by vboxsync, 16 years ago

E1000: forward-port of r54484 from 3.0 to HEAD

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

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