VirtualBox

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

Last change on this file since 28216 was 28196, checked in by vboxsync, 15 years ago

DevE1000: Alignment fix.

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

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