VirtualBox

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

Last change on this file since 28739 was 28710, checked in by vboxsync, 15 years ago

DevE1000: logging and #ifdef.

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

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