VirtualBox

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

Last change on this file since 29354 was 28800, checked in by vboxsync, 15 years ago

Automated rebranding to Oracle copyright/license strings via filemuncher

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