VirtualBox

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

Last change on this file since 32851 was 32724, checked in by vboxsync, 14 years ago

e1k: few PCI-related notes

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