VirtualBox

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

Last change on this file since 32059 was 31847, checked in by vboxsync, 14 years ago

iprt: removed crc32.h and crc64.h, use crc.h instead.

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

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