VirtualBox

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

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

e1k: temporary code for MSI testing

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

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