VirtualBox

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

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

DevE1000: Drop the E1K_LEDS_WITH_MUTEX #ifdefs. Don't set LEDs for packets that are <= 70 bytes (see PCNet), we don't see much of the green LED otherwise.

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