VirtualBox

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

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

DevE1000: Generate GSO frames.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 223.6 KB
Line 
1/* $Id: DevE1000.cpp 28057 2010-04-07 17:23:58Z vboxsync $ */
2/** @file
3 * DevE1000 - Intel 82540EM Ethernet Controller Emulation.
4 *
5 * Implemented in accordance with the specification:
6 *
7 * PCI/PCI-X Family of Gigabit Ethernet Controllers Software Developer's Manual
8 * 82540EP/EM, 82541xx, 82544GC/EI, 82545GM/EM, 82546GB/EB, and 82547xx
9 *
10 * 317453-002 Revision 3.5
11 *
12 * @todo IPv6 checksum offloading support
13 * @todo VLAN checksum offloading support
14 * @todo Flexible Filter / Wakeup (optional?)
15 */
16
17/*
18 * Copyright (C) 2007 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#ifdef E1K_LEDS_WITH_MUTEX
1991 if (RT_LIKELY(e1kCsEnter(pState, VERR_SEM_BUSY, RT_SRC_POS) == VINF_SUCCESS))
1992 {
1993#endif /* E1K_LEDS_WITH_MUTEX */
1994 pState->led.Asserted.s.fReading = 1;
1995 pState->led.Actual.s.fReading = 1;
1996#ifdef E1K_LEDS_WITH_MUTEX
1997 e1kCsLeave(pState);
1998 }
1999#endif /* E1K_LEDS_WITH_MUTEX */
2000
2001 Assert(cb <= E1K_MAX_RX_PKT_SIZE);
2002 memcpy(rxPacket, pvBuf, cb);
2003 /* Pad short packets */
2004 if (cb < 60)
2005 {
2006 memset(rxPacket + cb, 0, 60 - cb);
2007 cb = 60;
2008 }
2009 if (!(RCTL & RCTL_SECRC))
2010 {
2011 /* Add FCS if CRC stripping is not enabled */
2012 *(uint32_t*)(rxPacket + cb) = RTCrc32(rxPacket, cb);
2013 cb += sizeof(uint32_t);
2014 }
2015 /* Compute checksum of complete packet */
2016 uint16_t checksum = e1kCSum16(rxPacket + GET_BITS(RXCSUM, PCSS), cb);
2017 e1kRxChecksumOffload(pState, rxPacket, cb, &status);
2018
2019 /* Update stats */
2020 E1K_INC_CNT32(GPRC);
2021 if (e1kIsBroadcast(pvBuf))
2022 E1K_INC_CNT32(BPRC);
2023 else if (e1kIsMulticast(pvBuf))
2024 E1K_INC_CNT32(MPRC);
2025 /* Update octet receive counter */
2026 E1K_ADD_CNT64(GORCL, GORCH, cb);
2027 STAM_REL_COUNTER_ADD(&pState->StatReceiveBytes, cb);
2028 if (cb == 64)
2029 E1K_INC_CNT32(PRC64);
2030 else if (cb < 128)
2031 E1K_INC_CNT32(PRC127);
2032 else if (cb < 256)
2033 E1K_INC_CNT32(PRC255);
2034 else if (cb < 512)
2035 E1K_INC_CNT32(PRC511);
2036 else if (cb < 1024)
2037 E1K_INC_CNT32(PRC1023);
2038 else
2039 E1K_INC_CNT32(PRC1522);
2040
2041 E1K_INC_ISTAT_CNT(pState->uStatRxFrm);
2042
2043 if (RDH == RDT)
2044 {
2045 E1kLog(("%s Out of recieve buffers, dropping the packet",
2046 INSTANCE(pState)));
2047 }
2048 /* Store the packet to receive buffers */
2049 while (RDH != RDT)
2050 {
2051 /* Load the desciptor pointed by head */
2052 PDMDevHlpPhysRead(pState->CTX_SUFF(pDevIns), e1kDescAddr(RDBAH, RDBAL, RDH),
2053 &desc, sizeof(desc));
2054 if (desc.u64BufAddr)
2055 {
2056 /* Update descriptor */
2057 desc.status = status;
2058 desc.u16Checksum = checksum;
2059 desc.status.fDD = true;
2060
2061 /*
2062 * We need to leave Rx critical section here or we risk deadlocking
2063 * with EMT in e1kRegWriteRDT when the write is to an unallocated
2064 * page or has an access handler associated with it.
2065 * Note that it is safe to leave the critical section here since e1kRegWriteRDT()
2066 * modifies RDT only.
2067 */
2068 if (cb > pState->u16RxBSize)
2069 {
2070 desc.status.fEOP = false;
2071 e1kCsRxLeave(pState);
2072 e1kStoreRxFragment(pState, &desc, ptr, pState->u16RxBSize);
2073 rc = e1kCsRxEnter(pState, VERR_SEM_BUSY);
2074 if (RT_UNLIKELY(rc != VINF_SUCCESS))
2075 return rc;
2076 ptr += pState->u16RxBSize;
2077 cb -= pState->u16RxBSize;
2078 }
2079 else
2080 {
2081 desc.status.fEOP = true;
2082 e1kCsRxLeave(pState);
2083 e1kStoreRxFragment(pState, &desc, ptr, cb);
2084#ifdef E1K_LEDS_WITH_MUTEX
2085 if (RT_LIKELY(e1kCsEnter(pState, VERR_SEM_BUSY, RT_SRC_POS) == VINF_SUCCESS))
2086 {
2087#endif /* E1K_LEDS_WITH_MUTEX */
2088 pState->led.Actual.s.fReading = 0;
2089#ifdef E1K_LEDS_WITH_MUTEX
2090 e1kCsLeave(pState);
2091 }
2092#endif /* E1K_LEDS_WITH_MUTEX */
2093 return VINF_SUCCESS;
2094 }
2095 /* Note: RDH is advanced by e1kStoreRxFragment! */
2096 }
2097 else
2098 {
2099 desc.status.fDD = true;
2100 PDMDevHlpPhysWrite(pState->CTX_SUFF(pDevIns),
2101 e1kDescAddr(RDBAH, RDBAL, RDH),
2102 &desc, sizeof(desc));
2103 e1kAdvanceRDH(pState);
2104 }
2105 }
2106#ifdef E1K_LEDS_WITH_MUTEX
2107 if (RT_LIKELY(e1kCsEnter(pState, VERR_SEM_BUSY, RT_SRC_POS) == VINF_SUCCESS))
2108 {
2109#endif /* E1K_LEDS_WITH_MUTEX */
2110 pState->led.Actual.s.fReading = 0;
2111#ifdef E1K_LEDS_WITH_MUTEX
2112 e1kCsLeave(pState);
2113 }
2114#endif /* E1K_LEDS_WITH_MUTEX */
2115
2116 e1kCsRxLeave(pState);
2117
2118 return VINF_SUCCESS;
2119}
2120
2121#endif /* IN_RING3 */
2122
2123#if 0 /* unused */
2124/**
2125 * Read handler for Device Status register.
2126 *
2127 * Get the link status from PHY.
2128 *
2129 * @returns VBox status code.
2130 *
2131 * @param pState The device state structure.
2132 * @param offset Register offset in memory-mapped frame.
2133 * @param index Register index in register array.
2134 * @param mask Used to implement partial reads (8 and 16-bit).
2135 */
2136static int e1kRegReadCTRL(E1KSTATE* pState, uint32_t offset, uint32_t index, uint32_t *pu32Value)
2137{
2138 E1kLog(("%s e1kRegReadCTRL: mdio dir=%s mdc dir=%s mdc=%d\n",
2139 INSTANCE(pState), (CTRL & CTRL_MDIO_DIR)?"OUT":"IN ",
2140 (CTRL & CTRL_MDC_DIR)?"OUT":"IN ", !!(CTRL & CTRL_MDC)));
2141 if ((CTRL & CTRL_MDIO_DIR) == 0 && (CTRL & CTRL_MDC))
2142 {
2143 /* MDC is high and MDIO pin is used for input, read MDIO pin from PHY */
2144 if (Phy::readMDIO(&pState->phy))
2145 *pu32Value = CTRL | CTRL_MDIO;
2146 else
2147 *pu32Value = CTRL & ~CTRL_MDIO;
2148 E1kLog(("%s e1kRegReadCTRL: Phy::readMDIO(%d)\n",
2149 INSTANCE(pState), !!(*pu32Value & CTRL_MDIO)));
2150 }
2151 else
2152 {
2153 /* MDIO pin is used for output, ignore it */
2154 *pu32Value = CTRL;
2155 }
2156 return VINF_SUCCESS;
2157}
2158#endif /* unused */
2159
2160/**
2161 * Write handler for Device Control register.
2162 *
2163 * Handles reset.
2164 *
2165 * @param pState The device state structure.
2166 * @param offset Register offset in memory-mapped frame.
2167 * @param index Register index in register array.
2168 * @param value The value to store.
2169 * @param mask Used to implement partial writes (8 and 16-bit).
2170 * @thread EMT
2171 */
2172static int e1kRegWriteCTRL(E1KSTATE* pState, uint32_t offset, uint32_t index, uint32_t value)
2173{
2174 int rc = VINF_SUCCESS;
2175
2176 if (value & CTRL_RESET)
2177 { /* RST */
2178 e1kHardReset(pState);
2179 }
2180 else
2181 {
2182 if ( (value & CTRL_SLU)
2183 && pState->fCableConnected
2184 && !(STATUS & STATUS_LU))
2185 {
2186 /* The driver indicates that we should bring up the link */
2187 /* Do so in 5 seconds. */
2188 e1kArmTimer(pState, pState->CTX_SUFF(pLUTimer), 5000000);
2189 /*
2190 * Change the status (but not PHY status) anyway as Windows expects
2191 * it for 82543GC.
2192 */
2193 STATUS |= STATUS_LU;
2194 }
2195 if (value & CTRL_VME)
2196 {
2197 E1kLog(("%s VLAN Mode is not supported yet!\n", INSTANCE(pState)));
2198 }
2199 E1kLog(("%s e1kRegWriteCTRL: mdio dir=%s mdc dir=%s mdc=%s mdio=%d\n",
2200 INSTANCE(pState), (value & CTRL_MDIO_DIR)?"OUT":"IN ",
2201 (value & CTRL_MDC_DIR)?"OUT":"IN ", (value & CTRL_MDC)?"HIGH":"LOW ", !!(value & CTRL_MDIO)));
2202 if (value & CTRL_MDC)
2203 {
2204 if (value & CTRL_MDIO_DIR)
2205 {
2206 E1kLog(("%s e1kRegWriteCTRL: Phy::writeMDIO(%d)\n", INSTANCE(pState), !!(value & CTRL_MDIO)));
2207 /* MDIO direction pin is set to output and MDC is high, write MDIO pin value to PHY */
2208 Phy::writeMDIO(&pState->phy, !!(value & CTRL_MDIO));
2209 }
2210 else
2211 {
2212 if (Phy::readMDIO(&pState->phy))
2213 value |= CTRL_MDIO;
2214 else
2215 value &= ~CTRL_MDIO;
2216 E1kLog(("%s e1kRegWriteCTRL: Phy::readMDIO(%d)\n",
2217 INSTANCE(pState), !!(value & CTRL_MDIO)));
2218 }
2219 }
2220 rc = e1kRegWriteDefault(pState, offset, index, value);
2221 }
2222
2223 return rc;
2224}
2225
2226/**
2227 * Write handler for EEPROM/Flash Control/Data register.
2228 *
2229 * Handles EEPROM access requests; forwards writes to EEPROM device if access has been granted.
2230 *
2231 * @param pState The device state structure.
2232 * @param offset Register offset in memory-mapped frame.
2233 * @param index Register index in register array.
2234 * @param value The value to store.
2235 * @param mask Used to implement partial writes (8 and 16-bit).
2236 * @thread EMT
2237 */
2238static int e1kRegWriteEECD(E1KSTATE* pState, uint32_t offset, uint32_t index, uint32_t value)
2239{
2240#ifdef IN_RING3
2241 /* So far we are conserned with lower byte only */
2242 if ((EECD & EECD_EE_GNT) || pState->eChip == E1K_CHIP_82543GC)
2243 {
2244 /* Access to EEPROM granted -- forward 4-wire bits to EEPROM device */
2245 /* Note: 82543GC does not need to request EEPROM access */
2246 STAM_PROFILE_ADV_START(&pState->StatEEPROMWrite, a);
2247 pState->eeprom.write(value & EECD_EE_WIRES);
2248 STAM_PROFILE_ADV_STOP(&pState->StatEEPROMWrite, a);
2249 }
2250 if (value & EECD_EE_REQ)
2251 EECD |= EECD_EE_REQ|EECD_EE_GNT;
2252 else
2253 EECD &= ~EECD_EE_GNT;
2254 //e1kRegWriteDefault(pState, offset, index, value );
2255
2256 return VINF_SUCCESS;
2257#else /* !IN_RING3 */
2258 return VINF_IOM_HC_MMIO_WRITE;
2259#endif /* !IN_RING3 */
2260}
2261
2262/**
2263 * Read handler for EEPROM/Flash Control/Data register.
2264 *
2265 * Lower 4 bits come from EEPROM device if EEPROM access has been granted.
2266 *
2267 * @returns VBox status code.
2268 *
2269 * @param pState The device state structure.
2270 * @param offset Register offset in memory-mapped frame.
2271 * @param index Register index in register array.
2272 * @param mask Used to implement partial reads (8 and 16-bit).
2273 * @thread EMT
2274 */
2275static int e1kRegReadEECD(E1KSTATE* pState, uint32_t offset, uint32_t index, uint32_t *pu32Value)
2276{
2277#ifdef IN_RING3
2278 uint32_t value;
2279 int rc = e1kRegReadDefault(pState, offset, index, &value);
2280 if (RT_SUCCESS(rc))
2281 {
2282 if ((value & EECD_EE_GNT) || pState->eChip == E1K_CHIP_82543GC)
2283 {
2284 /* Note: 82543GC does not need to request EEPROM access */
2285 /* Access to EEPROM granted -- get 4-wire bits to EEPROM device */
2286 STAM_PROFILE_ADV_START(&pState->StatEEPROMRead, a);
2287 value |= pState->eeprom.read();
2288 STAM_PROFILE_ADV_STOP(&pState->StatEEPROMRead, a);
2289 }
2290 *pu32Value = value;
2291 }
2292
2293 return rc;
2294#else /* !IN_RING3 */
2295 return VINF_IOM_HC_MMIO_READ;
2296#endif /* !IN_RING3 */
2297}
2298
2299/**
2300 * Write handler for EEPROM Read register.
2301 *
2302 * Handles EEPROM word access requests, reads EEPROM and stores the result
2303 * into DATA field.
2304 *
2305 * @param pState The device state structure.
2306 * @param offset Register offset in memory-mapped frame.
2307 * @param index Register index in register array.
2308 * @param value The value to store.
2309 * @param mask Used to implement partial writes (8 and 16-bit).
2310 * @thread EMT
2311 */
2312static int e1kRegWriteEERD(E1KSTATE* pState, uint32_t offset, uint32_t index, uint32_t value)
2313{
2314#ifdef IN_RING3
2315 /* Make use of 'writable' and 'readable' masks. */
2316 e1kRegWriteDefault(pState, offset, index, value);
2317 /* DONE and DATA are set only if read was triggered by START. */
2318 if (value & EERD_START)
2319 {
2320 uint16_t tmp;
2321 STAM_PROFILE_ADV_START(&pState->StatEEPROMRead, a);
2322 if (pState->eeprom.readWord(GET_BITS_V(value, EERD, ADDR), &tmp))
2323 SET_BITS(EERD, DATA, tmp);
2324 EERD |= EERD_DONE;
2325 STAM_PROFILE_ADV_STOP(&pState->StatEEPROMRead, a);
2326 }
2327
2328 return VINF_SUCCESS;
2329#else /* !IN_RING3 */
2330 return VINF_IOM_HC_MMIO_WRITE;
2331#endif /* !IN_RING3 */
2332}
2333
2334
2335/**
2336 * Write handler for MDI Control register.
2337 *
2338 * Handles PHY read/write requests; forwards requests to internal PHY device.
2339 *
2340 * @param pState The device state structure.
2341 * @param offset Register offset in memory-mapped frame.
2342 * @param index Register index in register array.
2343 * @param value The value to store.
2344 * @param mask Used to implement partial writes (8 and 16-bit).
2345 * @thread EMT
2346 */
2347static int e1kRegWriteMDIC(E1KSTATE* pState, uint32_t offset, uint32_t index, uint32_t value)
2348{
2349 if (value & MDIC_INT_EN)
2350 {
2351 E1kLog(("%s ERROR! Interrupt at the end of an MDI cycle is not supported yet.\n",
2352 INSTANCE(pState)));
2353 }
2354 else if (value & MDIC_READY)
2355 {
2356 E1kLog(("%s ERROR! Ready bit is not reset by software during write operation.\n",
2357 INSTANCE(pState)));
2358 }
2359 else if (GET_BITS_V(value, MDIC, PHY) != 1)
2360 {
2361 E1kLog(("%s ERROR! Access to invalid PHY detected, phy=%d.\n",
2362 INSTANCE(pState), GET_BITS_V(value, MDIC, PHY)));
2363 }
2364 else
2365 {
2366 /* Store the value */
2367 e1kRegWriteDefault(pState, offset, index, value);
2368 STAM_COUNTER_INC(&pState->StatPHYAccesses);
2369 /* Forward op to PHY */
2370 if (value & MDIC_OP_READ)
2371 SET_BITS(MDIC, DATA, Phy::readRegister(&pState->phy, GET_BITS_V(value, MDIC, REG)));
2372 else
2373 Phy::writeRegister(&pState->phy, GET_BITS_V(value, MDIC, REG), value & MDIC_DATA_MASK);
2374 /* Let software know that we are done */
2375 MDIC |= MDIC_READY;
2376 }
2377
2378 return VINF_SUCCESS;
2379}
2380
2381/**
2382 * Write handler for Interrupt Cause Read register.
2383 *
2384 * Bits corresponding to 1s in 'value' will be cleared in ICR register.
2385 *
2386 * @param pState The device state structure.
2387 * @param offset Register offset in memory-mapped frame.
2388 * @param index Register index in register array.
2389 * @param value The value to store.
2390 * @param mask Used to implement partial writes (8 and 16-bit).
2391 * @thread EMT
2392 */
2393static int e1kRegWriteICR(E1KSTATE* pState, uint32_t offset, uint32_t index, uint32_t value)
2394{
2395 ICR &= ~value;
2396
2397 return VINF_SUCCESS;
2398}
2399
2400/**
2401 * Read handler for Interrupt Cause Read register.
2402 *
2403 * Reading this register acknowledges all interrupts.
2404 *
2405 * @returns VBox status code.
2406 *
2407 * @param pState The device state structure.
2408 * @param offset Register offset in memory-mapped frame.
2409 * @param index Register index in register array.
2410 * @param mask Not used.
2411 * @thread EMT
2412 */
2413static int e1kRegReadICR(E1KSTATE* pState, uint32_t offset, uint32_t index, uint32_t *pu32Value)
2414{
2415 int rc = e1kCsEnter(pState, VINF_IOM_HC_MMIO_READ);
2416 if (RT_UNLIKELY(rc != VINF_SUCCESS))
2417 return rc;
2418
2419 uint32_t value = 0;
2420 rc = e1kRegReadDefault(pState, offset, index, &value);
2421 if (RT_SUCCESS(rc))
2422 {
2423 if (value)
2424 {
2425 /*
2426 * Not clearing ICR causes QNX to hang as it reads ICR in a loop
2427 * with disabled interrupts.
2428 */
2429 //if (IMS)
2430 if (1)
2431 {
2432 /*
2433 * Interrupts were enabled -- we are supposedly at the very
2434 * beginning of interrupt handler
2435 */
2436 E1kLogRel(("E1000: irq lowered, icr=0x%x\n", ICR));
2437 E1kLog(("%s e1kRegReadICR: Lowered IRQ (%08x)\n", INSTANCE(pState), ICR));
2438 /* Clear all pending interrupts */
2439 ICR = 0;
2440 pState->fIntRaised = false;
2441 /* Lower(0) INTA(0) */
2442 //PDMDevHlpPCISetIrqNoWait(pState->CTX_SUFF(pDevIns), 0, 0);
2443 //e1kMutexRelease(pState);
2444 PDMDevHlpPCISetIrq(pState->CTX_SUFF(pDevIns), 0, 0);
2445 //e1kMutexAcquire(pState, RT_SRC_POS);
2446
2447 pState->u64AckedAt = TMTimerGet(pState->CTX_SUFF(pIntTimer));
2448 if (pState->fIntMaskUsed)
2449 pState->fDelayInts = true;
2450 }
2451 else
2452 {
2453 /*
2454 * Interrupts are disabled -- in windows guests ICR read is done
2455 * just before re-enabling interrupts
2456 */
2457 E1kLog(("%s e1kRegReadICR: Suppressing auto-clear due to disabled interrupts (%08x)\n", INSTANCE(pState), ICR));
2458 }
2459 }
2460 *pu32Value = value;
2461 }
2462 e1kCsLeave(pState);
2463
2464 return rc;
2465}
2466
2467/**
2468 * Write handler for Interrupt Cause Set register.
2469 *
2470 * Bits corresponding to 1s in 'value' will be set in ICR register.
2471 *
2472 * @param pState The device state structure.
2473 * @param offset Register offset in memory-mapped frame.
2474 * @param index Register index in register array.
2475 * @param value The value to store.
2476 * @param mask Used to implement partial writes (8 and 16-bit).
2477 * @thread EMT
2478 */
2479static int e1kRegWriteICS(E1KSTATE* pState, uint32_t offset, uint32_t index, uint32_t value)
2480{
2481 E1K_INC_ISTAT_CNT(pState->uStatIntICS);
2482 return e1kRaiseInterrupt(pState, VINF_IOM_HC_MMIO_WRITE, value & s_e1kRegMap[ICS_IDX].writable);
2483}
2484
2485/**
2486 * Write handler for Interrupt Mask Set register.
2487 *
2488 * Will trigger pending interrupts.
2489 *
2490 * @param pState The device state structure.
2491 * @param offset Register offset in memory-mapped frame.
2492 * @param index Register index in register array.
2493 * @param value The value to store.
2494 * @param mask Used to implement partial writes (8 and 16-bit).
2495 * @thread EMT
2496 */
2497static int e1kRegWriteIMS(E1KSTATE* pState, uint32_t offset, uint32_t index, uint32_t value)
2498{
2499 IMS |= value;
2500 E1kLogRel(("E1000: irq enabled, RDH=%x RDT=%x TDH=%x TDT=%x\n", RDH, RDT, TDH, TDT));
2501 E1kLog(("%s e1kRegWriteIMS: IRQ enabled\n", INSTANCE(pState)));
2502 /* Mask changes, we need to raise pending interrupts. */
2503 if ((ICR & IMS) && !pState->fLocked)
2504 {
2505 E1kLog2(("%s e1kRegWriteIMS: IRQ pending (%08x), arming late int timer...\n",
2506 INSTANCE(pState), ICR));
2507 //TMTimerSet(pState->CTX_SUFF(pIntTimer), TMTimerFromNano(pState->CTX_SUFF(pIntTimer), ITR * 256) +
2508 // TMTimerGet(pState->CTX_SUFF(pIntTimer)));
2509 e1kRaiseInterrupt(pState, VERR_SEM_BUSY);
2510 }
2511
2512 return VINF_SUCCESS;
2513}
2514
2515/**
2516 * Write handler for Interrupt Mask Clear register.
2517 *
2518 * Bits corresponding to 1s in 'value' will be cleared in IMS register.
2519 *
2520 * @param pState The device state structure.
2521 * @param offset Register offset in memory-mapped frame.
2522 * @param index Register index in register array.
2523 * @param value The value to store.
2524 * @param mask Used to implement partial writes (8 and 16-bit).
2525 * @thread EMT
2526 */
2527static int e1kRegWriteIMC(E1KSTATE* pState, uint32_t offset, uint32_t index, uint32_t value)
2528{
2529 int rc = e1kCsEnter(pState, VINF_IOM_HC_MMIO_WRITE);
2530 if (RT_UNLIKELY(rc != VINF_SUCCESS))
2531 return rc;
2532 if (pState->fIntRaised)
2533 {
2534 /*
2535 * Technically we should reset fIntRaised in ICR read handler, but it will cause
2536 * Windows to freeze since it may receive an interrupt while still in the very beginning
2537 * of interrupt handler.
2538 */
2539 E1K_INC_ISTAT_CNT(pState->uStatIntLower);
2540 STAM_COUNTER_INC(&pState->StatIntsPrevented);
2541 E1kLogRel(("E1000: irq lowered (IMC), icr=0x%x\n", ICR));
2542 /* Lower(0) INTA(0) */
2543 PDMDevHlpPCISetIrq(pState->CTX_SUFF(pDevIns), 0, 0);
2544 pState->fIntRaised = false;
2545 E1kLog(("%s e1kRegWriteIMC: Lowered IRQ: ICR=%08x\n", INSTANCE(pState), ICR));
2546 }
2547 IMS &= ~value;
2548 E1kLog(("%s e1kRegWriteIMC: IRQ disabled\n", INSTANCE(pState)));
2549 e1kCsLeave(pState);
2550
2551 return VINF_SUCCESS;
2552}
2553
2554/**
2555 * Write handler for Receive Control register.
2556 *
2557 * @param pState The device state structure.
2558 * @param offset Register offset in memory-mapped frame.
2559 * @param index Register index in register array.
2560 * @param value The value to store.
2561 * @param mask Used to implement partial writes (8 and 16-bit).
2562 * @thread EMT
2563 */
2564static int e1kRegWriteRCTL(E1KSTATE* pState, uint32_t offset, uint32_t index, uint32_t value)
2565{
2566 e1kRegWriteDefault(pState, offset, index, value);
2567 pState->u16RxBSize = 2048 >> GET_BITS(RCTL, BSIZE);
2568 if (RCTL & RCTL_BSEX)
2569 pState->u16RxBSize *= 16;
2570 E1kLog2(("%s e1kRegWriteRCTL: Setting receive buffer size to %d\n",
2571 INSTANCE(pState), pState->u16RxBSize));
2572
2573 return VINF_SUCCESS;
2574}
2575
2576/**
2577 * Write handler for Packet Buffer Allocation register.
2578 *
2579 * TXA = 64 - RXA.
2580 *
2581 * @param pState The device state structure.
2582 * @param offset Register offset in memory-mapped frame.
2583 * @param index Register index in register array.
2584 * @param value The value to store.
2585 * @param mask Used to implement partial writes (8 and 16-bit).
2586 * @thread EMT
2587 */
2588static int e1kRegWritePBA(E1KSTATE* pState, uint32_t offset, uint32_t index, uint32_t value)
2589{
2590 e1kRegWriteDefault(pState, offset, index, value);
2591 PBA_st->txa = 64 - PBA_st->rxa;
2592
2593 return VINF_SUCCESS;
2594}
2595
2596/**
2597 * Write handler for Receive Descriptor Tail register.
2598 *
2599 * @remarks Write into RDT forces switch to HC and signal to
2600 * e1kWaitReceiveAvail().
2601 *
2602 * @returns VBox status code.
2603 *
2604 * @param pState The device state structure.
2605 * @param offset Register offset in memory-mapped frame.
2606 * @param index Register index in register array.
2607 * @param value The value to store.
2608 * @param mask Used to implement partial writes (8 and 16-bit).
2609 * @thread EMT
2610 */
2611static int e1kRegWriteRDT(E1KSTATE* pState, uint32_t offset, uint32_t index, uint32_t value)
2612{
2613#ifndef IN_RING3
2614 /* XXX */
2615// return VINF_IOM_HC_MMIO_WRITE;
2616#endif
2617 int rc = e1kCsRxEnter(pState, VINF_IOM_HC_MMIO_WRITE);
2618 if (RT_LIKELY(rc == VINF_SUCCESS))
2619 {
2620 E1kLog(("%s e1kRegWriteRDT\n", INSTANCE(pState)));
2621 rc = e1kRegWriteDefault(pState, offset, index, value);
2622 e1kCsRxLeave(pState);
2623 if (RT_SUCCESS(rc))
2624 {
2625#ifdef IN_RING3
2626 /* Signal that we have more receive descriptors avalable. */
2627 e1kWakeupReceive(pState->CTX_SUFF(pDevIns));
2628#else
2629 PPDMQUEUEITEMCORE pItem = PDMQueueAlloc(pState->CTX_SUFF(pCanRxQueue));
2630 if (pItem)
2631 PDMQueueInsert(pState->CTX_SUFF(pCanRxQueue), pItem);
2632#endif
2633 }
2634 }
2635 return rc;
2636}
2637
2638/**
2639 * Write handler for Receive Delay Timer register.
2640 *
2641 * @param pState The device state structure.
2642 * @param offset Register offset in memory-mapped frame.
2643 * @param index Register index in register array.
2644 * @param value The value to store.
2645 * @param mask Used to implement partial writes (8 and 16-bit).
2646 * @thread EMT
2647 */
2648static int e1kRegWriteRDTR(E1KSTATE* pState, uint32_t offset, uint32_t index, uint32_t value)
2649{
2650 e1kRegWriteDefault(pState, offset, index, value);
2651 if (value & RDTR_FPD)
2652 {
2653 /* Flush requested, cancel both timers and raise interrupt */
2654#ifdef E1K_USE_RX_TIMERS
2655 e1kCancelTimer(pState, pState->CTX_SUFF(pRIDTimer));
2656 e1kCancelTimer(pState, pState->CTX_SUFF(pRADTimer));
2657#endif
2658 E1K_INC_ISTAT_CNT(pState->uStatIntRDTR);
2659 return e1kRaiseInterrupt(pState, VINF_IOM_HC_MMIO_WRITE, ICR_RXT0);
2660 }
2661
2662 return VINF_SUCCESS;
2663}
2664
2665DECLINLINE(uint32_t) e1kGetTxLen(E1KSTATE* pState)
2666{
2667 /**
2668 * Make sure TDT won't change during computation. EMT may modify TDT at
2669 * any moment.
2670 */
2671 uint32_t tdt = TDT;
2672 return (TDH>tdt ? TDLEN/sizeof(E1KTXDESC) : 0) + tdt - TDH;
2673}
2674
2675#ifdef IN_RING3
2676#ifdef E1K_USE_TX_TIMERS
2677/**
2678 * Transmit Interrupt Delay Timer handler.
2679 *
2680 * @remarks We only get here when the timer expires.
2681 *
2682 * @param pDevIns Pointer to device instance structure.
2683 * @param pTimer Pointer to the timer.
2684 * @param pvUser NULL.
2685 * @thread EMT
2686 */
2687static DECLCALLBACK(void) e1kTxIntDelayTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
2688{
2689 E1KSTATE *pState = (E1KSTATE *)pvUser;
2690
2691 if (RT_LIKELY(e1kMutexAcquire(pState, VERR_SEM_BUSY, RT_SRC_POS) == VINF_SUCCESS))
2692 {
2693 E1K_INC_ISTAT_CNT(pState->uStatTID);
2694 /* Cancel absolute delay timer as we have already got attention */
2695#ifndef E1K_NO_TAD
2696 e1kCancelTimer(pState, pState->CTX_SUFF(pTADTimer));
2697#endif /* E1K_NO_TAD */
2698 e1kRaiseInterrupt(pState, ICR_TXDW);
2699 e1kMutexRelease(pState);
2700 }
2701}
2702
2703/**
2704 * Transmit Absolute Delay Timer handler.
2705 *
2706 * @remarks We only get here when the timer expires.
2707 *
2708 * @param pDevIns Pointer to device instance structure.
2709 * @param pTimer Pointer to the timer.
2710 * @param pvUser NULL.
2711 * @thread EMT
2712 */
2713static DECLCALLBACK(void) e1kTxAbsDelayTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
2714{
2715 E1KSTATE *pState = (E1KSTATE *)pvUser;
2716
2717 if (RT_LIKELY(e1kMutexAcquire(pState, VERR_SEM_BUSY, RT_SRC_POS) == VINF_SUCCESS))
2718 {
2719 E1K_INC_ISTAT_CNT(pState->uStatTAD);
2720 /* Cancel interrupt delay timer as we have already got attention */
2721 e1kCancelTimer(pState, pState->CTX_SUFF(pTIDTimer));
2722 e1kRaiseInterrupt(pState, ICR_TXDW);
2723 e1kMutexRelease(pState);
2724 }
2725}
2726#endif /* E1K_USE_TX_TIMERS */
2727
2728#ifdef E1K_USE_RX_TIMERS
2729/**
2730 * Receive Interrupt Delay Timer handler.
2731 *
2732 * @remarks We only get here when the timer expires.
2733 *
2734 * @param pDevIns Pointer to device instance structure.
2735 * @param pTimer Pointer to the timer.
2736 * @param pvUser NULL.
2737 * @thread EMT
2738 */
2739static DECLCALLBACK(void) e1kRxIntDelayTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
2740{
2741 E1KSTATE *pState = (E1KSTATE *)pvUser;
2742
2743 if (RT_LIKELY(e1kMutexAcquire(pState, VERR_SEM_BUSY, RT_SRC_POS) == VINF_SUCCESS))
2744 {
2745 E1K_INC_ISTAT_CNT(pState->uStatRID);
2746 /* Cancel absolute delay timer as we have already got attention */
2747 e1kCancelTimer(pState, pState->CTX_SUFF(pRADTimer));
2748 e1kRaiseInterrupt(pState, ICR_RXT0);
2749 e1kMutexRelease(pState);
2750 }
2751}
2752
2753/**
2754 * Receive Absolute Delay Timer handler.
2755 *
2756 * @remarks We only get here when the timer expires.
2757 *
2758 * @param pDevIns Pointer to device instance structure.
2759 * @param pTimer Pointer to the timer.
2760 * @param pvUser NULL.
2761 * @thread EMT
2762 */
2763static DECLCALLBACK(void) e1kRxAbsDelayTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
2764{
2765 E1KSTATE *pState = (E1KSTATE *)pvUser;
2766
2767 if (RT_LIKELY(e1kMutexAcquire(pState, VERR_SEM_BUSY, RT_SRC_POS) == VINF_SUCCESS))
2768 {
2769 E1K_INC_ISTAT_CNT(pState->uStatRAD);
2770 /* Cancel interrupt delay timer as we have already got attention */
2771 e1kCancelTimer(pState, pState->CTX_SUFF(pRIDTimer));
2772 e1kRaiseInterrupt(pState, ICR_RXT0);
2773 e1kMutexRelease(pState);
2774 }
2775}
2776#endif /* E1K_USE_RX_TIMERS */
2777
2778/**
2779 * Late Interrupt Timer handler.
2780 *
2781 * @param pDevIns Pointer to device instance structure.
2782 * @param pTimer Pointer to the timer.
2783 * @param pvUser NULL.
2784 * @thread EMT
2785 */
2786static DECLCALLBACK(void) e1kLateIntTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
2787{
2788 E1KSTATE *pState = (E1KSTATE *)pvUser;
2789
2790 STAM_PROFILE_ADV_START(&pState->StatLateIntTimer, a);
2791 if (RT_LIKELY(e1kMutexAcquire(pState, VERR_SEM_BUSY, RT_SRC_POS) == VINF_SUCCESS))
2792 {
2793 STAM_COUNTER_INC(&pState->StatLateInts);
2794 E1K_INC_ISTAT_CNT(pState->uStatIntLate);
2795#if 0
2796 if (pState->iStatIntLost > -100)
2797 pState->iStatIntLost--;
2798#endif
2799 e1kRaiseInterrupt(pState, VERR_SEM_BUSY, 0);
2800 e1kMutexRelease(pState);
2801 }
2802 STAM_PROFILE_ADV_STOP(&pState->StatLateIntTimer, a);
2803}
2804
2805/**
2806 * Link Up Timer handler.
2807 *
2808 * @param pDevIns Pointer to device instance structure.
2809 * @param pTimer Pointer to the timer.
2810 * @param pvUser NULL.
2811 * @thread EMT
2812 */
2813static DECLCALLBACK(void) e1kLinkUpTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
2814{
2815 E1KSTATE *pState = (E1KSTATE *)pvUser;
2816
2817 if (RT_LIKELY(e1kMutexAcquire(pState, VERR_SEM_BUSY, RT_SRC_POS) == VINF_SUCCESS))
2818 {
2819 STATUS |= STATUS_LU;
2820 Phy::setLinkStatus(&pState->phy, true);
2821 e1kRaiseInterrupt(pState, VERR_SEM_BUSY, ICR_LSC);
2822 e1kMutexRelease(pState);
2823 }
2824}
2825
2826
2827
2828/**
2829 * Sets up the GSO context according to the TSE new context descriptor.
2830 *
2831 * @param pGso The GSO context to setup.
2832 * @param pCtx The context descriptor.
2833 */
2834DECLINLINE(void) e1kSetupGsoCtx(PPDMNETWORKGSO pGso, E1KTXCTX const *pCtx)
2835{
2836 pGso->u8Type = PDMNETWORKGSOTYPE_INVALID;
2837
2838 /*
2839 * See if the context descriptor describes something that could be TCP or
2840 * UDP over IPv[46].
2841 */
2842 /* Check the header ordering and spacing: 1. Ethernet, 2. IP, 3. TCP/UDP. */
2843 if (RT_UNLIKELY( pCtx->ip.u8CSS < sizeof(RTNETETHERHDR) ))
2844 return;
2845 if (RT_UNLIKELY( pCtx->tu.u8CSS < (size_t)pCtx->ip.u8CSS + (pCtx->dw2.fIP ? RTNETIPV4_MIN_LEN : RTNETIPV6_MIN_LEN) ))
2846 return;
2847 if (RT_UNLIKELY( pCtx->dw2.fTCP
2848 ? pCtx->dw3.u8HDRLEN < (size_t)pCtx->tu.u8CSS + RTNETTCP_MIN_LEN
2849 : pCtx->dw3.u8HDRLEN != (size_t)pCtx->tu.u8CSS + RTNETUDP_MIN_LEN ))
2850 return;
2851
2852 /* The end of the TCP/UDP checksum should stop at the end of the packet or at least after the headers. */
2853 if (RT_UNLIKELY( pCtx->tu.u16CSE > 0 && pCtx->tu.u16CSE <= pCtx->dw3.u8HDRLEN ))
2854 return;
2855
2856 /* IPv4 checksum offset. */
2857 if (RT_UNLIKELY( pCtx->dw2.fIP && pCtx->ip.u8CSO - pCtx->ip.u8CSS != RT_OFFSETOF(RTNETIPV4, ip_sum) ))
2858 return;
2859
2860 /* TCP/UDP checksum offsets. */
2861 if (RT_UNLIKELY( pCtx->tu.u8CSO - pCtx->tu.u8CSS != ( pCtx->dw2.fTCP
2862 ? RT_OFFSETOF(RTNETTCP, th_sum)
2863 : RT_OFFSETOF(RTNETUDP, uh_sum) ) ))
2864 return;
2865
2866 /*
2867 * We're good for now - we'll do more checks when seeing the data.
2868 * So, figure the type of offloading and setup the context.
2869 */
2870 if (pCtx->dw2.fIP)
2871 {
2872 if (pCtx->dw2.fTCP)
2873 pGso->u8Type = PDMNETWORKGSOTYPE_IPV4_TCP;
2874 else
2875 pGso->u8Type = PDMNETWORKGSOTYPE_IPV4_UDP;
2876 /** @todo Detect IPv4-IPv6 tunneling (need test setup since linux doesn't do
2877 * this yet it seems)... */
2878 }
2879 else
2880 {
2881 if (pCtx->dw2.fTCP)
2882 pGso->u8Type = PDMNETWORKGSOTYPE_IPV6_TCP;
2883 else
2884 pGso->u8Type = PDMNETWORKGSOTYPE_IPV6_UDP;
2885 }
2886 pGso->offHdr1 = pCtx->ip.u8CSS;
2887 pGso->offHdr2 = pCtx->tu.u8CSS;
2888 pGso->cbHdrs = pCtx->dw3.u8HDRLEN;
2889 pGso->cbMaxSeg = pCtx->dw3.u16MSS;
2890 Assert(PDMNetGsoIsValid(pGso, sizeof(*pGso), pGso->cbMaxSeg * 5));
2891}
2892
2893/**
2894 * Checks if we can use GSO processing for the current TSE frame.
2895 *
2896 * @param pGso The GSO context.
2897 * @param pData The first data descriptor of the frame.
2898 */
2899DECLINLINE(bool) e1kCanDoGso(PCPDMNETWORKGSO pGso, E1KTXDAT const *pData)
2900{
2901//return false; /** @todo remove this before comitting */
2902 if (!pData->cmd.fTSE)
2903 return false;
2904 if (pData->cmd.fVLE) /** @todo VLAN tagging. */
2905 return false;
2906
2907 switch ((PDMNETWORKGSOTYPE)pGso->u8Type)
2908 {
2909 case PDMNETWORKGSOTYPE_IPV4_TCP:
2910 case PDMNETWORKGSOTYPE_IPV4_UDP:
2911 if (!pData->dw3.fIXSM)
2912 return false;
2913 if (!pData->dw3.fTXSM)
2914 return false;
2915 /** @todo what more check should we perform here? Ethernet frame type? */
2916 return true;
2917
2918 case PDMNETWORKGSOTYPE_IPV6_TCP:
2919 case PDMNETWORKGSOTYPE_IPV6_UDP:
2920 if (pData->dw3.fIXSM)
2921 return false;
2922 if (!pData->dw3.fTXSM)
2923 return false;
2924 /** @todo what more check should we perform here? Ethernet frame type? */
2925 return true;
2926
2927 default:
2928 Assert(pGso->u8Type == PDMNETWORKGSOTYPE_INVALID);
2929 return false;
2930 }
2931}
2932
2933/**
2934 * Frees the current xmit buffer.
2935 *
2936 * @param pState The device state structure.
2937 */
2938static void e1kXmitFreeBuf(E1KSTATE *pState)
2939{
2940 PPDMSCATTERGATHER pSg = pState->pTxSgR3;
2941 if (pSg)
2942 {
2943 pState->pTxSgR3 = NULL;
2944
2945 if (pSg->pvAllocator != pState)
2946 {
2947 PPDMINETWORKUP pDrv = pState->pDrv;
2948 if (pDrv)
2949 pDrv->pfnFreeBuf(pDrv, pSg);
2950 }
2951 else
2952 {
2953 /* loopback */
2954 AssertCompileMemberSize(E1KSTATE, uTxFallback.Sg, 8 * sizeof(size_t));
2955 Assert(pSg->fFlags == (PDMSCATTERGATHER_FLAGS_MAGIC | PDMSCATTERGATHER_FLAGS_OWNER_3));
2956 pSg->fFlags = 0;
2957 pSg->pvAllocator = NULL;
2958 }
2959 }
2960}
2961
2962/**
2963 * Allocates a xmit buffer.
2964 *
2965 * Presently this will always return a buffer. Later on we'll have a
2966 * out-of-buffer mechanism in place where the driver calls us back when buffers
2967 * becomes available.
2968 *
2969 * @returns See PDMINETWORKUP::pfnAllocBuf.
2970 * @param pState The device state structure.
2971 * @param cbMin The minimum frame size.
2972 * @param fExactSize Whether cbMin is exact or if we have to max it
2973 * out to the max MTU size.
2974 * @param fGso Whether this is a GSO frame or not.
2975 */
2976DECLINLINE(int) e1kXmitAllocBuf(E1KSTATE *pState, size_t cbMin, bool fExactSize, bool fGso)
2977{
2978 /* Adjust cbMin if necessary. */
2979 if (!fExactSize)
2980 cbMin = RT_MAX(cbMin, E1K_MAX_TX_PKT_SIZE);
2981
2982 /* Deal with existing buffer (descriptor screw up, reset, etc). */
2983 if (RT_UNLIKELY(pState->pTxSgR3))
2984 e1kXmitFreeBuf(pState);
2985 Assert(pState->pTxSgR3 == NULL);
2986
2987 /*
2988 * Allocate the buffe.r
2989 */
2990 PPDMSCATTERGATHER pSg;
2991 if (RT_LIKELY(GET_BITS(RCTL, LBM) != RCTL_LBM_TCVR))
2992 {
2993 PPDMINETWORKUP pDrv = pState->pDrv;
2994 if (RT_UNLIKELY(!pDrv))
2995 return VERR_NET_DOWN;
2996 int rc = pDrv->pfnAllocBuf(pDrv, cbMin, fGso ? &pState->GsoCtx : NULL, &pSg);
2997 if (RT_FAILURE(rc))
2998 return rc;
2999 }
3000 else
3001 {
3002 /* Create a loopback using the fallback buffer and preallocated SG. */
3003 AssertCompileMemberSize(E1KSTATE, uTxFallback.Sg, 8 * sizeof(size_t));
3004 pSg = &pState->uTxFallback.Sg;
3005 pSg->fFlags = PDMSCATTERGATHER_FLAGS_MAGIC | PDMSCATTERGATHER_FLAGS_OWNER_3;
3006 pSg->cbUsed = 0;
3007 pSg->cbAvailable = 0;
3008 pSg->pvAllocator = pState;
3009 pSg->pvUser = NULL; /* No GSO here. */
3010 pSg->cSegs = 1;
3011 pSg->aSegs[0].pvSeg = pState->aTxPacketFallback;
3012 pSg->aSegs[0].cbSeg = sizeof(pState->aTxPacketFallback);
3013 }
3014
3015 pState->pTxSgR3 = pSg;
3016 return VINF_SUCCESS;
3017}
3018
3019/**
3020 * Checks if it's a GSO buffer or not.
3021 *
3022 * @returns true / false.
3023 * @param pTxSg The scatter / gather buffer.
3024 */
3025DECLINLINE(bool) e1kXmitIsGsoBuf(PDMSCATTERGATHER const *pTxSg)
3026{
3027 return pTxSg && pTxSg->pvUser /* GSO indicator */;
3028}
3029
3030/**
3031 * Load transmit descriptor from guest memory.
3032 *
3033 * @param pState The device state structure.
3034 * @param pDesc Pointer to descriptor union.
3035 * @param addr Physical address in guest context.
3036 * @thread E1000_TX
3037 */
3038DECLINLINE(void) e1kLoadDesc(E1KSTATE* pState, E1KTXDESC* pDesc, RTGCPHYS addr)
3039{
3040 PDMDevHlpPhysRead(pState->CTX_SUFF(pDevIns), addr, pDesc, sizeof(E1KTXDESC));
3041}
3042
3043/**
3044 * Write back transmit descriptor to guest memory.
3045 *
3046 * @param pState The device state structure.
3047 * @param pDesc Pointer to descriptor union.
3048 * @param addr Physical address in guest context.
3049 * @thread E1000_TX
3050 */
3051DECLINLINE(void) e1kWriteBackDesc(E1KSTATE* pState, E1KTXDESC* pDesc, RTGCPHYS addr)
3052{
3053 /* Only the last half of the descriptor has to be written back. */
3054 e1kPrintTDesc(pState, pDesc, "^^^");
3055 PDMDevHlpPhysWrite(pState->CTX_SUFF(pDevIns), addr, pDesc, sizeof(E1KTXDESC));
3056}
3057
3058/**
3059 * Transmit complete frame.
3060 *
3061 * @remarks We skip the FCS since we're not responsible for sending anything to
3062 * a real ethernet wire.
3063 *
3064 * @param pState The device state structure.
3065 * @thread E1000_TX
3066 */
3067static void e1kTransmitFrame(E1KSTATE* pState)
3068{
3069 PPDMSCATTERGATHER pSg = pState->pTxSgR3;
3070 uint32_t const cbFrame = pSg ? (size_t)pSg->cbUsed : 0;
3071 Assert(!pSg || pSg->cSegs == 1);
3072
3073/* E1kLog2(("%s <<< Outgoing packet. Dump follows: >>>\n"
3074 "%.*Rhxd\n"
3075 "%s <<<<<<<<<<<<< End of dump >>>>>>>>>>>>\n",
3076 INSTANCE(pState), cbFrame, pSg->aSegs[0].pvSeg, INSTANCE(pState)));*/
3077
3078#ifdef E1K_LEDS_WITH_MUTEX
3079 if (RT_LIKELY(e1kCsEnter(pState, VERR_SEM_BUSY, RT_SRC_POS) == VINF_SUCCESS))
3080 {
3081#endif /* E1K_LEDS_WITH_MUTEX */
3082 pState->led.Asserted.s.fWriting = 1;
3083 pState->led.Actual.s.fWriting = 1;
3084#ifdef E1K_LEDS_WITH_MUTEX
3085 e1kCsLeave(pState);
3086 }
3087#endif /* E1K_LEDS_WITH_MUTEX */
3088 /* Update the stats */
3089 E1K_INC_CNT32(TPT);
3090 E1K_ADD_CNT64(TOTL, TOTH, cbFrame);
3091 E1K_INC_CNT32(GPTC);
3092 if (pSg && e1kIsBroadcast(pSg->aSegs[0].pvSeg))
3093 E1K_INC_CNT32(BPTC);
3094 else if (pSg && e1kIsMulticast(pSg->aSegs[0].pvSeg))
3095 E1K_INC_CNT32(MPTC);
3096 /* Update octet transmit counter */
3097 E1K_ADD_CNT64(GOTCL, GOTCH, cbFrame);
3098 if (pState->pDrv)
3099 STAM_REL_COUNTER_ADD(&pState->StatTransmitBytes, cbFrame);
3100 if (cbFrame == 64)
3101 E1K_INC_CNT32(PTC64);
3102 else if (cbFrame < 128)
3103 E1K_INC_CNT32(PTC127);
3104 else if (cbFrame < 256)
3105 E1K_INC_CNT32(PTC255);
3106 else if (cbFrame < 512)
3107 E1K_INC_CNT32(PTC511);
3108 else if (cbFrame < 1024)
3109 E1K_INC_CNT32(PTC1023);
3110 else
3111 E1K_INC_CNT32(PTC1522);
3112
3113 E1K_INC_ISTAT_CNT(pState->uStatTxFrm);
3114
3115 /*
3116 * Dump and send the packet.
3117 */
3118 int rc = VERR_NET_DOWN;
3119 if (pSg && pSg->pvAllocator != pState)
3120 {
3121 e1kPacketDump(pState, (uint8_t const *)pSg->aSegs[0].pvSeg, cbFrame, "--> Outgoing");
3122
3123 pState->pTxSgR3 = NULL;
3124 PPDMINETWORKUP pDrv = pState->pDrv;
3125 if (pDrv)
3126 {
3127 /* Release critical section to avoid deadlock in CanReceive */
3128 //e1kCsLeave(pState);
3129 e1kMutexRelease(pState);
3130 STAM_PROFILE_START(&pState->StatTransmitSend, a);
3131 rc = pDrv->pfnSendBuf(pDrv, pSg, true /*fOnWorkerThread*/);
3132 STAM_PROFILE_STOP(&pState->StatTransmitSend, a);
3133 e1kMutexAcquire(pState, VERR_SEM_BUSY, RT_SRC_POS);
3134 //e1kCsEnter(pState, RT_SRC_POS);
3135 }
3136 }
3137 else if (pSg)
3138 {
3139 Assert(pSg->aSegs[0].pvSeg == pState->aTxPacketFallback);
3140 e1kPacketDump(pState, (uint8_t const *)pSg->aSegs[0].pvSeg, cbFrame, "--> Loopback");
3141
3142 /** @todo do we actually need to check that we're in loopback mode here? */
3143 if (GET_BITS(RCTL, LBM) == RCTL_LBM_TCVR)
3144 {
3145 E1KRXDST status;
3146 status.fPIF = true;
3147 e1kHandleRxPacket(pState, pSg->aSegs[0].pvSeg, cbFrame, status);
3148 rc = VINF_SUCCESS;
3149 }
3150 e1kXmitFreeBuf(pState);
3151 }
3152 else
3153 rc = VERR_NET_DOWN;
3154 if (RT_FAILURE(rc))
3155 {
3156 E1kLogRel(("E1000: ERROR! pfnSend returned %Rrc\n", rc));
3157 /** @todo handle VERR_NET_DOWN and VERR_NET_NO_BUFFER_SPACE. Signal error ? */
3158 }
3159
3160#ifdef E1K_LEDS_WITH_MUTEX
3161 if (RT_LIKELY(e1kCsEnter(pState, VERR_SEM_BUSY, RT_SRC_POS) == VINF_SUCCESS))
3162 {
3163#endif /* E1K_LEDS_WITH_MUTEX */
3164 pState->led.Actual.s.fWriting = 0;
3165#ifdef E1K_LEDS_WITH_MUTEX
3166 e1kCsLeave(pState);
3167 }
3168#endif /* E1K_LEDS_WITH_MUTEX */
3169}
3170
3171/**
3172 * Compute and write internet checksum (e1kCSum16) at the specified offset.
3173 *
3174 * @param pState The device state structure.
3175 * @param pPkt Pointer to the packet.
3176 * @param u16PktLen Total length of the packet.
3177 * @param cso Offset in packet to write checksum at.
3178 * @param css Offset in packet to start computing
3179 * checksum from.
3180 * @param cse Offset in packet to stop computing
3181 * checksum at.
3182 * @thread E1000_TX
3183 */
3184static void e1kInsertChecksum(E1KSTATE* pState, uint8_t *pPkt, uint16_t u16PktLen, uint8_t cso, uint8_t css, uint16_t cse)
3185{
3186 if (cso > u16PktLen)
3187 {
3188 E1kLog2(("%s cso(%X) is greater than packet length(%X), checksum is not inserted\n",
3189 INSTANCE(pState), cso, u16PktLen));
3190 return;
3191 }
3192
3193 if (cse == 0)
3194 cse = u16PktLen - 1;
3195 uint16_t u16ChkSum = e1kCSum16(pPkt + css, cse - css + 1);
3196 E1kLog2(("%s Inserting csum: %04X at %02X, old value: %04X\n", INSTANCE(pState),
3197 u16ChkSum, cso, *(uint16_t*)(pPkt + cso)));
3198 *(uint16_t*)(pPkt + cso) = u16ChkSum;
3199}
3200
3201/**
3202 * Add a part of descriptor's buffer to transmit frame.
3203 *
3204 * @remarks data.u64BufAddr is used uncoditionally for both data
3205 * and legacy descriptors since it is identical to
3206 * legacy.u64BufAddr.
3207 *
3208 * @param pState The device state structure.
3209 * @param pDesc Pointer to the descriptor to transmit.
3210 * @param u16Len Length of buffer to the end of segment.
3211 * @param fSend Force packet sending.
3212 * @param pSgBuf The current scatter gather buffer.
3213 * @thread E1000_TX
3214 */
3215static void e1kFallbackAddSegment(E1KSTATE* pState, RTGCPHYS PhysAddr, uint16_t u16Len, bool fSend)
3216{
3217 /* TCP header being transmitted */
3218 struct E1kTcpHeader *pTcpHdr = (struct E1kTcpHeader *)
3219 (pState->aTxPacketFallback + pState->contextTSE.tu.u8CSS);
3220 /* IP header being transmitted */
3221 struct E1kIpHeader *pIpHdr = (struct E1kIpHeader *)
3222 (pState->aTxPacketFallback + pState->contextTSE.ip.u8CSS);
3223
3224 E1kLog3(("%s e1kFallbackAddSegment: Length=%x, remaining payload=%x, header=%x, send=%RTbool\n",
3225 INSTANCE(pState), u16Len, pState->u32PayRemain, pState->u16HdrRemain, fSend));
3226 Assert(pState->u32PayRemain + pState->u16HdrRemain > 0);
3227
3228 PDMDevHlpPhysRead(pState->CTX_SUFF(pDevIns), PhysAddr,
3229 pState->aTxPacketFallback + pState->u16TxPktLen, u16Len);
3230 E1kLog3(("%s Dump of the segment:\n"
3231 "%.*Rhxd\n"
3232 "%s --- End of dump ---\n",
3233 INSTANCE(pState), u16Len, pState->aTxPacketFallback + pState->u16TxPktLen, INSTANCE(pState)));
3234 pState->u16TxPktLen += u16Len;
3235 E1kLog3(("%s e1kFallbackAddSegment: pState->u16TxPktLen=%x\n",
3236 INSTANCE(pState), pState->u16TxPktLen));
3237 if (pState->u16HdrRemain > 0)
3238 {
3239 /* The header was not complete, check if it is now */
3240 if (u16Len >= pState->u16HdrRemain)
3241 {
3242 /* The rest is payload */
3243 u16Len -= pState->u16HdrRemain;
3244 pState->u16HdrRemain = 0;
3245 /* Save partial checksum and flags */
3246 pState->u32SavedCsum = pTcpHdr->chksum;
3247 pState->u16SavedFlags = pTcpHdr->hdrlen_flags;
3248 /* Clear FIN and PSH flags now and set them only in the last segment */
3249 pTcpHdr->hdrlen_flags &= ~htons(E1K_TCP_FIN | E1K_TCP_PSH);
3250 }
3251 else
3252 {
3253 /* Still not */
3254 pState->u16HdrRemain -= u16Len;
3255 E1kLog3(("%s e1kFallbackAddSegment: Header is still incomplete, 0x%x bytes remain.\n",
3256 INSTANCE(pState), pState->u16HdrRemain));
3257 return;
3258 }
3259 }
3260
3261 pState->u32PayRemain -= u16Len;
3262
3263 if (fSend)
3264 {
3265 /* Leave ethernet header intact */
3266 /* IP Total Length = payload + headers - ethernet header */
3267 pIpHdr->total_len = htons(pState->u16TxPktLen - pState->contextTSE.ip.u8CSS);
3268 E1kLog3(("%s e1kFallbackAddSegment: End of packet, pIpHdr->total_len=%x\n",
3269 INSTANCE(pState), ntohs(pIpHdr->total_len)));
3270 /* Update IP Checksum */
3271 pIpHdr->chksum = 0;
3272 e1kInsertChecksum(pState, pState->aTxPacketFallback, pState->u16TxPktLen,
3273 pState->contextTSE.ip.u8CSO,
3274 pState->contextTSE.ip.u8CSS,
3275 pState->contextTSE.ip.u16CSE);
3276
3277 /* Update TCP flags */
3278 /* Restore original FIN and PSH flags for the last segment */
3279 if (pState->u32PayRemain == 0)
3280 {
3281 pTcpHdr->hdrlen_flags = pState->u16SavedFlags;
3282 E1K_INC_CNT32(TSCTC);
3283 }
3284 /** @todo else: inc TSCTFC, see EOP description in 3.3.7.1. */
3285 /* Add TCP length to partial pseudo header sum */
3286 uint32_t csum = pState->u32SavedCsum
3287 + htons(pState->u16TxPktLen - pState->contextTSE.tu.u8CSS);
3288 while (csum >> 16)
3289 csum = (csum >> 16) + (csum & 0xFFFF);
3290 pTcpHdr->chksum = csum;
3291 /* Compute final checksum */
3292 e1kInsertChecksum(pState, pState->aTxPacketFallback, pState->u16TxPktLen,
3293 pState->contextTSE.tu.u8CSO,
3294 pState->contextTSE.tu.u8CSS,
3295 pState->contextTSE.tu.u16CSE);
3296
3297 /*
3298 * Transmit it. If we've use the SG already, allocate a new one before
3299 * we copy of the data.
3300 */
3301 if (!pState->pTxSgR3)
3302 e1kXmitAllocBuf(pState, pState->u16TxPktLen, true /*fExactSize*/, false /*fGso*/);
3303 if (pState->pTxSgR3)
3304 {
3305 Assert(pState->u16TxPktLen <= pState->pTxSgR3->cbAvailable);
3306 Assert(pState->pTxSgR3->cSegs == 1);
3307 if (pState->pTxSgR3->aSegs[0].pvSeg != pState->aTxPacketFallback)
3308 memcpy(pState->pTxSgR3->aSegs[0].pvSeg, pState->aTxPacketFallback, pState->u16TxPktLen);
3309 pState->pTxSgR3->cbUsed = pState->u16TxPktLen;
3310 pState->pTxSgR3->aSegs[0].cbSeg = pState->u16TxPktLen;
3311 }
3312 e1kTransmitFrame(pState);
3313
3314 /* Update Sequence Number */
3315 pTcpHdr->seqno = htonl(ntohl(pTcpHdr->seqno) + pState->u16TxPktLen
3316 - pState->contextTSE.dw3.u8HDRLEN);
3317 /* Increment IP identification */
3318 pIpHdr->ident = htons(ntohs(pIpHdr->ident) + 1);
3319 }
3320}
3321
3322/**
3323 * TCP segmentation offloading fallback: Add descriptor's buffer to transmit
3324 * frame.
3325 *
3326 * We construct the frame in the fallback buffer first and the copy it to the SG
3327 * buffer before passing it down to the network driver code.
3328 *
3329 * @returns true if the frame should be transmitted, false if not.
3330 *
3331 * @param pState The device state structure.
3332 * @param pDesc Pointer to the descriptor to transmit.
3333 * @param cbFragment Length of descriptor's buffer.
3334 * @thread E1000_TX
3335 */
3336static bool e1kFallbackAddToFrame(E1KSTATE* pState, E1KTXDESC* pDesc, uint32_t cbFragment)
3337{
3338 PPDMSCATTERGATHER pTxSg = pState->pTxSgR3;
3339 Assert(e1kGetDescType(pDesc) == E1K_DTYP_DATA);
3340 Assert(pDesc->data.cmd.fTSE);
3341 Assert(!e1kXmitIsGsoBuf(pTxSg));
3342
3343 uint16_t u16MaxPktLen = pState->contextTSE.dw3.u8HDRLEN + pState->contextTSE.dw3.u16MSS;
3344 Assert(u16MaxPktLen != 0);
3345 Assert(u16MaxPktLen < E1K_MAX_TX_PKT_SIZE);
3346
3347 /*
3348 * Carve out segments.
3349 */
3350 do
3351 {
3352 /* Calculate how many bytes we have left in this TCP segment */
3353 uint32_t cb = u16MaxPktLen - pState->u16TxPktLen;
3354 if (cb > cbFragment)
3355 {
3356 /* This descriptor fits completely into current segment */
3357 cb = cbFragment;
3358 e1kFallbackAddSegment(pState, pDesc->data.u64BufAddr, cb, pDesc->data.cmd.fEOP /*fSend*/);
3359 }
3360 else
3361 {
3362 e1kFallbackAddSegment(pState, pDesc->data.u64BufAddr, cb, true /*fSend*/);
3363 /*
3364 * Rewind the packet tail pointer to the beginning of payload,
3365 * so we continue writing right beyond the header.
3366 */
3367 pState->u16TxPktLen = pState->contextTSE.dw3.u8HDRLEN;
3368 }
3369
3370 pDesc->data.u64BufAddr += cb;
3371 cbFragment -= cb;
3372 } while (cbFragment > 0);
3373
3374 if (pDesc->data.cmd.fEOP)
3375 {
3376 /* End of packet, next segment will contain header. */
3377 pState->u16TxPktLen = 0;
3378 e1kXmitFreeBuf(pState);
3379 }
3380
3381 return false;
3382}
3383
3384
3385/**
3386 * Add descriptor's buffer to transmit frame.
3387 *
3388 * This deals with GSO and normal frames, e1kFallbackAddToFrame deals with the
3389 * TSE frames we cannot handle as GSO.
3390 *
3391 * @returns true on success, false on failure.
3392 *
3393 * @param pThis The device state structure.
3394 * @param PhysAddr The physical address of the descriptor buffer.
3395 * @param cbFragment Length of descriptor's buffer.
3396 * @thread E1000_TX
3397 */
3398static bool e1kAddToFrame(E1KSTATE *pThis, RTGCPHYS PhysAddr, uint32_t cbFragment)
3399{
3400 PPDMSCATTERGATHER pTxSg = pThis->pTxSgR3;
3401 bool const fGso = e1kXmitIsGsoBuf(pTxSg);
3402 uint32_t const cbNewPkt = cbFragment + pThis->u16TxPktLen;
3403
3404 if (RT_UNLIKELY( !fGso && cbNewPkt > E1K_MAX_TX_PKT_SIZE ))
3405 {
3406 E1kLog(("%s Transmit packet is too large: %u > %u(max)\n", INSTANCE(pThis), cbNewPkt, E1K_MAX_TX_PKT_SIZE));
3407 return false;
3408 }
3409 if (RT_UNLIKELY( fGso && cbNewPkt > pTxSg->cbAvailable ))
3410 {
3411 E1kLog(("%s Transmit packet is too large: %u > %u(max)/GSO\n", INSTANCE(pThis), cbNewPkt, pTxSg->cbAvailable));
3412 return false;
3413 }
3414
3415 if (RT_LIKELY(pTxSg))
3416 {
3417 Assert(pTxSg->cSegs == 1);
3418 Assert(pTxSg->cbUsed == pThis->u16TxPktLen);
3419
3420 PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns), PhysAddr,
3421 (uint8_t *)pTxSg->aSegs[0].pvSeg + pThis->u16TxPktLen, cbFragment);
3422
3423 pTxSg->cbUsed = cbNewPkt;
3424 }
3425 pThis->u16TxPktLen = cbNewPkt;
3426
3427 return true;
3428}
3429
3430
3431/**
3432 * Write the descriptor back to guest memory and notify the guest.
3433 *
3434 * @param pState The device state structure.
3435 * @param pDesc Pointer to the descriptor have been transmited.
3436 * @param addr Physical address of the descriptor in guest memory.
3437 * @thread E1000_TX
3438 */
3439static void e1kDescReport(E1KSTATE* pState, E1KTXDESC* pDesc, RTGCPHYS addr)
3440{
3441 /*
3442 * We fake descriptor write-back bursting. Descriptors are written back as they are
3443 * processed.
3444 */
3445 /* Let's pretend we process descriptors. Write back with DD set. */
3446 if (pDesc->legacy.cmd.fRS || (GET_BITS(TXDCTL, WTHRESH) > 0))
3447 {
3448 pDesc->legacy.dw3.fDD = 1; /* Descriptor Done */
3449 e1kWriteBackDesc(pState, pDesc, addr);
3450 if (pDesc->legacy.cmd.fEOP)
3451 {
3452#ifdef E1K_USE_TX_TIMERS
3453 if (pDesc->legacy.cmd.fIDE)
3454 {
3455 E1K_INC_ISTAT_CNT(pState->uStatTxIDE);
3456 //if (pState->fIntRaised)
3457 //{
3458 // /* Interrupt is already pending, no need for timers */
3459 // ICR |= ICR_TXDW;
3460 //}
3461 //else {
3462 /* Arm the timer to fire in TIVD usec (discard .024) */
3463 e1kArmTimer(pState, pState->CTX_SUFF(pTIDTimer), TIDV);
3464# ifndef E1K_NO_TAD
3465 /* If absolute timer delay is enabled and the timer is not running yet, arm it. */
3466 E1kLog2(("%s Checking if TAD timer is running\n",
3467 INSTANCE(pState)));
3468 if (TADV != 0 && !TMTimerIsActive(pState->CTX_SUFF(pTADTimer)))
3469 e1kArmTimer(pState, pState->CTX_SUFF(pTADTimer), TADV);
3470# endif /* E1K_NO_TAD */
3471 }
3472 else
3473 {
3474 E1kLog2(("%s No IDE set, cancel TAD timer and raise interrupt\n",
3475 INSTANCE(pState)));
3476# ifndef E1K_NO_TAD
3477 /* Cancel both timers if armed and fire immediately. */
3478 e1kCancelTimer(pState, pState->CTX_SUFF(pTADTimer));
3479# endif /* E1K_NO_TAD */
3480#endif /* E1K_USE_TX_TIMERS */
3481 E1K_INC_ISTAT_CNT(pState->uStatIntTx);
3482 e1kRaiseInterrupt(pState, VERR_SEM_BUSY, ICR_TXDW);
3483#ifdef E1K_USE_TX_TIMERS
3484 }
3485#endif /* E1K_USE_TX_TIMERS */
3486 }
3487 }
3488 else
3489 {
3490 E1K_INC_ISTAT_CNT(pState->uStatTxNoRS);
3491 }
3492}
3493
3494/**
3495 * Process Transmit Descriptor.
3496 *
3497 * E1000 supports three types of transmit descriptors:
3498 * - legacy data descriptors of older format (context-less).
3499 * - data the same as legacy but providing new offloading capabilities.
3500 * - context sets up the context for following data descriptors.
3501 *
3502 * @param pState The device state structure.
3503 * @param pDesc Pointer to descriptor union.
3504 * @param addr Physical address of descriptor in guest memory.
3505 * @thread E1000_TX
3506 */
3507static void e1kXmitDesc(E1KSTATE* pState, E1KTXDESC* pDesc, RTGCPHYS addr)
3508{
3509 e1kPrintTDesc(pState, pDesc, "vvv");
3510
3511#ifdef E1K_USE_TX_TIMERS
3512 e1kCancelTimer(pState, pState->CTX_SUFF(pTIDTimer));
3513#endif /* E1K_USE_TX_TIMERS */
3514
3515 switch (e1kGetDescType(pDesc))
3516 {
3517 case E1K_DTYP_CONTEXT:
3518 if (pDesc->context.dw2.fTSE)
3519 {
3520 pState->contextTSE = pDesc->context;
3521 pState->u32PayRemain = pDesc->context.dw2.u20PAYLEN;
3522 pState->u16HdrRemain = pDesc->context.dw3.u8HDRLEN;
3523 e1kSetupGsoCtx(&pState->GsoCtx, &pDesc->context);
3524 }
3525 else
3526 pState->contextNormal = pDesc->context;
3527 E1kLog2(("%s %s context updated: IP CSS=%02X, IP CSO=%02X, IP CSE=%04X"
3528 ", TU CSS=%02X, TU CSO=%02X, TU CSE=%04X\n", INSTANCE(pState),
3529 pDesc->context.dw2.fTSE ? "TSE" : "Normal",
3530 pDesc->context.ip.u8CSS,
3531 pDesc->context.ip.u8CSO,
3532 pDesc->context.ip.u16CSE,
3533 pDesc->context.tu.u8CSS,
3534 pDesc->context.tu.u8CSO,
3535 pDesc->context.tu.u16CSE));
3536 E1K_INC_ISTAT_CNT(pState->uStatDescCtx);
3537 e1kDescReport(pState, pDesc, addr);
3538 break;
3539
3540 case E1K_DTYP_DATA:
3541 {
3542 if (pDesc->data.cmd.u20DTALEN == 0 || pDesc->data.u64BufAddr == 0)
3543 {
3544 E1kLog2(("% Empty data descriptor, skipped.\n", INSTANCE(pState)));
3545 /** @todo Same as legacy when !TSE. See below. */
3546 break;
3547 }
3548 STAM_COUNTER_INC(pDesc->data.cmd.fTSE?
3549 &pState->StatTxDescTSEData:
3550 &pState->StatTxDescData);
3551 STAM_PROFILE_ADV_START(&pState->StatTransmit, a);
3552 E1K_INC_ISTAT_CNT(pState->uStatDescDat);
3553
3554 /*
3555 * First fragment: Allocate new buffer and save the IXSM and TXSM
3556 * packet options as these are only valid in the first fragment.
3557 */
3558 if (pState->u16TxPktLen == 0)
3559 {
3560 pState->fIPcsum = pDesc->data.dw3.fIXSM;
3561 pState->fTCPcsum = pDesc->data.dw3.fTXSM;
3562 E1kLog2(("%s Saving checksum flags:%s%s; \n", INSTANCE(pState),
3563 pState->fIPcsum ? " IP" : "",
3564 pState->fTCPcsum ? " TCP/UDP" : ""));
3565 if (e1kCanDoGso(&pState->GsoCtx, &pDesc->data))
3566 e1kXmitAllocBuf(pState, pState->contextTSE.dw2.u20PAYLEN + pState->contextTSE.dw3.u8HDRLEN,
3567 true /*fExactSize*/, true /*fGso*/);
3568 else
3569 e1kXmitAllocBuf(pState, pState->contextTSE.dw3.u16MSS + pState->contextTSE.dw3.u8HDRLEN,
3570 pDesc->data.cmd.fTSE /*fExactSize*/, false /*fGso*/);
3571 /** @todo Is there any way to indicating errors other than collisions? Like
3572 * VERR_NET_DOWN. */
3573 }
3574
3575 /*
3576 * Add the descriptor data to the frame. If the frame is complete,
3577 * transmit it and reset the u16TxPktLen field.
3578 */
3579 if (e1kXmitIsGsoBuf(pState->pTxSgR3))
3580 {
3581 bool fRc = e1kAddToFrame(pState, pDesc->data.u64BufAddr, pDesc->data.cmd.u20DTALEN);
3582 if (pDesc->data.cmd.fEOP)
3583 {
3584 if ( fRc
3585 && pState->pTxSgR3
3586 && pState->pTxSgR3->cbUsed == (size_t)pState->contextTSE.dw3.u8HDRLEN + pState->contextTSE.dw2.u20PAYLEN)
3587 {
3588 e1kTransmitFrame(pState);
3589 E1K_INC_CNT32(TSCTC);
3590 }
3591 else
3592 {
3593 if (fRc)
3594 E1kLog(("%s bad GSO/TSE %p or %u < %u\n" , INSTANCE(pState),
3595 pState->pTxSgR3, pState->pTxSgR3 ? pState->pTxSgR3->cbUsed : 0,
3596 pState->contextTSE.dw3.u8HDRLEN + pState->contextTSE.dw2.u20PAYLEN));
3597 e1kXmitFreeBuf(pState);
3598 E1K_INC_CNT32(TSCTFC);
3599 }
3600 pState->u16TxPktLen = 0;
3601 }
3602 }
3603 else if (!pDesc->data.cmd.fTSE)
3604 {
3605 bool fRc = e1kAddToFrame(pState, pDesc->data.u64BufAddr, pDesc->data.cmd.u20DTALEN);
3606 if (pDesc->data.cmd.fEOP)
3607 {
3608 if (fRc && pState->pTxSgR3)
3609 {
3610 Assert(pState->pTxSgR3->cSegs == 1);
3611 if (pState->fIPcsum)
3612 e1kInsertChecksum(pState, (uint8_t *)pState->pTxSgR3->aSegs[0].pvSeg, pState->u16TxPktLen,
3613 pState->contextNormal.ip.u8CSO,
3614 pState->contextNormal.ip.u8CSS,
3615 pState->contextNormal.ip.u16CSE);
3616 if (pState->fTCPcsum)
3617 e1kInsertChecksum(pState, (uint8_t *)pState->pTxSgR3->aSegs[0].pvSeg, pState->u16TxPktLen,
3618 pState->contextNormal.tu.u8CSO,
3619 pState->contextNormal.tu.u8CSS,
3620 pState->contextNormal.tu.u16CSE);
3621 e1kTransmitFrame(pState);
3622 }
3623 else
3624 e1kXmitFreeBuf(pState);
3625 pState->u16TxPktLen = 0;
3626 }
3627 }
3628 else
3629 e1kFallbackAddToFrame(pState, pDesc, pDesc->data.cmd.u20DTALEN);
3630
3631 e1kDescReport(pState, pDesc, addr);
3632 STAM_PROFILE_ADV_STOP(&pState->StatTransmit, a);
3633 break;
3634 }
3635
3636 case E1K_DTYP_LEGACY:
3637 if (pDesc->legacy.cmd.u16Length == 0 || pDesc->legacy.u64BufAddr == 0)
3638 {
3639 E1kLog(("%s Empty legacy descriptor, skipped.\n", INSTANCE(pState)));
3640 /** @todo 3.3.3, Length/Buffer Address: RS set -> write DD when processing. */
3641 break;
3642 }
3643 STAM_COUNTER_INC(&pState->StatTxDescLegacy);
3644 STAM_PROFILE_ADV_START(&pState->StatTransmit, a);
3645
3646 /* First fragment: allocate new buffer. */
3647 if (pState->u16TxPktLen == 0)
3648 /** @todo reset status bits? */
3649 e1kXmitAllocBuf(pState, pDesc->legacy.cmd.u16Length, pDesc->legacy.cmd.fEOP, false /*fGso*/);
3650 /** @todo Is there any way to indicating errors other than collisions? Like
3651 * VERR_NET_DOWN. */
3652
3653 /* Add fragment to frame. */
3654 if (e1kAddToFrame(pState, pDesc->data.u64BufAddr, pDesc->legacy.cmd.u16Length))
3655 {
3656 E1K_INC_ISTAT_CNT(pState->uStatDescLeg);
3657
3658 /* Last fragment: Transmit and reset the packet storage counter. */
3659 if (pDesc->legacy.cmd.fEOP)
3660 {
3661 /** @todo Offload processing goes here. */
3662 e1kTransmitFrame(pState);
3663 pState->u16TxPktLen = 0;
3664 }
3665 }
3666 /* Last fragment + failure: free the buffer and reset the storage counter. */
3667 else if (pDesc->legacy.cmd.fEOP)
3668 {
3669 e1kXmitFreeBuf(pState);
3670 pState->u16TxPktLen = 0;
3671 }
3672
3673 e1kDescReport(pState, pDesc, addr);
3674 STAM_PROFILE_ADV_STOP(&pState->StatTransmit, a);
3675 break;
3676
3677 default:
3678 E1kLog(("%s ERROR Unsupported transmit descriptor type: 0x%04x\n",
3679 INSTANCE(pState), e1kGetDescType(pDesc)));
3680 break;
3681 }
3682}
3683
3684#ifdef VBOX_WITH_TX_THREAD_IN_NET_DEVICES
3685
3686/**
3687 * Wake up callback for transmission thread.
3688 *
3689 * @returns VBox status code. Returning failure will naturally terminate the thread.
3690 * @param pDevIns The pcnet device instance.
3691 * @param pThread The thread.
3692 */
3693static DECLCALLBACK(int) e1kTxThreadWakeUp(PPDMDEVINS pDevIns, PPDMTHREAD pThread)
3694{
3695 E1KSTATE *pState = PDMINS_2_DATA(pDevIns, E1KSTATE *);
3696 int rc = RTSemEventSignal(pState->hTxSem);
3697 AssertRC(rc);
3698 return VINF_SUCCESS;
3699}
3700
3701/**
3702 * I/O thread for packet transmission.
3703 *
3704 * @returns VBox status code. Returning failure will naturally terminate the thread.
3705 * @param pDevIns Pointer to device instance structure.
3706 * @param pThread The thread.
3707 * @thread E1000_TX
3708 */
3709static DECLCALLBACK(int) e1kTxThread(PPDMDEVINS pDevIns, PPDMTHREAD pThread)
3710{
3711 E1KSTATE *pState = PDMINS_2_DATA(pDevIns, E1KSTATE *);
3712
3713 while (pThread->enmState == PDMTHREADSTATE_RUNNING)
3714 {
3715 int rc = RTSemEventWait(pState->hTxSem, RT_INDEFINITE_WAIT);
3716 AssertRCReturn(rc, rc);
3717 if (RT_UNLIKELY(pThread->enmState != PDMTHREADSTATE_RUNNING))
3718 break;
3719
3720 if (pThread->enmState == PDMTHREADSTATE_RUNNING)
3721 {
3722 E1KTXDESC desc;
3723 rc = e1kMutexAcquire(pState, VERR_SEM_BUSY, RT_SRC_POS);
3724 AssertRCReturn(rc, rc);
3725 /* Do not process descriptors in locked state */
3726 while (TDH != TDT && !pState->fLocked)
3727 {
3728 E1kLog3(("%s About to process new TX descriptor at %08x%08x, TDLEN=%08x, TDH=%08x, TDT=%08x\n",
3729 INSTANCE(pState), TDBAH, TDBAL + TDH * sizeof(desc), TDLEN, TDH, TDT));
3730 //if (!e1kCsEnter(pState, RT_SRC_POS))
3731 // return VERR_PERMISSION_DENIED;
3732 e1kLoadDesc(pState, &desc, ((uint64_t)TDBAH << 32) + TDBAL + TDH * sizeof(desc));
3733 e1kXmitDesc(pState, &desc, ((uint64_t)TDBAH << 32) + TDBAL + TDH * sizeof(desc));
3734 if (++TDH * sizeof(desc) >= TDLEN)
3735 TDH = 0;
3736 if (e1kGetTxLen(pState) <= GET_BITS(TXDCTL, LWTHRESH)*8)
3737 {
3738 E1kLog2(("%s Low on transmit descriptors, raise ICR.TXD_LOW, len=%x thresh=%x\n",
3739 INSTANCE(pState), e1kGetTxLen(pState), GET_BITS(TXDCTL, LWTHRESH)*8));
3740 e1kRaiseInterrupt(pState, VERR_SEM_BUSY, ICR_TXD_LOW);
3741 }
3742 STAM_PROFILE_ADV_STOP(&pState->StatTransmit, a);
3743 //e1kCsLeave(pState);
3744 }
3745 /// @todo: uncomment: pState->uStatIntTXQE++;
3746 /// @todo: uncomment: e1kRaiseInterrupt(pState, ICR_TXQE);
3747 e1kMutexRelease(pState);
3748 }
3749 }
3750 return VINF_SUCCESS;
3751}
3752
3753#endif /* VBOX_WITH_TX_THREAD_IN_NET_DEVICES */
3754
3755/**
3756 * Callback for consuming from transmit queue. It gets called in R3 whenever
3757 * we enqueue something in R0/GC.
3758 *
3759 * @returns true
3760 * @param pDevIns Pointer to device instance structure.
3761 * @param pItem Pointer to the element being dequeued (not used).
3762 * @thread ???
3763 */
3764static DECLCALLBACK(bool) e1kTxQueueConsumer(PPDMDEVINS pDevIns, PPDMQUEUEITEMCORE pItem)
3765{
3766 NOREF(pItem);
3767 E1KSTATE *pState = PDMINS_2_DATA(pDevIns, E1KSTATE *);
3768 E1kLog2(("%s e1kTxQueueConsumer: Waking up TX thread...\n", INSTANCE(pState)));
3769 int rc = RTSemEventSignal(pState->hTxSem);
3770 AssertRC(rc);
3771 return true;
3772}
3773
3774/**
3775 * Handler for the wakeup signaller queue.
3776 */
3777static DECLCALLBACK(bool) e1kCanRxQueueConsumer(PPDMDEVINS pDevIns, PPDMQUEUEITEMCORE pItem)
3778{
3779 e1kWakeupReceive(pDevIns);
3780 return true;
3781}
3782
3783#endif /* IN_RING3 */
3784
3785/**
3786 * Write handler for Transmit Descriptor Tail register.
3787 *
3788 * @param pState The device state structure.
3789 * @param offset Register offset in memory-mapped frame.
3790 * @param index Register index in register array.
3791 * @param value The value to store.
3792 * @param mask Used to implement partial writes (8 and 16-bit).
3793 * @thread EMT
3794 */
3795static int e1kRegWriteTDT(E1KSTATE* pState, uint32_t offset, uint32_t index, uint32_t value)
3796{
3797#ifndef IN_RING3
3798// return VINF_IOM_HC_MMIO_WRITE;
3799#endif
3800 int rc = e1kCsTxEnter(pState, VINF_IOM_HC_MMIO_WRITE);
3801 if (RT_UNLIKELY(rc != VINF_SUCCESS))
3802 return rc;
3803 rc = e1kRegWriteDefault(pState, offset, index, value);
3804 /* All descriptors starting with head and not including tail belong to us. */
3805 /* Process them. */
3806 E1kLog2(("%s e1kRegWriteTDT: TDBAL=%08x, TDBAH=%08x, TDLEN=%08x, TDH=%08x, TDT=%08x\n",
3807 INSTANCE(pState), TDBAL, TDBAH, TDLEN, TDH, TDT));
3808 /* Ignore TDT writes when the link is down. */
3809 if (TDH != TDT && (STATUS & STATUS_LU))
3810 {
3811 E1kLogRel(("E1000: TDT write: %d descriptors to process\n", e1kGetTxLen(pState)));
3812 E1kLog(("%s e1kRegWriteTDT: %d descriptors to process, waking up E1000_TX thread\n",
3813 INSTANCE(pState), e1kGetTxLen(pState)));
3814#ifdef IN_RING3
3815 rc = RTSemEventSignal(pState->hTxSem);
3816 AssertRC(rc);
3817#else
3818 PPDMQUEUEITEMCORE pItem = PDMQueueAlloc(pState->CTX_SUFF(pTxQueue));
3819 if (RT_UNLIKELY(pItem))
3820 PDMQueueInsert(pState->CTX_SUFF(pTxQueue), pItem);
3821#endif /* !IN_RING3 */
3822
3823 }
3824 e1kCsTxLeave(pState);
3825
3826 return rc;
3827}
3828
3829/**
3830 * Write handler for Multicast Table Array registers.
3831 *
3832 * @param pState The device state structure.
3833 * @param offset Register offset in memory-mapped frame.
3834 * @param index Register index in register array.
3835 * @param value The value to store.
3836 * @thread EMT
3837 */
3838static int e1kRegWriteMTA(E1KSTATE* pState, uint32_t offset, uint32_t index, uint32_t value)
3839{
3840 AssertReturn(offset - s_e1kRegMap[index].offset < sizeof(pState->auMTA), VERR_DEV_IO_ERROR);
3841 pState->auMTA[(offset - s_e1kRegMap[index].offset)/sizeof(pState->auMTA[0])] = value;
3842
3843 return VINF_SUCCESS;
3844}
3845
3846/**
3847 * Read handler for Multicast Table Array registers.
3848 *
3849 * @returns VBox status code.
3850 *
3851 * @param pState The device state structure.
3852 * @param offset Register offset in memory-mapped frame.
3853 * @param index Register index in register array.
3854 * @thread EMT
3855 */
3856static int e1kRegReadMTA(E1KSTATE* pState, uint32_t offset, uint32_t index, uint32_t *pu32Value)
3857{
3858 AssertReturn(offset - s_e1kRegMap[index].offset< sizeof(pState->auMTA), VERR_DEV_IO_ERROR);
3859 *pu32Value = pState->auMTA[(offset - s_e1kRegMap[index].offset)/sizeof(pState->auMTA[0])];
3860
3861 return VINF_SUCCESS;
3862}
3863
3864/**
3865 * Write handler for Receive Address registers.
3866 *
3867 * @param pState The device state structure.
3868 * @param offset Register offset in memory-mapped frame.
3869 * @param index Register index in register array.
3870 * @param value The value to store.
3871 * @thread EMT
3872 */
3873static int e1kRegWriteRA(E1KSTATE* pState, uint32_t offset, uint32_t index, uint32_t value)
3874{
3875 AssertReturn(offset - s_e1kRegMap[index].offset < sizeof(pState->aRecAddr.au32), VERR_DEV_IO_ERROR);
3876 pState->aRecAddr.au32[(offset - s_e1kRegMap[index].offset)/sizeof(pState->aRecAddr.au32[0])] = value;
3877
3878 return VINF_SUCCESS;
3879}
3880
3881/**
3882 * Read handler for Receive Address registers.
3883 *
3884 * @returns VBox status code.
3885 *
3886 * @param pState The device state structure.
3887 * @param offset Register offset in memory-mapped frame.
3888 * @param index Register index in register array.
3889 * @thread EMT
3890 */
3891static int e1kRegReadRA(E1KSTATE* pState, uint32_t offset, uint32_t index, uint32_t *pu32Value)
3892{
3893 AssertReturn(offset - s_e1kRegMap[index].offset< sizeof(pState->aRecAddr.au32), VERR_DEV_IO_ERROR);
3894 *pu32Value = pState->aRecAddr.au32[(offset - s_e1kRegMap[index].offset)/sizeof(pState->aRecAddr.au32[0])];
3895
3896 return VINF_SUCCESS;
3897}
3898
3899/**
3900 * Write handler for VLAN Filter Table Array registers.
3901 *
3902 * @param pState The device state structure.
3903 * @param offset Register offset in memory-mapped frame.
3904 * @param index Register index in register array.
3905 * @param value The value to store.
3906 * @thread EMT
3907 */
3908static int e1kRegWriteVFTA(E1KSTATE* pState, uint32_t offset, uint32_t index, uint32_t value)
3909{
3910 AssertReturn(offset - s_e1kRegMap[index].offset < sizeof(pState->auVFTA), VINF_SUCCESS);
3911 pState->auVFTA[(offset - s_e1kRegMap[index].offset)/sizeof(pState->auVFTA[0])] = value;
3912
3913 return VINF_SUCCESS;
3914}
3915
3916/**
3917 * Read handler for VLAN Filter Table Array registers.
3918 *
3919 * @returns VBox status code.
3920 *
3921 * @param pState The device state structure.
3922 * @param offset Register offset in memory-mapped frame.
3923 * @param index Register index in register array.
3924 * @thread EMT
3925 */
3926static int e1kRegReadVFTA(E1KSTATE* pState, uint32_t offset, uint32_t index, uint32_t *pu32Value)
3927{
3928 AssertReturn(offset - s_e1kRegMap[index].offset< sizeof(pState->auVFTA), VERR_DEV_IO_ERROR);
3929 *pu32Value = pState->auVFTA[(offset - s_e1kRegMap[index].offset)/sizeof(pState->auVFTA[0])];
3930
3931 return VINF_SUCCESS;
3932}
3933
3934/**
3935 * Read handler for unimplemented registers.
3936 *
3937 * Merely reports reads from unimplemented registers.
3938 *
3939 * @returns VBox status code.
3940 *
3941 * @param pState The device state structure.
3942 * @param offset Register offset in memory-mapped frame.
3943 * @param index Register index in register array.
3944 * @thread EMT
3945 */
3946
3947static int e1kRegReadUnimplemented(E1KSTATE* pState, uint32_t offset, uint32_t index, uint32_t *pu32Value)
3948{
3949 E1kLog(("%s At %08X read (00000000) attempt from unimplemented register %s (%s)\n",
3950 INSTANCE(pState), offset, s_e1kRegMap[index].abbrev, s_e1kRegMap[index].name));
3951 *pu32Value = 0;
3952
3953 return VINF_SUCCESS;
3954}
3955
3956/**
3957 * Default register read handler with automatic clear operation.
3958 *
3959 * Retrieves the value of register from register array in device state structure.
3960 * Then resets all bits.
3961 *
3962 * @remarks The 'mask' parameter is simply ignored as masking and shifting is
3963 * done in the caller.
3964 *
3965 * @returns VBox status code.
3966 *
3967 * @param pState The device state structure.
3968 * @param offset Register offset in memory-mapped frame.
3969 * @param index Register index in register array.
3970 * @thread EMT
3971 */
3972
3973static int e1kRegReadAutoClear(E1KSTATE* pState, uint32_t offset, uint32_t index, uint32_t *pu32Value)
3974{
3975 AssertReturn(index < E1K_NUM_OF_32BIT_REGS, VERR_DEV_IO_ERROR);
3976 int rc = e1kRegReadDefault(pState, offset, index, pu32Value);
3977 pState->auRegs[index] = 0;
3978
3979 return rc;
3980}
3981
3982/**
3983 * Default register read handler.
3984 *
3985 * Retrieves the value of register from register array in device state structure.
3986 * Bits corresponding to 0s in 'readable' mask will always read as 0s.
3987 *
3988 * @remarks The 'mask' parameter is simply ignored as masking and shifting is
3989 * done in the caller.
3990 *
3991 * @returns VBox status code.
3992 *
3993 * @param pState The device state structure.
3994 * @param offset Register offset in memory-mapped frame.
3995 * @param index Register index in register array.
3996 * @thread EMT
3997 */
3998
3999static int e1kRegReadDefault(E1KSTATE* pState, uint32_t offset, uint32_t index, uint32_t *pu32Value)
4000{
4001 AssertReturn(index < E1K_NUM_OF_32BIT_REGS, VERR_DEV_IO_ERROR);
4002 *pu32Value = pState->auRegs[index] & s_e1kRegMap[index].readable;
4003
4004 return VINF_SUCCESS;
4005}
4006
4007/**
4008 * Write handler for unimplemented registers.
4009 *
4010 * Merely reports writes to unimplemented registers.
4011 *
4012 * @param pState The device state structure.
4013 * @param offset Register offset in memory-mapped frame.
4014 * @param index Register index in register array.
4015 * @param value The value to store.
4016 * @thread EMT
4017 */
4018
4019 static int e1kRegWriteUnimplemented(E1KSTATE* pState, uint32_t offset, uint32_t index, uint32_t value)
4020{
4021 E1kLog(("%s At %08X write attempt (%08X) to unimplemented register %s (%s)\n",
4022 INSTANCE(pState), offset, value, s_e1kRegMap[index].abbrev, s_e1kRegMap[index].name));
4023
4024 return VINF_SUCCESS;
4025}
4026
4027/**
4028 * Default register write handler.
4029 *
4030 * Stores the value to the register array in device state structure. Only bits
4031 * corresponding to 1s both in 'writable' and 'mask' will be stored.
4032 *
4033 * @returns VBox status code.
4034 *
4035 * @param pState The device state structure.
4036 * @param offset Register offset in memory-mapped frame.
4037 * @param index Register index in register array.
4038 * @param value The value to store.
4039 * @param mask Used to implement partial writes (8 and 16-bit).
4040 * @thread EMT
4041 */
4042
4043static int e1kRegWriteDefault(E1KSTATE* pState, uint32_t offset, uint32_t index, uint32_t value)
4044{
4045 AssertReturn(index < E1K_NUM_OF_32BIT_REGS, VERR_DEV_IO_ERROR);
4046 pState->auRegs[index] = (value & s_e1kRegMap[index].writable) |
4047 (pState->auRegs[index] & ~s_e1kRegMap[index].writable);
4048
4049 return VINF_SUCCESS;
4050}
4051
4052/**
4053 * Search register table for matching register.
4054 *
4055 * @returns Index in the register table or -1 if not found.
4056 *
4057 * @param pState The device state structure.
4058 * @param uOffset Register offset in memory-mapped region.
4059 * @thread EMT
4060 */
4061static int e1kRegLookup(E1KSTATE *pState, uint32_t uOffset)
4062{
4063 int index;
4064
4065 for (index = 0; index < E1K_NUM_OF_REGS; index++)
4066 {
4067 if (s_e1kRegMap[index].offset <= uOffset && uOffset < s_e1kRegMap[index].offset + s_e1kRegMap[index].size)
4068 {
4069 return index;
4070 }
4071 }
4072
4073 return -1;
4074}
4075
4076/**
4077 * Handle register read operation.
4078 *
4079 * Looks up and calls appropriate handler.
4080 *
4081 * @returns VBox status code.
4082 *
4083 * @param pState The device state structure.
4084 * @param uOffset Register offset in memory-mapped frame.
4085 * @param pv Where to store the result.
4086 * @param cb Number of bytes to read.
4087 * @thread EMT
4088 */
4089static int e1kRegRead(E1KSTATE *pState, uint32_t uOffset, void *pv, uint32_t cb)
4090{
4091 uint32_t u32 = 0;
4092 uint32_t mask = 0;
4093 uint32_t shift;
4094 int rc = VINF_SUCCESS;
4095 int index = e1kRegLookup(pState, uOffset);
4096 const char *szInst = INSTANCE(pState);
4097#ifdef DEBUG
4098 char buf[9];
4099#endif
4100
4101 /*
4102 * From the spec:
4103 * For registers that should be accessed as 32-bit double words, partial writes (less than a 32-bit
4104 * double word) is ignored. Partial reads return all 32 bits of data regardless of the byte enables.
4105 */
4106
4107 /*
4108 * To be able to write bytes and short word we convert them
4109 * to properly shifted 32-bit words and masks. The idea is
4110 * to keep register-specific handlers simple. Most accesses
4111 * will be 32-bit anyway.
4112 */
4113 switch (cb)
4114 {
4115 case 1: mask = 0x000000FF; break;
4116 case 2: mask = 0x0000FFFF; break;
4117 case 4: mask = 0xFFFFFFFF; break;
4118 default:
4119 return PDMDevHlpDBGFStop(pState->CTX_SUFF(pDevIns), RT_SRC_POS,
4120 "%s e1kRegRead: unsupported op size: offset=%#10x cb=%#10x\n",
4121 szInst, uOffset, cb);
4122 }
4123 if (index != -1)
4124 {
4125 if (s_e1kRegMap[index].readable)
4126 {
4127 /* Make the mask correspond to the bits we are about to read. */
4128 shift = (uOffset - s_e1kRegMap[index].offset) % sizeof(uint32_t) * 8;
4129 mask <<= shift;
4130 if (!mask)
4131 return PDMDevHlpDBGFStop(pState->CTX_SUFF(pDevIns), RT_SRC_POS,
4132 "%s e1kRegRead: Zero mask: offset=%#10x cb=%#10x\n",
4133 szInst, uOffset, cb);
4134 /*
4135 * Read it. Pass the mask so the handler knows what has to be read.
4136 * Mask out irrelevant bits.
4137 */
4138#ifdef E1K_GLOBAL_MUTEX
4139 rc = e1kMutexAcquire(pState, VINF_IOM_HC_MMIO_READ, RT_SRC_POS);
4140#else
4141 //rc = e1kCsEnter(pState, VERR_SEM_BUSY, RT_SRC_POS);
4142#endif
4143 if (RT_UNLIKELY(rc != VINF_SUCCESS))
4144 return rc;
4145 //pState->fDelayInts = false;
4146 //pState->iStatIntLost += pState->iStatIntLostOne;
4147 //pState->iStatIntLostOne = 0;
4148 rc = s_e1kRegMap[index].pfnRead(pState, uOffset & 0xFFFFFFFC, index, &u32) & mask;
4149 //e1kCsLeave(pState);
4150 e1kMutexRelease(pState);
4151 E1kLog2(("%s At %08X read %s from %s (%s)\n",
4152 szInst, uOffset, e1kU32toHex(u32, mask, buf), s_e1kRegMap[index].abbrev, s_e1kRegMap[index].name));
4153 /* Shift back the result. */
4154 u32 >>= shift;
4155 }
4156 else
4157 {
4158 E1kLog(("%s At %08X read (%s) attempt from write-only register %s (%s)\n",
4159 szInst, uOffset, e1kU32toHex(u32, mask, buf), s_e1kRegMap[index].abbrev, s_e1kRegMap[index].name));
4160 }
4161 }
4162 else
4163 {
4164 E1kLog(("%s At %08X read (%s) attempt from non-existing register\n",
4165 szInst, uOffset, e1kU32toHex(u32, mask, buf)));
4166 }
4167
4168 memcpy(pv, &u32, cb);
4169 return rc;
4170}
4171
4172/**
4173 * Handle register write operation.
4174 *
4175 * Looks up and calls appropriate handler.
4176 *
4177 * @returns VBox status code.
4178 *
4179 * @param pState The device state structure.
4180 * @param uOffset Register offset in memory-mapped frame.
4181 * @param pv Where to fetch the value.
4182 * @param cb Number of bytes to write.
4183 * @thread EMT
4184 */
4185static int e1kRegWrite(E1KSTATE *pState, uint32_t uOffset, void *pv, unsigned cb)
4186{
4187 int rc = VINF_SUCCESS;
4188 int index = e1kRegLookup(pState, uOffset);
4189 uint32_t u32;
4190
4191 /*
4192 * From the spec:
4193 * For registers that should be accessed as 32-bit double words, partial writes (less than a 32-bit
4194 * double word) is ignored. Partial reads return all 32 bits of data regardless of the byte enables.
4195 */
4196
4197 if (cb != 4)
4198 {
4199 E1kLog(("%s e1kRegWrite: Spec violation: unsupported op size: offset=%#10x cb=%#10x, ignored.\n",
4200 INSTANCE(pState), uOffset, cb));
4201 return VINF_SUCCESS;
4202 }
4203 if (uOffset & 3)
4204 {
4205 E1kLog(("%s e1kRegWrite: Spec violation: misaligned offset: %#10x cb=%#10x, ignored.\n",
4206 INSTANCE(pState), uOffset, cb));
4207 return VINF_SUCCESS;
4208 }
4209 u32 = *(uint32_t*)pv;
4210 if (index != -1)
4211 {
4212 if (s_e1kRegMap[index].writable)
4213 {
4214 /*
4215 * Write it. Pass the mask so the handler knows what has to be written.
4216 * Mask out irrelevant bits.
4217 */
4218 E1kLog2(("%s At %08X write %08X to %s (%s)\n",
4219 INSTANCE(pState), uOffset, u32, s_e1kRegMap[index].abbrev, s_e1kRegMap[index].name));
4220#ifdef E1K_GLOBAL_MUTEX
4221 rc = e1kMutexAcquire(pState, VINF_IOM_HC_MMIO_WRITE, RT_SRC_POS);
4222#else
4223 //rc = e1kCsEnter(pState, VERR_SEM_BUSY, RT_SRC_POS);
4224#endif
4225 if (RT_UNLIKELY(rc != VINF_SUCCESS))
4226 return rc;
4227 //pState->fDelayInts = false;
4228 //pState->iStatIntLost += pState->iStatIntLostOne;
4229 //pState->iStatIntLostOne = 0;
4230 rc = s_e1kRegMap[index].pfnWrite(pState, uOffset, index, u32);
4231 //e1kCsLeave(pState);
4232 e1kMutexRelease(pState);
4233 }
4234 else
4235 {
4236 E1kLog(("%s At %08X write attempt (%08X) to read-only register %s (%s)\n",
4237 INSTANCE(pState), uOffset, u32, s_e1kRegMap[index].abbrev, s_e1kRegMap[index].name));
4238 }
4239 }
4240 else
4241 {
4242 E1kLog(("%s At %08X write attempt (%08X) to non-existing register\n",
4243 INSTANCE(pState), uOffset, u32));
4244 }
4245 return rc;
4246}
4247
4248/**
4249 * I/O handler for memory-mapped read operations.
4250 *
4251 * @returns VBox status code.
4252 *
4253 * @param pDevIns The device instance.
4254 * @param pvUser User argument.
4255 * @param GCPhysAddr Physical address (in GC) where the read starts.
4256 * @param pv Where to store the result.
4257 * @param cb Number of bytes read.
4258 * @thread EMT
4259 */
4260PDMBOTHCBDECL(int) e1kMMIORead(PPDMDEVINS pDevIns, void *pvUser,
4261 RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
4262{
4263 NOREF(pvUser);
4264 E1KSTATE *pState = PDMINS_2_DATA(pDevIns, E1KSTATE *);
4265 uint32_t uOffset = GCPhysAddr - pState->addrMMReg;
4266 STAM_PROFILE_ADV_START(&pState->CTXSUFF(StatMMIORead), a);
4267
4268 Assert(uOffset < E1K_MM_SIZE);
4269
4270 int rc = e1kRegRead(pState, uOffset, pv, cb);
4271 STAM_PROFILE_ADV_STOP(&pState->CTXSUFF(StatMMIORead), a);
4272 return rc;
4273}
4274
4275/**
4276 * Memory mapped I/O Handler for write operations.
4277 *
4278 * @returns VBox status code.
4279 *
4280 * @param pDevIns The device instance.
4281 * @param pvUser User argument.
4282 * @param GCPhysAddr Physical address (in GC) where the read starts.
4283 * @param pv Where to fetch the value.
4284 * @param cb Number of bytes to write.
4285 * @thread EMT
4286 */
4287PDMBOTHCBDECL(int) e1kMMIOWrite(PPDMDEVINS pDevIns, void *pvUser,
4288 RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
4289{
4290 NOREF(pvUser);
4291 E1KSTATE *pState = PDMINS_2_DATA(pDevIns, E1KSTATE *);
4292 uint32_t uOffset = GCPhysAddr - pState->addrMMReg;
4293 int rc;
4294 STAM_PROFILE_ADV_START(&pState->CTXSUFF(StatMMIOWrite), a);
4295
4296 Assert(uOffset < E1K_MM_SIZE);
4297 if (cb != 4)
4298 {
4299 E1kLog(("%s e1kMMIOWrite: invalid op size: offset=%#10x cb=%#10x", pDevIns, uOffset, cb));
4300 rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "e1kMMIOWrite: invalid op size: offset=%#10x cb=%#10x\n", uOffset, cb);
4301 }
4302 else
4303 rc = e1kRegWrite(pState, uOffset, pv, cb);
4304
4305 STAM_PROFILE_ADV_STOP(&pState->CTXSUFF(StatMMIOWrite), a);
4306 return rc;
4307}
4308
4309/**
4310 * Port I/O Handler for IN operations.
4311 *
4312 * @returns VBox status code.
4313 *
4314 * @param pDevIns The device instance.
4315 * @param pvUser Pointer to the device state structure.
4316 * @param port Port number used for the IN operation.
4317 * @param pu32 Where to store the result.
4318 * @param cb Number of bytes read.
4319 * @thread EMT
4320 */
4321PDMBOTHCBDECL(int) e1kIOPortIn(PPDMDEVINS pDevIns, void *pvUser,
4322 RTIOPORT port, uint32_t *pu32, unsigned cb)
4323{
4324 E1KSTATE *pState = PDMINS_2_DATA(pDevIns, E1KSTATE *);
4325 int rc = VINF_SUCCESS;
4326 const char *szInst = INSTANCE(pState);
4327 STAM_PROFILE_ADV_START(&pState->CTXSUFF(StatIORead), a);
4328
4329 port -= pState->addrIOPort;
4330 if (cb != 4)
4331 {
4332 E1kLog(("%s e1kIOPortIn: invalid op size: port=%RTiop cb=%08x", szInst, port, cb));
4333 rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "%s e1kIOPortIn: invalid op size: port=%RTiop cb=%08x\n", szInst, port, cb);
4334 }
4335 else
4336 switch (port)
4337 {
4338 case 0x00: /* IOADDR */
4339 *pu32 = pState->uSelectedReg;
4340 E1kLog2(("%s e1kIOPortIn: IOADDR(0), selecting register %#010x, val=%#010x\n", szInst, pState->uSelectedReg, *pu32));
4341 break;
4342 case 0x04: /* IODATA */
4343 rc = e1kRegRead(pState, pState->uSelectedReg, pu32, cb);
4344 /* @todo wrong return code triggers assertions in the debug build; fix please */
4345 if (rc == VINF_IOM_HC_MMIO_READ)
4346 rc = VINF_IOM_HC_IOPORT_READ;
4347
4348 E1kLog2(("%s e1kIOPortIn: IODATA(4), reading from selected register %#010x, val=%#010x\n", szInst, pState->uSelectedReg, *pu32));
4349 break;
4350 default:
4351 E1kLog(("%s e1kIOPortIn: invalid port %#010x\n", szInst, port));
4352 //*pRC = VERR_IOM_IOPORT_UNUSED;
4353 }
4354
4355 STAM_PROFILE_ADV_STOP(&pState->CTXSUFF(StatIORead), a);
4356 return rc;
4357}
4358
4359
4360/**
4361 * Port I/O Handler for OUT operations.
4362 *
4363 * @returns VBox status code.
4364 *
4365 * @param pDevIns The device instance.
4366 * @param pvUser User argument.
4367 * @param Port Port number used for the IN operation.
4368 * @param u32 The value to output.
4369 * @param cb The value size in bytes.
4370 * @thread EMT
4371 */
4372PDMBOTHCBDECL(int) e1kIOPortOut(PPDMDEVINS pDevIns, void *pvUser,
4373 RTIOPORT port, uint32_t u32, unsigned cb)
4374{
4375 E1KSTATE *pState = PDMINS_2_DATA(pDevIns, E1KSTATE *);
4376 int rc = VINF_SUCCESS;
4377 const char *szInst = INSTANCE(pState);
4378 STAM_PROFILE_ADV_START(&pState->CTXSUFF(StatIOWrite), a);
4379
4380 E1kLog2(("%s e1kIOPortOut: port=%RTiop value=%08x\n", szInst, port, u32));
4381 if (cb != 4)
4382 {
4383 E1kLog(("%s e1kIOPortOut: invalid op size: port=%RTiop cb=%08x\n", szInst, port, cb));
4384 rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "%s e1kIOPortOut: invalid op size: port=%RTiop cb=%08x\n", szInst, port, cb);
4385 }
4386 else
4387 {
4388 port -= pState->addrIOPort;
4389 switch (port)
4390 {
4391 case 0x00: /* IOADDR */
4392 pState->uSelectedReg = u32;
4393 E1kLog2(("%s e1kIOPortOut: IOADDR(0), selected register %08x\n", szInst, pState->uSelectedReg));
4394 break;
4395 case 0x04: /* IODATA */
4396 E1kLog2(("%s e1kIOPortOut: IODATA(4), writing to selected register %#010x, value=%#010x\n", szInst, pState->uSelectedReg, u32));
4397 rc = e1kRegWrite(pState, pState->uSelectedReg, &u32, cb);
4398 /* @todo wrong return code triggers assertions in the debug build; fix please */
4399 if (rc == VINF_IOM_HC_MMIO_WRITE)
4400 rc = VINF_IOM_HC_IOPORT_WRITE;
4401 break;
4402 default:
4403 E1kLog(("%s e1kIOPortOut: invalid port %#010x\n", szInst, port));
4404 /** @todo Do we need to return an error here?
4405 * bird: VINF_SUCCESS is fine for unhandled cases of an OUT handler. (If you're curious
4406 * about the guest code and a bit adventuresome, try rc = PDMDeviceDBGFStop(...);) */
4407 rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "e1kIOPortOut: invalid port %#010x\n", port);
4408 }
4409 }
4410
4411 STAM_PROFILE_ADV_STOP(&pState->CTXSUFF(StatIOWrite), a);
4412 return rc;
4413}
4414
4415#ifdef IN_RING3
4416/**
4417 * Dump complete device state to log.
4418 *
4419 * @param pState Pointer to device state.
4420 */
4421static void e1kDumpState(E1KSTATE *pState)
4422{
4423 for (int i = 0; i<E1K_NUM_OF_32BIT_REGS; ++i)
4424 {
4425 E1kLog2(("%s %8.8s = %08x\n", INSTANCE(pState),
4426 s_e1kRegMap[i].abbrev, pState->auRegs[i]));
4427 }
4428#ifdef E1K_INT_STATS
4429 LogRel(("%s Interrupt attempts: %d\n", INSTANCE(pState), pState->uStatIntTry));
4430 LogRel(("%s Interrupts raised : %d\n", INSTANCE(pState), pState->uStatInt));
4431 LogRel(("%s Interrupts lowered: %d\n", INSTANCE(pState), pState->uStatIntLower));
4432 LogRel(("%s Interrupts delayed: %d\n", INSTANCE(pState), pState->uStatIntDly));
4433 LogRel(("%s Disabled delayed: %d\n", INSTANCE(pState), pState->uStatDisDly));
4434 LogRel(("%s Interrupts skipped: %d\n", INSTANCE(pState), pState->uStatIntSkip));
4435 LogRel(("%s Masked interrupts : %d\n", INSTANCE(pState), pState->uStatIntMasked));
4436 LogRel(("%s Early interrupts : %d\n", INSTANCE(pState), pState->uStatIntEarly));
4437 LogRel(("%s Late interrupts : %d\n", INSTANCE(pState), pState->uStatIntLate));
4438 LogRel(("%s Lost interrupts : %d\n", INSTANCE(pState), pState->iStatIntLost));
4439 LogRel(("%s Interrupts by RX : %d\n", INSTANCE(pState), pState->uStatIntRx));
4440 LogRel(("%s Interrupts by TX : %d\n", INSTANCE(pState), pState->uStatIntTx));
4441 LogRel(("%s Interrupts by ICS : %d\n", INSTANCE(pState), pState->uStatIntICS));
4442 LogRel(("%s Interrupts by RDTR: %d\n", INSTANCE(pState), pState->uStatIntRDTR));
4443 LogRel(("%s Interrupts by RDMT: %d\n", INSTANCE(pState), pState->uStatIntRXDMT0));
4444 LogRel(("%s Interrupts by TXQE: %d\n", INSTANCE(pState), pState->uStatIntTXQE));
4445 LogRel(("%s TX int delay asked: %d\n", INSTANCE(pState), pState->uStatTxIDE));
4446 LogRel(("%s TX no report asked: %d\n", INSTANCE(pState), pState->uStatTxNoRS));
4447 LogRel(("%s TX abs timer expd : %d\n", INSTANCE(pState), pState->uStatTAD));
4448 LogRel(("%s TX int timer expd : %d\n", INSTANCE(pState), pState->uStatTID));
4449 LogRel(("%s RX abs timer expd : %d\n", INSTANCE(pState), pState->uStatRAD));
4450 LogRel(("%s RX int timer expd : %d\n", INSTANCE(pState), pState->uStatRID));
4451 LogRel(("%s TX CTX descriptors: %d\n", INSTANCE(pState), pState->uStatDescCtx));
4452 LogRel(("%s TX DAT descriptors: %d\n", INSTANCE(pState), pState->uStatDescDat));
4453 LogRel(("%s TX LEG descriptors: %d\n", INSTANCE(pState), pState->uStatDescLeg));
4454 LogRel(("%s Received frames : %d\n", INSTANCE(pState), pState->uStatRxFrm));
4455 LogRel(("%s Transmitted frames: %d\n", INSTANCE(pState), pState->uStatTxFrm));
4456#endif /* E1K_INT_STATS */
4457}
4458
4459/**
4460 * Map PCI I/O region.
4461 *
4462 * @return VBox status code.
4463 * @param pPciDev Pointer to PCI device. Use pPciDev->pDevIns to get the device instance.
4464 * @param iRegion The region number.
4465 * @param GCPhysAddress Physical address of the region. If iType is PCI_ADDRESS_SPACE_IO, this is an
4466 * I/O port, else it's a physical address.
4467 * This address is *NOT* relative to pci_mem_base like earlier!
4468 * @param cb Region size.
4469 * @param enmType One of the PCI_ADDRESS_SPACE_* values.
4470 * @thread EMT
4471 */
4472static DECLCALLBACK(int) e1kMap(PPCIDEVICE pPciDev, int iRegion,
4473 RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
4474{
4475 int rc;
4476 E1KSTATE *pState = PDMINS_2_DATA(pPciDev->pDevIns, E1KSTATE*);
4477
4478 switch (enmType)
4479 {
4480 case PCI_ADDRESS_SPACE_IO:
4481 pState->addrIOPort = (RTIOPORT)GCPhysAddress;
4482 rc = PDMDevHlpIOPortRegister(pPciDev->pDevIns, pState->addrIOPort, cb, 0,
4483 e1kIOPortOut, e1kIOPortIn, NULL, NULL, "E1000");
4484 if (RT_FAILURE(rc))
4485 break;
4486 if (pState->fR0Enabled)
4487 {
4488 rc = PDMDevHlpIOPortRegisterR0(pPciDev->pDevIns, pState->addrIOPort, cb, 0,
4489 "e1kIOPortOut", "e1kIOPortIn", NULL, NULL, "E1000");
4490 if (RT_FAILURE(rc))
4491 break;
4492 }
4493 if (pState->fGCEnabled)
4494 {
4495 rc = PDMDevHlpIOPortRegisterRC(pPciDev->pDevIns, pState->addrIOPort, cb, 0,
4496 "e1kIOPortOut", "e1kIOPortIn", NULL, NULL, "E1000");
4497 }
4498 break;
4499 case PCI_ADDRESS_SPACE_MEM:
4500 pState->addrMMReg = GCPhysAddress;
4501 rc = PDMDevHlpMMIORegister(pPciDev->pDevIns, GCPhysAddress, cb, 0,
4502 e1kMMIOWrite, e1kMMIORead, NULL, "E1000");
4503 if (pState->fR0Enabled)
4504 {
4505 rc = PDMDevHlpMMIORegisterR0(pPciDev->pDevIns, GCPhysAddress, cb, 0,
4506 "e1kMMIOWrite", "e1kMMIORead", NULL);
4507 if (RT_FAILURE(rc))
4508 break;
4509 }
4510 if (pState->fGCEnabled)
4511 {
4512 rc = PDMDevHlpMMIORegisterRC(pPciDev->pDevIns, GCPhysAddress, cb, 0,
4513 "e1kMMIOWrite", "e1kMMIORead", NULL);
4514 }
4515 break;
4516 default:
4517 /* We should never get here */
4518 AssertMsgFailed(("Invalid PCI address space param in map callback"));
4519 rc = VERR_INTERNAL_ERROR;
4520 break;
4521 }
4522 return rc;
4523}
4524
4525/**
4526 * Check if the device can receive data now.
4527 * This must be called before the pfnRecieve() method is called.
4528 *
4529 * @returns Number of bytes the device can receive.
4530 * @param pInterface Pointer to the interface structure containing the called function pointer.
4531 * @thread EMT
4532 */
4533static int e1kCanReceive(E1KSTATE *pState)
4534{
4535 size_t cb;
4536
4537 if (RT_UNLIKELY(e1kMutexAcquire(pState, VERR_SEM_BUSY, RT_SRC_POS) != VINF_SUCCESS))
4538 return VERR_NET_NO_BUFFER_SPACE;
4539 if (RT_UNLIKELY(e1kCsRxEnter(pState, VERR_SEM_BUSY) != VINF_SUCCESS))
4540 return VERR_NET_NO_BUFFER_SPACE;
4541
4542 if (RDH < RDT)
4543 cb = (RDT - RDH) * pState->u16RxBSize;
4544 else if (RDH > RDT)
4545 cb = (RDLEN/sizeof(E1KRXDESC) - RDH + RDT) * pState->u16RxBSize;
4546 else
4547 {
4548 cb = 0;
4549 E1kLogRel(("E1000: OUT of RX descriptors!\n"));
4550 }
4551
4552 e1kCsRxLeave(pState);
4553 e1kMutexRelease(pState);
4554 return cb > 0 ? VINF_SUCCESS : VERR_NET_NO_BUFFER_SPACE;
4555}
4556
4557static DECLCALLBACK(int) e1kWaitReceiveAvail(PPDMINETWORKDOWN pInterface, RTMSINTERVAL cMillies)
4558{
4559 E1KSTATE *pState = IFACE_TO_STATE(pInterface, INetworkDown);
4560 int rc = e1kCanReceive(pState);
4561
4562 if (RT_SUCCESS(rc))
4563 return VINF_SUCCESS;
4564 if (RT_UNLIKELY(cMillies == 0))
4565 return VERR_NET_NO_BUFFER_SPACE;
4566
4567 rc = VERR_INTERRUPTED;
4568 ASMAtomicXchgBool(&pState->fMaybeOutOfSpace, true);
4569 STAM_PROFILE_START(&pState->StatRxOverflow, a);
4570 VMSTATE enmVMState;
4571 while (RT_LIKELY( (enmVMState = PDMDevHlpVMState(pState->CTX_SUFF(pDevIns))) == VMSTATE_RUNNING
4572 || enmVMState == VMSTATE_RUNNING_LS))
4573 {
4574 int rc2 = e1kCanReceive(pState);
4575 if (RT_SUCCESS(rc2))
4576 {
4577 rc = VINF_SUCCESS;
4578 break;
4579 }
4580 E1kLogRel(("E1000 e1kWaitReceiveAvail: waiting cMillies=%u...\n",
4581 cMillies));
4582 E1kLog(("%s e1kWaitReceiveAvail: waiting cMillies=%u...\n",
4583 INSTANCE(pState), cMillies));
4584 RTSemEventWait(pState->hEventMoreRxDescAvail, cMillies);
4585 }
4586 STAM_PROFILE_STOP(&pState->StatRxOverflow, a);
4587 ASMAtomicXchgBool(&pState->fMaybeOutOfSpace, false);
4588
4589 return rc;
4590}
4591
4592
4593/**
4594 * Matches the packet addresses against Receive Address table. Looks for
4595 * exact matches only.
4596 *
4597 * @returns true if address matches.
4598 * @param pState Pointer to the state structure.
4599 * @param pvBuf The ethernet packet.
4600 * @param cb Number of bytes available in the packet.
4601 * @thread EMT
4602 */
4603static bool e1kPerfectMatch(E1KSTATE *pState, const void *pvBuf)
4604{
4605 for (unsigned i = 0; i < RT_ELEMENTS(pState->aRecAddr.array); i++)
4606 {
4607 E1KRAELEM* ra = pState->aRecAddr.array + i;
4608
4609 /* Valid address? */
4610 if (ra->ctl & RA_CTL_AV)
4611 {
4612 Assert((ra->ctl & RA_CTL_AS) < 2);
4613 //unsigned char *pAddr = (unsigned char*)pvBuf + sizeof(ra->addr)*(ra->ctl & RA_CTL_AS);
4614 //E1kLog3(("%s Matching %02x:%02x:%02x:%02x:%02x:%02x against %02x:%02x:%02x:%02x:%02x:%02x...\n",
4615 // INSTANCE(pState), pAddr[0], pAddr[1], pAddr[2], pAddr[3], pAddr[4], pAddr[5],
4616 // ra->addr[0], ra->addr[1], ra->addr[2], ra->addr[3], ra->addr[4], ra->addr[5]));
4617 /*
4618 * Address Select:
4619 * 00b = Destination address
4620 * 01b = Source address
4621 * 10b = Reserved
4622 * 11b = Reserved
4623 * Since ethernet header is (DA, SA, len) we can use address
4624 * select as index.
4625 */
4626 if (memcmp((char*)pvBuf + sizeof(ra->addr)*(ra->ctl & RA_CTL_AS),
4627 ra->addr, sizeof(ra->addr)) == 0)
4628 return true;
4629 }
4630 }
4631
4632 return false;
4633}
4634
4635/**
4636 * Matches the packet addresses against Multicast Table Array.
4637 *
4638 * @remarks This is imperfect match since it matches not exact address but
4639 * a subset of addresses.
4640 *
4641 * @returns true if address matches.
4642 * @param pState Pointer to the state structure.
4643 * @param pvBuf The ethernet packet.
4644 * @param cb Number of bytes available in the packet.
4645 * @thread EMT
4646 */
4647static bool e1kImperfectMatch(E1KSTATE *pState, const void *pvBuf)
4648{
4649 /* Get bits 32..47 of destination address */
4650 uint16_t u16Bit = ((uint16_t*)pvBuf)[2];
4651
4652 unsigned offset = GET_BITS(RCTL, MO);
4653 /*
4654 * offset means:
4655 * 00b = bits 36..47
4656 * 01b = bits 35..46
4657 * 10b = bits 34..45
4658 * 11b = bits 32..43
4659 */
4660 if (offset < 3)
4661 u16Bit = u16Bit >> (4 - offset);
4662 return ASMBitTest(pState->auMTA, u16Bit & 0xFFF);
4663}
4664
4665/**
4666 * Determines if the packet is to be delivered to upper layer. The following
4667 * filters supported:
4668 * - Exact Unicast/Multicast
4669 * - Promiscuous Unicast/Multicast
4670 * - Multicast
4671 * - VLAN
4672 *
4673 * @returns true if packet is intended for this node.
4674 * @param pState Pointer to the state structure.
4675 * @param pvBuf The ethernet packet.
4676 * @param cb Number of bytes available in the packet.
4677 * @param pStatus Bit field to store status bits.
4678 * @thread EMT
4679 */
4680static bool e1kAddressFilter(E1KSTATE *pState, const void *pvBuf, size_t cb, E1KRXDST *pStatus)
4681{
4682 Assert(cb > 14);
4683 /* Assume that we fail to pass exact filter. */
4684 pStatus->fPIF = false;
4685 pStatus->fVP = false;
4686 /* Discard oversized packets */
4687 if (cb > E1K_MAX_RX_PKT_SIZE)
4688 {
4689 E1kLog(("%s ERROR: Incoming packet is too big, cb=%d > max=%d\n",
4690 INSTANCE(pState), cb, E1K_MAX_RX_PKT_SIZE));
4691 E1K_INC_CNT32(ROC);
4692 return false;
4693 }
4694 else if (!(RCTL & RCTL_LPE) && cb > 1522)
4695 {
4696 /* When long packet reception is disabled packets over 1522 are discarded */
4697 E1kLog(("%s Discarding incoming packet (LPE=0), cb=%d\n",
4698 INSTANCE(pState), cb));
4699 E1K_INC_CNT32(ROC);
4700 return false;
4701 }
4702
4703 /* Broadcast filtering */
4704 if (e1kIsBroadcast(pvBuf) && (RCTL & RCTL_BAM))
4705 return true;
4706 E1kLog2(("%s Packet filter: not a broadcast\n", INSTANCE(pState)));
4707 if (e1kIsMulticast(pvBuf))
4708 {
4709 /* Is multicast promiscuous enabled? */
4710 if (RCTL & RCTL_MPE)
4711 return true;
4712 E1kLog2(("%s Packet filter: no promiscuous multicast\n", INSTANCE(pState)));
4713 /* Try perfect matches first */
4714 if (e1kPerfectMatch(pState, pvBuf))
4715 {
4716 pStatus->fPIF = true;
4717 return true;
4718 }
4719 E1kLog2(("%s Packet filter: no perfect match\n", INSTANCE(pState)));
4720 if (e1kImperfectMatch(pState, pvBuf))
4721 return true;
4722 E1kLog2(("%s Packet filter: no imperfect match\n", INSTANCE(pState)));
4723 }
4724 else {
4725 /* Is unicast promiscuous enabled? */
4726 if (RCTL & RCTL_UPE)
4727 return true;
4728 E1kLog2(("%s Packet filter: no promiscuous unicast\n", INSTANCE(pState)));
4729 if (e1kPerfectMatch(pState, pvBuf))
4730 {
4731 pStatus->fPIF = true;
4732 return true;
4733 }
4734 E1kLog2(("%s Packet filter: no perfect match\n", INSTANCE(pState)));
4735 }
4736 /* Is VLAN filtering enabled? */
4737 if (RCTL & RCTL_VFE)
4738 {
4739 uint16_t *u16Ptr = (uint16_t*)pvBuf;
4740 /* Compare TPID with VLAN Ether Type */
4741 if (u16Ptr[6] == VET)
4742 {
4743 pStatus->fVP = true;
4744 /* It is 802.1q packet indeed, let's filter by VID */
4745 if (ASMBitTest(pState->auVFTA, RT_BE2H_U16(u16Ptr[7]) & 0xFFF))
4746 return true;
4747 E1kLog2(("%s Packet filter: no VLAN match\n", INSTANCE(pState)));
4748 }
4749 }
4750 E1kLog2(("%s Packet filter: packet discarded\n", INSTANCE(pState)));
4751 return false;
4752}
4753
4754/**
4755 * Receive data from the network.
4756 *
4757 * @returns VBox status code.
4758 * @param pInterface Pointer to the interface structure containing the called function pointer.
4759 * @param pvBuf The available data.
4760 * @param cb Number of bytes available in the buffer.
4761 * @thread ???
4762 */
4763static DECLCALLBACK(int) e1kReceive(PPDMINETWORKDOWN pInterface, const void *pvBuf, size_t cb)
4764{
4765 E1KSTATE *pState = IFACE_TO_STATE(pInterface, INetworkDown);
4766 int rc = VINF_SUCCESS;
4767
4768 /*
4769 * Drop packets if the VM is not running yet/anymore.
4770 */
4771 VMSTATE enmVMState = PDMDevHlpVMState(STATE_TO_DEVINS(pState));
4772 if ( enmVMState != VMSTATE_RUNNING
4773 && enmVMState != VMSTATE_RUNNING_LS)
4774 {
4775 E1kLog(("%s Dropping incoming packet as VM is not running.\n", INSTANCE(pState)));
4776 return VINF_SUCCESS;
4777 }
4778
4779 /* Discard incoming packets in locked state */
4780 if (!(RCTL & RCTL_EN) || pState->fLocked || !(STATUS & STATUS_LU))
4781 {
4782 E1kLog(("%s Dropping incoming packet as receive operation is disabled.\n", INSTANCE(pState)));
4783 return VINF_SUCCESS;
4784 }
4785
4786 STAM_PROFILE_ADV_START(&pState->StatReceive, a);
4787 rc = e1kMutexAcquire(pState, VERR_SEM_BUSY, RT_SRC_POS);
4788 if (RT_LIKELY(rc == VINF_SUCCESS))
4789 {
4790 //if (!e1kCsEnter(pState, RT_SRC_POS))
4791 // return VERR_PERMISSION_DENIED;
4792
4793 e1kPacketDump(pState, (const uint8_t*)pvBuf, cb, "<-- Incoming");
4794
4795 /* Update stats */
4796 if (RT_LIKELY(e1kCsEnter(pState, VERR_SEM_BUSY) == VINF_SUCCESS))
4797 {
4798 E1K_INC_CNT32(TPR);
4799 E1K_ADD_CNT64(TORL, TORH, cb < 64? 64 : cb);
4800 e1kCsLeave(pState);
4801 }
4802 STAM_PROFILE_ADV_START(&pState->StatReceiveFilter, a);
4803 E1KRXDST status;
4804 memset(&status, 0, sizeof(status));
4805 bool fPassed = e1kAddressFilter(pState, pvBuf, cb, &status);
4806 STAM_PROFILE_ADV_STOP(&pState->StatReceiveFilter, a);
4807 if (fPassed)
4808 {
4809 rc = e1kHandleRxPacket(pState, pvBuf, cb, status);
4810 }
4811 //e1kCsLeave(pState);
4812 e1kMutexRelease(pState);
4813 }
4814 STAM_PROFILE_ADV_STOP(&pState->StatReceive, a);
4815
4816 return rc;
4817}
4818
4819/**
4820 * Gets the pointer to the status LED of a unit.
4821 *
4822 * @returns VBox status code.
4823 * @param pInterface Pointer to the interface structure.
4824 * @param iLUN The unit which status LED we desire.
4825 * @param ppLed Where to store the LED pointer.
4826 * @thread EMT
4827 */
4828static DECLCALLBACK(int) e1kQueryStatusLed(PPDMILEDPORTS pInterface, unsigned iLUN, PPDMLED *ppLed)
4829{
4830 E1KSTATE *pState = IFACE_TO_STATE(pInterface, ILeds);
4831 int rc = VERR_PDM_LUN_NOT_FOUND;
4832
4833 if (iLUN == 0)
4834 {
4835 *ppLed = &pState->led;
4836 rc = VINF_SUCCESS;
4837 }
4838 return rc;
4839}
4840
4841/**
4842 * Gets the current Media Access Control (MAC) address.
4843 *
4844 * @returns VBox status code.
4845 * @param pInterface Pointer to the interface structure containing the called function pointer.
4846 * @param pMac Where to store the MAC address.
4847 * @thread EMT
4848 */
4849static DECLCALLBACK(int) e1kGetMac(PPDMINETWORKCONFIG pInterface, PRTMAC pMac)
4850{
4851 E1KSTATE *pState = IFACE_TO_STATE(pInterface, INetworkConfig);
4852 pState->eeprom.getMac(pMac);
4853 return VINF_SUCCESS;
4854}
4855
4856
4857/**
4858 * Gets the new link state.
4859 *
4860 * @returns The current link state.
4861 * @param pInterface Pointer to the interface structure containing the called function pointer.
4862 * @thread EMT
4863 */
4864static DECLCALLBACK(PDMNETWORKLINKSTATE) e1kGetLinkState(PPDMINETWORKCONFIG pInterface)
4865{
4866 E1KSTATE *pState = IFACE_TO_STATE(pInterface, INetworkConfig);
4867 if (STATUS & STATUS_LU)
4868 return PDMNETWORKLINKSTATE_UP;
4869 return PDMNETWORKLINKSTATE_DOWN;
4870}
4871
4872
4873/**
4874 * Sets the new link state.
4875 *
4876 * @returns VBox status code.
4877 * @param pInterface Pointer to the interface structure containing the called function pointer.
4878 * @param enmState The new link state
4879 * @thread EMT
4880 */
4881static DECLCALLBACK(int) e1kSetLinkState(PPDMINETWORKCONFIG pInterface, PDMNETWORKLINKSTATE enmState)
4882{
4883 E1KSTATE *pState = IFACE_TO_STATE(pInterface, INetworkConfig);
4884 bool fOldUp = !!(STATUS & STATUS_LU);
4885 bool fNewUp = enmState == PDMNETWORKLINKSTATE_UP;
4886
4887 if (fNewUp != fOldUp)
4888 {
4889 if (fNewUp)
4890 {
4891 E1kLog(("%s Link will be up in approximately 5 secs\n", INSTANCE(pState)));
4892 pState->fCableConnected = true;
4893 STATUS &= ~STATUS_LU;
4894 Phy::setLinkStatus(&pState->phy, false);
4895 e1kRaiseInterrupt(pState, VERR_SEM_BUSY, ICR_LSC);
4896 /* Restore the link back in 5 second. */
4897 e1kArmTimer(pState, pState->pLUTimerR3, 5000000);
4898 }
4899 else
4900 {
4901 E1kLog(("%s Link is down\n", INSTANCE(pState)));
4902 pState->fCableConnected = false;
4903 STATUS &= ~STATUS_LU;
4904 Phy::setLinkStatus(&pState->phy, false);
4905 e1kRaiseInterrupt(pState, VERR_SEM_BUSY, ICR_LSC);
4906 }
4907 if (pState->pDrv)
4908 pState->pDrv->pfnNotifyLinkChanged(pState->pDrv, enmState);
4909 }
4910 return VINF_SUCCESS;
4911}
4912
4913/**
4914 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
4915 */
4916static DECLCALLBACK(void *) e1kQueryInterface(struct PDMIBASE *pInterface, const char *pszIID)
4917{
4918 E1KSTATE *pThis = IFACE_TO_STATE(pInterface, IBase);
4919 Assert(&pThis->IBase == pInterface);
4920
4921 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase);
4922 PDMIBASE_RETURN_INTERFACE(pszIID, PDMINETWORKDOWN, &pThis->INetworkDown);
4923 PDMIBASE_RETURN_INTERFACE(pszIID, PDMINETWORKCONFIG, &pThis->INetworkConfig);
4924 PDMIBASE_RETURN_INTERFACE(pszIID, PDMILEDPORTS, &pThis->ILeds);
4925 return NULL;
4926}
4927
4928/**
4929 * Saves the configuration.
4930 *
4931 * @param pState The E1K state.
4932 * @param pSSM The handle to the saved state.
4933 */
4934static void e1kSaveConfig(E1KSTATE *pState, PSSMHANDLE pSSM)
4935{
4936 SSMR3PutMem(pSSM, &pState->macConfigured, sizeof(pState->macConfigured));
4937 SSMR3PutU32(pSSM, pState->eChip);
4938}
4939
4940/**
4941 * Live save - save basic configuration.
4942 *
4943 * @returns VBox status code.
4944 * @param pDevIns The device instance.
4945 * @param pSSM The handle to the saved state.
4946 * @param uPass
4947 */
4948static DECLCALLBACK(int) e1kLiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
4949{
4950 E1KSTATE *pState = PDMINS_2_DATA(pDevIns, E1KSTATE*);
4951 e1kSaveConfig(pState, pSSM);
4952 return VINF_SSM_DONT_CALL_AGAIN;
4953}
4954
4955/**
4956 * Prepares for state saving.
4957 *
4958 * @returns VBox status code.
4959 * @param pDevIns The device instance.
4960 * @param pSSM The handle to the saved state.
4961 */
4962static DECLCALLBACK(int) e1kSavePrep(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
4963{
4964 E1KSTATE* pState = PDMINS_2_DATA(pDevIns, E1KSTATE*);
4965
4966 int rc = e1kCsEnter(pState, VERR_SEM_BUSY);
4967 if (RT_UNLIKELY(rc != VINF_SUCCESS))
4968 return rc;
4969 e1kCsLeave(pState);
4970 return VINF_SUCCESS;
4971#if 0
4972 int rc = e1kMutexAcquire(pState, VERR_SEM_BUSY, RT_SRC_POS);
4973 if (RT_UNLIKELY(rc != VINF_SUCCESS))
4974 return rc;
4975 /* 1) Prevent all threads from modifying the state and memory */
4976 //pState->fLocked = true;
4977 /* 2) Cancel all timers */
4978#ifdef E1K_USE_TX_TIMERS
4979 e1kCancelTimer(pState, pState->CTX_SUFF(pTIDTimer));
4980#ifndef E1K_NO_TAD
4981 e1kCancelTimer(pState, pState->CTX_SUFF(pTADTimer));
4982#endif /* E1K_NO_TAD */
4983#endif /* E1K_USE_TX_TIMERS */
4984#ifdef E1K_USE_RX_TIMERS
4985 e1kCancelTimer(pState, pState->CTX_SUFF(pRIDTimer));
4986 e1kCancelTimer(pState, pState->CTX_SUFF(pRADTimer));
4987#endif /* E1K_USE_RX_TIMERS */
4988 e1kCancelTimer(pState, pState->CTX_SUFF(pIntTimer));
4989 /* 3) Did I forget anything? */
4990 E1kLog(("%s Locked\n", INSTANCE(pState)));
4991 e1kMutexRelease(pState);
4992 return VINF_SUCCESS;
4993#endif
4994}
4995
4996
4997/**
4998 * Saves the state of device.
4999 *
5000 * @returns VBox status code.
5001 * @param pDevIns The device instance.
5002 * @param pSSM The handle to the saved state.
5003 */
5004static DECLCALLBACK(int) e1kSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
5005{
5006 E1KSTATE* pState = PDMINS_2_DATA(pDevIns, E1KSTATE*);
5007
5008 e1kSaveConfig(pState, pSSM);
5009 pState->eeprom.save(pSSM);
5010 e1kDumpState(pState);
5011 SSMR3PutMem(pSSM, pState->auRegs, sizeof(pState->auRegs));
5012 SSMR3PutBool(pSSM, pState->fIntRaised);
5013 Phy::saveState(pSSM, &pState->phy);
5014 SSMR3PutU32(pSSM, pState->uSelectedReg);
5015 SSMR3PutMem(pSSM, pState->auMTA, sizeof(pState->auMTA));
5016 SSMR3PutMem(pSSM, &pState->aRecAddr, sizeof(pState->aRecAddr));
5017 SSMR3PutMem(pSSM, pState->auVFTA, sizeof(pState->auVFTA));
5018 SSMR3PutU64(pSSM, pState->u64AckedAt);
5019 SSMR3PutU16(pSSM, pState->u16RxBSize);
5020 //SSMR3PutBool(pSSM, pState->fDelayInts);
5021 //SSMR3PutBool(pSSM, pState->fIntMaskUsed);
5022 SSMR3PutU16(pSSM, pState->u16TxPktLen);
5023/** @todo State wrt to the TSE buffer is incomplete, so little point in
5024 * saving this actually. */
5025 SSMR3PutMem(pSSM, pState->aTxPacketFallback, pState->u16TxPktLen);
5026 SSMR3PutBool(pSSM, pState->fIPcsum);
5027 SSMR3PutBool(pSSM, pState->fTCPcsum);
5028 SSMR3PutMem(pSSM, &pState->contextTSE, sizeof(pState->contextTSE));
5029 SSMR3PutMem(pSSM, &pState->contextNormal, sizeof(pState->contextNormal));
5030/**@todo GSO requres some more state here. */
5031 E1kLog(("%s State has been saved\n", INSTANCE(pState)));
5032 return VINF_SUCCESS;
5033}
5034
5035#if 0
5036/**
5037 * Cleanup after saving.
5038 *
5039 * @returns VBox status code.
5040 * @param pDevIns The device instance.
5041 * @param pSSM The handle to the saved state.
5042 */
5043static DECLCALLBACK(int) e1kSaveDone(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
5044{
5045 E1KSTATE* pState = PDMINS_2_DATA(pDevIns, E1KSTATE*);
5046
5047 int rc = e1kMutexAcquire(pState, VERR_SEM_BUSY, RT_SRC_POS);
5048 if (RT_UNLIKELY(rc != VINF_SUCCESS))
5049 return rc;
5050 /* If VM is being powered off unlocking will result in assertions in PGM */
5051 if (PDMDevHlpGetVM(pDevIns)->enmVMState == VMSTATE_RUNNING)
5052 pState->fLocked = false;
5053 else
5054 E1kLog(("%s VM is not running -- remain locked\n", INSTANCE(pState)));
5055 E1kLog(("%s Unlocked\n", INSTANCE(pState)));
5056 e1kMutexRelease(pState);
5057 return VINF_SUCCESS;
5058}
5059#endif
5060
5061/**
5062 * Sync with .
5063 *
5064 * @returns VBox status code.
5065 * @param pDevIns The device instance.
5066 * @param pSSM The handle to the saved state.
5067 */
5068static DECLCALLBACK(int) e1kLoadPrep(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
5069{
5070 E1KSTATE* pState = PDMINS_2_DATA(pDevIns, E1KSTATE*);
5071
5072 int rc = e1kCsEnter(pState, VERR_SEM_BUSY);
5073 if (RT_UNLIKELY(rc != VINF_SUCCESS))
5074 return rc;
5075 e1kCsLeave(pState);
5076 return VINF_SUCCESS;
5077}
5078
5079/**
5080 * Restore previously saved state of device.
5081 *
5082 * @returns VBox status code.
5083 * @param pDevIns The device instance.
5084 * @param pSSM The handle to the saved state.
5085 * @param uVersion The data unit version number.
5086 * @param uPass The data pass.
5087 */
5088static DECLCALLBACK(int) e1kLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
5089{
5090 E1KSTATE *pState = PDMINS_2_DATA(pDevIns, E1KSTATE*);
5091 int rc;
5092
5093 if ( uVersion != E1K_SAVEDSTATE_VERSION
5094 && uVersion != E1K_SAVEDSTATE_VERSION_VBOX_30)
5095 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
5096
5097 if ( uVersion > E1K_SAVEDSTATE_VERSION_VBOX_30
5098 || uPass != SSM_PASS_FINAL)
5099 {
5100 /* config checks */
5101 RTMAC macConfigured;
5102 rc = SSMR3GetMem(pSSM, &macConfigured, sizeof(macConfigured));
5103 AssertRCReturn(rc, rc);
5104 if ( memcmp(&macConfigured, &pState->macConfigured, sizeof(macConfigured))
5105 && (uPass == 0 || !PDMDevHlpVMTeleportedAndNotFullyResumedYet(pDevIns)) )
5106 LogRel(("%s: The mac address differs: config=%RTmac saved=%RTmac\n", INSTANCE(pState), &pState->macConfigured, &macConfigured));
5107
5108 E1KCHIP eChip;
5109 rc = SSMR3GetU32(pSSM, &eChip);
5110 AssertRCReturn(rc, rc);
5111 if (eChip != pState->eChip)
5112 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("The chip type differs: config=%u saved=%u"), pState->eChip, eChip);
5113 }
5114
5115 if (uPass == SSM_PASS_FINAL)
5116 {
5117 if (uVersion > E1K_SAVEDSTATE_VERSION_VBOX_30)
5118 {
5119 rc = pState->eeprom.load(pSSM);
5120 AssertRCReturn(rc, rc);
5121 }
5122 /* the state */
5123 SSMR3GetMem(pSSM, &pState->auRegs, sizeof(pState->auRegs));
5124 SSMR3GetBool(pSSM, &pState->fIntRaised);
5125 /** @todo: PHY could be made a separate device with its own versioning */
5126 Phy::loadState(pSSM, &pState->phy);
5127 SSMR3GetU32(pSSM, &pState->uSelectedReg);
5128 SSMR3GetMem(pSSM, &pState->auMTA, sizeof(pState->auMTA));
5129 SSMR3GetMem(pSSM, &pState->aRecAddr, sizeof(pState->aRecAddr));
5130 SSMR3GetMem(pSSM, &pState->auVFTA, sizeof(pState->auVFTA));
5131 SSMR3GetU64(pSSM, &pState->u64AckedAt);
5132 SSMR3GetU16(pSSM, &pState->u16RxBSize);
5133 //SSMR3GetBool(pSSM, pState->fDelayInts);
5134 //SSMR3GetBool(pSSM, pState->fIntMaskUsed);
5135 SSMR3GetU16(pSSM, &pState->u16TxPktLen);
5136 SSMR3GetMem(pSSM, &pState->aTxPacketFallback[0], pState->u16TxPktLen);
5137 SSMR3GetBool(pSSM, &pState->fIPcsum);
5138 SSMR3GetBool(pSSM, &pState->fTCPcsum);
5139 SSMR3GetMem(pSSM, &pState->contextTSE, sizeof(pState->contextTSE));
5140 rc = SSMR3GetMem(pSSM, &pState->contextNormal, sizeof(pState->contextNormal));
5141 AssertRCReturn(rc, rc);
5142
5143 /* derived state */
5144 e1kSetupGsoCtx(&pState->GsoCtx, &pState->contextTSE);
5145
5146 E1kLog(("%s State has been restored\n", INSTANCE(pState)));
5147 e1kDumpState(pState);
5148 }
5149 return VINF_SUCCESS;
5150}
5151
5152/**
5153 * Link status adjustments after loading.
5154 *
5155 * @returns VBox status code.
5156 * @param pDevIns The device instance.
5157 * @param pSSM The handle to the saved state.
5158 */
5159static DECLCALLBACK(int) e1kLoadDone(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
5160{
5161 E1KSTATE* pState = PDMINS_2_DATA(pDevIns, E1KSTATE*);
5162
5163 int rc = e1kMutexAcquire(pState, VERR_SEM_BUSY, RT_SRC_POS);
5164 if (RT_UNLIKELY(rc != VINF_SUCCESS))
5165 return rc;
5166 /*
5167 * Force the link down here, since PDMNETWORKLINKSTATE_DOWN_RESUME is never
5168 * passed to us. We go through all this stuff if the link was up and we
5169 * wasn't teleported.
5170 */
5171 if ( (STATUS & STATUS_LU)
5172 && !PDMDevHlpVMTeleportedAndNotFullyResumedYet(pDevIns))
5173 {
5174 E1kLog(("%s Link is down temporarily\n", INSTANCE(pState)));
5175 STATUS &= ~STATUS_LU;
5176 Phy::setLinkStatus(&pState->phy, false);
5177 e1kRaiseInterrupt(pState, VERR_SEM_BUSY, ICR_LSC);
5178 /* Restore the link back in five seconds. */
5179 e1kArmTimer(pState, pState->pLUTimerR3, 5000000);
5180 }
5181 e1kMutexRelease(pState);
5182 return VINF_SUCCESS;
5183}
5184
5185/* -=-=-=-=- PDMDEVREG -=-=-=-=- */
5186
5187#ifdef VBOX_DYNAMIC_NET_ATTACH
5188
5189/**
5190 * Detach notification.
5191 *
5192 * One port on the network card has been disconnected from the network.
5193 *
5194 * @param pDevIns The device instance.
5195 * @param iLUN The logical unit which is being detached.
5196 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
5197 */
5198static DECLCALLBACK(void) e1kDetach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
5199{
5200 E1KSTATE *pState = PDMINS_2_DATA(pDevIns, E1KSTATE*);
5201 Log(("%s e1kDetach:\n", INSTANCE(pState)));
5202
5203 AssertLogRelReturnVoid(iLUN == 0);
5204
5205 PDMCritSectEnter(&pState->cs, VERR_SEM_BUSY);
5206
5207 /** @todo: r=pritesh still need to check if i missed
5208 * to clean something in this function
5209 */
5210
5211 /*
5212 * Zero some important members.
5213 */
5214 pState->pDrvBase = NULL;
5215 pState->pDrv = NULL;
5216
5217 PDMCritSectLeave(&pState->cs);
5218}
5219
5220
5221/**
5222 * Attach the Network attachment.
5223 *
5224 * One port on the network card has been connected to a network.
5225 *
5226 * @returns VBox status code.
5227 * @param pDevIns The device instance.
5228 * @param iLUN The logical unit which is being attached.
5229 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
5230 *
5231 * @remarks This code path is not used during construction.
5232 */
5233static DECLCALLBACK(int) e1kAttach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
5234{
5235 E1KSTATE *pState = PDMINS_2_DATA(pDevIns, E1KSTATE*);
5236 LogFlow(("%s e1kAttach:\n", INSTANCE(pState)));
5237
5238 AssertLogRelReturn(iLUN == 0, VERR_PDM_NO_SUCH_LUN);
5239
5240 PDMCritSectEnter(&pState->cs, VERR_SEM_BUSY);
5241
5242 /*
5243 * Attach the driver.
5244 */
5245 int rc = PDMDevHlpDriverAttach(pDevIns, 0, &pState->IBase, &pState->pDrvBase, "Network Port");
5246 if (RT_SUCCESS(rc))
5247 {
5248 if (rc == VINF_NAT_DNS)
5249 {
5250#ifdef RT_OS_LINUX
5251 PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "NoDNSforNAT",
5252 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"));
5253#else
5254 PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "NoDNSforNAT",
5255 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"));
5256#endif
5257 }
5258 pState->pDrv = PDMIBASE_QUERY_INTERFACE(pState->pDrvBase, PDMINETWORKUP);
5259 AssertMsgStmt(pState->pDrv, ("Failed to obtain the PDMINETWORKUP interface!\n"),
5260 rc = VERR_PDM_MISSING_INTERFACE_BELOW);
5261 }
5262 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
5263 Log(("%s No attached driver!\n", INSTANCE(pState)));
5264
5265
5266 /*
5267 * Temporary set the link down if it was up so that the guest
5268 * will know that we have change the configuration of the
5269 * network card
5270 */
5271 if ((STATUS & STATUS_LU) && RT_SUCCESS(rc))
5272 {
5273 STATUS &= ~STATUS_LU;
5274 Phy::setLinkStatus(&pState->phy, false);
5275 e1kRaiseInterrupt(pState, VERR_SEM_BUSY, ICR_LSC);
5276 /* Restore the link back in 5 second. */
5277 e1kArmTimer(pState, pState->pLUTimerR3, 5000000);
5278 }
5279
5280 PDMCritSectLeave(&pState->cs);
5281 return rc;
5282
5283}
5284
5285#endif /* VBOX_DYNAMIC_NET_ATTACH */
5286
5287/**
5288 * @copydoc FNPDMDEVPOWEROFF
5289 */
5290static DECLCALLBACK(void) e1kPowerOff(PPDMDEVINS pDevIns)
5291{
5292 /* Poke thread waiting for buffer space. */
5293 e1kWakeupReceive(pDevIns);
5294}
5295
5296/**
5297 * @copydoc FNPDMDEVSUSPEND
5298 */
5299static DECLCALLBACK(void) e1kSuspend(PPDMDEVINS pDevIns)
5300{
5301 /* Poke thread waiting for buffer space. */
5302 e1kWakeupReceive(pDevIns);
5303}
5304
5305/**
5306 * Device relocation callback.
5307 *
5308 * When this callback is called the device instance data, and if the
5309 * device have a GC component, is being relocated, or/and the selectors
5310 * have been changed. The device must use the chance to perform the
5311 * necessary pointer relocations and data updates.
5312 *
5313 * Before the GC code is executed the first time, this function will be
5314 * called with a 0 delta so GC pointer calculations can be one in one place.
5315 *
5316 * @param pDevIns Pointer to the device instance.
5317 * @param offDelta The relocation delta relative to the old location.
5318 *
5319 * @remark A relocation CANNOT fail.
5320 */
5321static DECLCALLBACK(void) e1kRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
5322{
5323 E1KSTATE* pState = PDMINS_2_DATA(pDevIns, E1KSTATE*);
5324 pState->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
5325 pState->pTxQueueRC = PDMQueueRCPtr(pState->pTxQueueR3);
5326 pState->pCanRxQueueRC = PDMQueueRCPtr(pState->pCanRxQueueR3);
5327#ifdef E1K_USE_RX_TIMERS
5328 pState->pRIDTimerRC = TMTimerRCPtr(pState->pRIDTimerR3);
5329 pState->pRADTimerRC = TMTimerRCPtr(pState->pRADTimerR3);
5330#endif /* E1K_USE_RX_TIMERS */
5331#ifdef E1K_USE_TX_TIMERS
5332 pState->pTIDTimerRC = TMTimerRCPtr(pState->pTIDTimerR3);
5333# ifndef E1K_NO_TAD
5334 pState->pTADTimerRC = TMTimerRCPtr(pState->pTADTimerR3);
5335# endif /* E1K_NO_TAD */
5336#endif /* E1K_USE_TX_TIMERS */
5337 pState->pIntTimerRC = TMTimerRCPtr(pState->pIntTimerR3);
5338 pState->pLUTimerRC = TMTimerRCPtr(pState->pLUTimerR3);
5339}
5340
5341/**
5342 * Destruct a device instance.
5343 *
5344 * We need to free non-VM resources only.
5345 *
5346 * @returns VBox status.
5347 * @param pDevIns The device instance data.
5348 * @thread EMT
5349 */
5350static DECLCALLBACK(int) e1kDestruct(PPDMDEVINS pDevIns)
5351{
5352 E1KSTATE* pState = PDMINS_2_DATA(pDevIns, E1KSTATE*);
5353 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
5354
5355 e1kDumpState(pState);
5356 E1kLog(("%s Destroying instance\n", INSTANCE(pState)));
5357 if (PDMCritSectIsInitialized(&pState->cs))
5358 {
5359 if (pState->hEventMoreRxDescAvail != NIL_RTSEMEVENT)
5360 {
5361 RTSemEventSignal(pState->hEventMoreRxDescAvail);
5362 RTSemEventDestroy(pState->hEventMoreRxDescAvail);
5363 pState->hEventMoreRxDescAvail = NIL_RTSEMEVENT;
5364 }
5365 if (pState->hTxSem != NIL_RTSEMEVENT)
5366 {
5367 RTSemEventDestroy(pState->hTxSem);
5368 pState->hTxSem = NIL_RTSEMEVENT;
5369 }
5370#ifndef E1K_GLOBAL_MUTEX
5371 PDMR3CritSectDelete(&pState->csRx);
5372 //PDMR3CritSectDelete(&pState->csTx);
5373#endif
5374 PDMR3CritSectDelete(&pState->cs);
5375 }
5376 return VINF_SUCCESS;
5377}
5378
5379/**
5380 * Sets 8-bit register in PCI configuration space.
5381 * @param refPciDev The PCI device.
5382 * @param uOffset The register offset.
5383 * @param u16Value The value to store in the register.
5384 * @thread EMT
5385 */
5386DECLINLINE(void) e1kPCICfgSetU8(PCIDEVICE& refPciDev, uint32_t uOffset, uint8_t u8Value)
5387{
5388 Assert(uOffset < sizeof(refPciDev.config));
5389 refPciDev.config[uOffset] = u8Value;
5390}
5391
5392/**
5393 * Sets 16-bit register in PCI configuration space.
5394 * @param refPciDev The PCI device.
5395 * @param uOffset The register offset.
5396 * @param u16Value The value to store in the register.
5397 * @thread EMT
5398 */
5399DECLINLINE(void) e1kPCICfgSetU16(PCIDEVICE& refPciDev, uint32_t uOffset, uint16_t u16Value)
5400{
5401 Assert(uOffset+sizeof(u16Value) <= sizeof(refPciDev.config));
5402 *(uint16_t*)&refPciDev.config[uOffset] = u16Value;
5403}
5404
5405/**
5406 * Sets 32-bit register in PCI configuration space.
5407 * @param refPciDev The PCI device.
5408 * @param uOffset The register offset.
5409 * @param u32Value The value to store in the register.
5410 * @thread EMT
5411 */
5412DECLINLINE(void) e1kPCICfgSetU32(PCIDEVICE& refPciDev, uint32_t uOffset, uint32_t u32Value)
5413{
5414 Assert(uOffset+sizeof(u32Value) <= sizeof(refPciDev.config));
5415 *(uint32_t*)&refPciDev.config[uOffset] = u32Value;
5416}
5417
5418/**
5419 * Set PCI configuration space registers.
5420 *
5421 * @param pci Reference to PCI device structure.
5422 * @thread EMT
5423 */
5424static DECLCALLBACK(void) e1kConfigurePCI(PCIDEVICE& pci, E1KCHIP eChip)
5425{
5426 Assert(eChip < RT_ELEMENTS(g_Chips));
5427 /* Configure PCI Device, assume 32-bit mode ******************************/
5428 PCIDevSetVendorId(&pci, g_Chips[eChip].uPCIVendorId);
5429 PCIDevSetDeviceId(&pci, g_Chips[eChip].uPCIDeviceId);
5430 e1kPCICfgSetU16(pci, VBOX_PCI_SUBSYSTEM_VENDOR_ID, g_Chips[eChip].uPCISubsystemVendorId);
5431 e1kPCICfgSetU16(pci, VBOX_PCI_SUBSYSTEM_ID, g_Chips[eChip].uPCISubsystemId);
5432
5433 e1kPCICfgSetU16(pci, VBOX_PCI_COMMAND, 0x0000);
5434 /* DEVSEL Timing (medium device), 66 MHz Capable, New capabilities */
5435 e1kPCICfgSetU16(pci, VBOX_PCI_STATUS, 0x0230);
5436 /* Stepping A2 */
5437 e1kPCICfgSetU8( pci, VBOX_PCI_REVISION_ID, 0x02);
5438 /* Ethernet adapter */
5439 e1kPCICfgSetU8( pci, VBOX_PCI_CLASS_PROG, 0x00);
5440 e1kPCICfgSetU16(pci, VBOX_PCI_CLASS_DEVICE, 0x0200);
5441 /* normal single function Ethernet controller */
5442 e1kPCICfgSetU8( pci, VBOX_PCI_HEADER_TYPE, 0x00);
5443 /* Memory Register Base Address */
5444 e1kPCICfgSetU32(pci, VBOX_PCI_BASE_ADDRESS_0, 0x00000000);
5445 /* Memory Flash Base Address */
5446 e1kPCICfgSetU32(pci, VBOX_PCI_BASE_ADDRESS_1, 0x00000000);
5447 /* IO Register Base Address */
5448 e1kPCICfgSetU32(pci, VBOX_PCI_BASE_ADDRESS_2, 0x00000001);
5449 /* Expansion ROM Base Address */
5450 e1kPCICfgSetU32(pci, VBOX_PCI_ROM_ADDRESS, 0x00000000);
5451 /* Capabilities Pointer */
5452 e1kPCICfgSetU8( pci, VBOX_PCI_CAPABILITY_LIST, 0xDC);
5453 /* Interrupt Pin: INTA# */
5454 e1kPCICfgSetU8( pci, VBOX_PCI_INTERRUPT_PIN, 0x01);
5455 /* Max_Lat/Min_Gnt: very high priority and time slice */
5456 e1kPCICfgSetU8( pci, VBOX_PCI_MIN_GNT, 0xFF);
5457 e1kPCICfgSetU8( pci, VBOX_PCI_MAX_LAT, 0x00);
5458
5459 /* PCI Power Management Registers ****************************************/
5460 /* Capability ID: PCI Power Management Registers */
5461 e1kPCICfgSetU8( pci, 0xDC, 0x01);
5462 /* Next Item Pointer: PCI-X */
5463 e1kPCICfgSetU8( pci, 0xDC + 1, 0xE4);
5464 /* Power Management Capabilities: PM disabled, DSI */
5465 e1kPCICfgSetU16(pci, 0xDC + 2, 0x0022);
5466 /* Power Management Control / Status Register: PM disabled */
5467 e1kPCICfgSetU16(pci, 0xDC + 4, 0x0000);
5468 /* PMCSR_BSE Bridge Support Extensions: Not supported */
5469 e1kPCICfgSetU8( pci, 0xDC + 6, 0x00);
5470 /* Data Register: PM disabled, always 0 */
5471 e1kPCICfgSetU8( pci, 0xDC + 7, 0x00);
5472
5473 /* PCI-X Configuration Registers *****************************************/
5474 /* Capability ID: PCI-X Configuration Registers */
5475 e1kPCICfgSetU8( pci, 0xE4, 0x07);
5476 /* Next Item Pointer: None (Message Signalled Interrupts are disabled) */
5477 e1kPCICfgSetU8( pci, 0xE4 + 1, 0x00);
5478 /* PCI-X Command: Enable Relaxed Ordering */
5479 e1kPCICfgSetU16(pci, 0xE4 + 2, 0x0002);
5480 /* PCI-X Status: 32-bit, 66MHz*/
5481 e1kPCICfgSetU32(pci, 0xE4 + 4, 0x0040FFF8);
5482}
5483
5484/**
5485 * @interface_method_impl{PDMDEVREG,pfnConstruct}
5486 */
5487static DECLCALLBACK(int) e1kConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
5488{
5489 E1KSTATE* pState = PDMINS_2_DATA(pDevIns, E1KSTATE*);
5490 int rc;
5491 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
5492
5493 /* Init handles and log related stuff. */
5494 RTStrPrintf(pState->szInstance, sizeof(pState->szInstance), "E1000#%d", iInstance);
5495 E1kLog(("%s Constructing new instance sizeof(E1KRXDESC)=%d\n", INSTANCE(pState), sizeof(E1KRXDESC)));
5496 pState->hTxSem = NIL_RTSEMEVENT;
5497 pState->hEventMoreRxDescAvail = NIL_RTSEMEVENT;
5498
5499 /*
5500 * Validate configuration.
5501 */
5502 if (!CFGMR3AreValuesValid(pCfg, "MAC\0" "CableConnected\0" "AdapterType\0" "LineSpeed\0"))
5503 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
5504 N_("Invalid configuration for E1000 device"));
5505
5506 /** @todo: LineSpeed unused! */
5507
5508 /* Get config params */
5509 rc = CFGMR3QueryBytes(pCfg, "MAC", pState->macConfigured.au8,
5510 sizeof(pState->macConfigured.au8));
5511 if (RT_FAILURE(rc))
5512 return PDMDEV_SET_ERROR(pDevIns, rc,
5513 N_("Configuration error: Failed to get MAC address"));
5514 rc = CFGMR3QueryBool(pCfg, "CableConnected", &pState->fCableConnected);
5515 if (RT_FAILURE(rc))
5516 return PDMDEV_SET_ERROR(pDevIns, rc,
5517 N_("Configuration error: Failed to get the value of 'CableConnected'"));
5518 rc = CFGMR3QueryU32(pCfg, "AdapterType", (uint32_t*)&pState->eChip);
5519 if (RT_FAILURE(rc))
5520 return PDMDEV_SET_ERROR(pDevIns, rc,
5521 N_("Configuration error: Failed to get the value of 'AdapterType'"));
5522 Assert(pState->eChip <= E1K_CHIP_82545EM);
5523
5524 E1kLog(("%s Chip=%s\n", INSTANCE(pState), g_Chips[pState->eChip].pcszName));
5525
5526 /* Initialize state structure */
5527 pState->fR0Enabled = true;
5528 pState->fGCEnabled = true;
5529 pState->pDevInsR3 = pDevIns;
5530 pState->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
5531 pState->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
5532 pState->u16TxPktLen = 0;
5533 pState->fIPcsum = false;
5534 pState->fTCPcsum = false;
5535 pState->fIntMaskUsed = false;
5536 pState->fDelayInts = false;
5537 pState->fLocked = false;
5538 pState->u64AckedAt = 0;
5539 pState->led.u32Magic = PDMLED_MAGIC;
5540 pState->u32PktNo = 1;
5541
5542#ifdef E1K_INT_STATS
5543 pState->uStatInt = 0;
5544 pState->uStatIntTry = 0;
5545 pState->uStatIntLower = 0;
5546 pState->uStatIntDly = 0;
5547 pState->uStatDisDly = 0;
5548 pState->iStatIntLost = 0;
5549 pState->iStatIntLostOne = 0;
5550 pState->uStatIntLate = 0;
5551 pState->uStatIntMasked = 0;
5552 pState->uStatIntEarly = 0;
5553 pState->uStatIntRx = 0;
5554 pState->uStatIntTx = 0;
5555 pState->uStatIntICS = 0;
5556 pState->uStatIntRDTR = 0;
5557 pState->uStatIntRXDMT0 = 0;
5558 pState->uStatIntTXQE = 0;
5559 pState->uStatTxNoRS = 0;
5560 pState->uStatTxIDE = 0;
5561 pState->uStatTAD = 0;
5562 pState->uStatTID = 0;
5563 pState->uStatRAD = 0;
5564 pState->uStatRID = 0;
5565 pState->uStatRxFrm = 0;
5566 pState->uStatTxFrm = 0;
5567 pState->uStatDescCtx = 0;
5568 pState->uStatDescDat = 0;
5569 pState->uStatDescLeg = 0;
5570#endif /* E1K_INT_STATS */
5571
5572 /* Interfaces */
5573 pState->IBase.pfnQueryInterface = e1kQueryInterface;
5574 pState->INetworkDown.pfnWaitReceiveAvail = e1kWaitReceiveAvail;
5575 pState->INetworkDown.pfnReceive = e1kReceive;
5576 pState->ILeds.pfnQueryStatusLed = e1kQueryStatusLed;
5577 pState->INetworkConfig.pfnGetMac = e1kGetMac;
5578 pState->INetworkConfig.pfnGetLinkState = e1kGetLinkState;
5579 pState->INetworkConfig.pfnSetLinkState = e1kSetLinkState;
5580
5581 /* Initialize the EEPROM */
5582 pState->eeprom.init(pState->macConfigured);
5583
5584 /* Initialize internal PHY */
5585 Phy::init(&pState->phy, iInstance,
5586 pState->eChip == E1K_CHIP_82543GC?
5587 PHY_EPID_M881000 : PHY_EPID_M881011);
5588 Phy::setLinkStatus(&pState->phy, pState->fCableConnected);
5589
5590 rc = PDMDevHlpSSMRegisterEx(pDevIns, E1K_SAVEDSTATE_VERSION, sizeof(E1KSTATE), NULL,
5591 NULL, e1kLiveExec, NULL,
5592 e1kSavePrep, e1kSaveExec, NULL,
5593 e1kLoadPrep, e1kLoadExec, e1kLoadDone);
5594 if (RT_FAILURE(rc))
5595 return rc;
5596
5597 /* Initialize critical section */
5598 rc = PDMDevHlpCritSectInit(pDevIns, &pState->cs, RT_SRC_POS, "%s", pState->szInstance);
5599 if (RT_FAILURE(rc))
5600 return rc;
5601#ifndef E1K_GLOBAL_MUTEX
5602 rc = PDMDevHlpCritSectInit(pDevIns, &pState->csRx, RT_SRC_POS, "%sRX", pState->szInstance);
5603 if (RT_FAILURE(rc))
5604 return rc;
5605#endif
5606
5607 /* Set PCI config registers */
5608 e1kConfigurePCI(pState->pciDevice, pState->eChip);
5609 /* Register PCI device */
5610 rc = PDMDevHlpPCIRegister(pDevIns, &pState->pciDevice);
5611 if (RT_FAILURE(rc))
5612 return rc;
5613
5614 /* Map our registers to memory space (region 0, see e1kConfigurePCI)*/
5615 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0, E1K_MM_SIZE,
5616 PCI_ADDRESS_SPACE_MEM, e1kMap);
5617 if (RT_FAILURE(rc))
5618 return rc;
5619 /* Map our registers to IO space (region 2, see e1kConfigurePCI) */
5620 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 2, E1K_IOPORT_SIZE,
5621 PCI_ADDRESS_SPACE_IO, e1kMap);
5622 if (RT_FAILURE(rc))
5623 return rc;
5624
5625 /* Create transmit queue */
5626 rc = PDMDevHlpQueueCreate(pDevIns, sizeof(PDMQUEUEITEMCORE), 1, 0,
5627 e1kTxQueueConsumer, true, "E1000-Xmit", &pState->pTxQueueR3);
5628 if (RT_FAILURE(rc))
5629 return rc;
5630 pState->pTxQueueR0 = PDMQueueR0Ptr(pState->pTxQueueR3);
5631 pState->pTxQueueRC = PDMQueueRCPtr(pState->pTxQueueR3);
5632
5633 /* Create the RX notifier signaller. */
5634 rc = PDMDevHlpQueueCreate(pDevIns, sizeof(PDMQUEUEITEMCORE), 1, 0,
5635 e1kCanRxQueueConsumer, true, "E1000-Rcv", &pState->pCanRxQueueR3);
5636 if (RT_FAILURE(rc))
5637 return rc;
5638 pState->pCanRxQueueR0 = PDMQueueR0Ptr(pState->pCanRxQueueR3);
5639 pState->pCanRxQueueRC = PDMQueueRCPtr(pState->pCanRxQueueR3);
5640
5641#ifdef E1K_USE_TX_TIMERS
5642 /* Create Transmit Interrupt Delay Timer */
5643 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, e1kTxIntDelayTimer, pState,
5644 TMTIMER_FLAGS_DEFAULT_CRIT_SECT, /** @todo check locking here. */
5645 "E1000 Transmit Interrupt Delay Timer", &pState->pTIDTimerR3);
5646 if (RT_FAILURE(rc))
5647 return rc;
5648 pState->pTIDTimerR0 = TMTimerR0Ptr(pState->pTIDTimerR3);
5649 pState->pTIDTimerRC = TMTimerRCPtr(pState->pTIDTimerR3);
5650
5651# ifndef E1K_NO_TAD
5652 /* Create Transmit Absolute Delay Timer */
5653 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, e1kTxAbsDelayTimer, pState,
5654 TMTIMER_FLAGS_DEFAULT_CRIT_SECT, /** @todo check locking here. */
5655 "E1000 Transmit Absolute Delay Timer", &pState->pTADTimerR3);
5656 if (RT_FAILURE(rc))
5657 return rc;
5658 pState->pTADTimerR0 = TMTimerR0Ptr(pState->pTADTimerR3);
5659 pState->pTADTimerRC = TMTimerRCPtr(pState->pTADTimerR3);
5660# endif /* E1K_NO_TAD */
5661#endif /* E1K_USE_TX_TIMERS */
5662
5663#ifdef E1K_USE_RX_TIMERS
5664 /* Create Receive Interrupt Delay Timer */
5665 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, e1kRxIntDelayTimer, pState,
5666 TMTIMER_FLAGS_DEFAULT_CRIT_SECT, /** @todo check locking here. */
5667 "E1000 Receive Interrupt Delay Timer", &pState->pRIDTimerR3);
5668 if (RT_FAILURE(rc))
5669 return rc;
5670 pState->pRIDTimerR0 = TMTimerR0Ptr(pState->pRIDTimerR3);
5671 pState->pRIDTimerRC = TMTimerRCPtr(pState->pRIDTimerR3);
5672
5673 /* Create Receive Absolute Delay Timer */
5674 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, e1kRxAbsDelayTimer, pState,
5675 TMTIMER_FLAGS_DEFAULT_CRIT_SECT, /** @todo check locking here. */
5676 "E1000 Receive Absolute Delay Timer", &pState->pRADTimerR3);
5677 if (RT_FAILURE(rc))
5678 return rc;
5679 pState->pRADTimerR0 = TMTimerR0Ptr(pState->pRADTimerR3);
5680 pState->pRADTimerRC = TMTimerRCPtr(pState->pRADTimerR3);
5681#endif /* E1K_USE_RX_TIMERS */
5682
5683 /* Create Late Interrupt Timer */
5684 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, e1kLateIntTimer, pState,
5685 TMTIMER_FLAGS_DEFAULT_CRIT_SECT, /** @todo check locking here. */
5686 "E1000 Late Interrupt Timer", &pState->pIntTimerR3);
5687 if (RT_FAILURE(rc))
5688 return rc;
5689 pState->pIntTimerR0 = TMTimerR0Ptr(pState->pIntTimerR3);
5690 pState->pIntTimerRC = TMTimerRCPtr(pState->pIntTimerR3);
5691
5692 /* Create Link Up Timer */
5693 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, e1kLinkUpTimer, pState,
5694 TMTIMER_FLAGS_DEFAULT_CRIT_SECT, /** @todo check locking here. */
5695 "E1000 Link Up Timer", &pState->pLUTimerR3);
5696 if (RT_FAILURE(rc))
5697 return rc;
5698 pState->pLUTimerR0 = TMTimerR0Ptr(pState->pLUTimerR3);
5699 pState->pLUTimerRC = TMTimerRCPtr(pState->pLUTimerR3);
5700
5701 /* Status driver */
5702 PPDMIBASE pBase;
5703 rc = PDMDevHlpDriverAttach(pDevIns, PDM_STATUS_LUN, &pState->IBase, &pBase, "Status Port");
5704 if (RT_FAILURE(rc))
5705 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to attach the status LUN"));
5706 pState->pLedsConnector = PDMIBASE_QUERY_INTERFACE(pBase, PDMILEDCONNECTORS);
5707
5708 rc = PDMDevHlpDriverAttach(pDevIns, 0, &pState->IBase, &pState->pDrvBase, "Network Port");
5709 if (RT_SUCCESS(rc))
5710 {
5711 if (rc == VINF_NAT_DNS)
5712 {
5713 PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "NoDNSforNAT",
5714 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"));
5715 }
5716 pState->pDrv = PDMIBASE_QUERY_INTERFACE(pState->pDrvBase, PDMINETWORKUP);
5717 AssertMsgReturn(pState->pDrv, ("Failed to obtain the PDMINETWORKUP interface!\n"),
5718 VERR_PDM_MISSING_INTERFACE_BELOW);
5719 }
5720 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
5721 {
5722 E1kLog(("%s This adapter is not attached to any network!\n", INSTANCE(pState)));
5723 }
5724 else
5725 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to attach the network LUN"));
5726
5727 rc = RTSemEventCreate(&pState->hTxSem);
5728 if (RT_FAILURE(rc))
5729 return rc;
5730 rc = RTSemEventCreate(&pState->hEventMoreRxDescAvail);
5731 if (RT_FAILURE(rc))
5732 return rc;
5733
5734 e1kHardReset(pState);
5735
5736#ifdef VBOX_WITH_TX_THREAD_IN_NET_DEVICES
5737 rc = PDMDevHlpThreadCreate(pDevIns, &pState->pTxThread, pState, e1kTxThread, e1kTxThreadWakeUp, 0, RTTHREADTYPE_IO, "E1000_TX");
5738 if (RT_FAILURE(rc))
5739 return rc;
5740#endif
5741
5742#if defined(VBOX_WITH_STATISTICS) || defined(E1K_REL_STATS)
5743 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatMMIOReadGC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling MMIO reads in GC", "/Devices/E1k%d/MMIO/ReadGC", iInstance);
5744 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatMMIOReadHC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling MMIO reads in HC", "/Devices/E1k%d/MMIO/ReadHC", iInstance);
5745 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatMMIOWriteGC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling MMIO writes in GC", "/Devices/E1k%d/MMIO/WriteGC", iInstance);
5746 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatMMIOWriteHC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling MMIO writes in HC", "/Devices/E1k%d/MMIO/WriteHC", iInstance);
5747 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatEEPROMRead, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling EEPROM reads", "/Devices/E1k%d/EEPROM/Read", iInstance);
5748 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatEEPROMWrite, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling EEPROM writes", "/Devices/E1k%d/EEPROM/Write", iInstance);
5749 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatIOReadGC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling IO reads in GC", "/Devices/E1k%d/IO/ReadGC", iInstance);
5750 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatIOReadHC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling IO reads in HC", "/Devices/E1k%d/IO/ReadHC", iInstance);
5751 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatIOWriteGC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling IO writes in GC", "/Devices/E1k%d/IO/WriteGC", iInstance);
5752 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatIOWriteHC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling IO writes in HC", "/Devices/E1k%d/IO/WriteHC", iInstance);
5753 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatLateIntTimer, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling late int timer", "/Devices/E1k%d/LateInt/Timer", iInstance);
5754 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatLateInts, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of late interrupts", "/Devices/E1k%d/LateInt/Occured", iInstance);
5755 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatIntsRaised, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of raised interrupts", "/Devices/E1k%d/Interrupts/Raised", iInstance);
5756 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatIntsPrevented, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of prevented interrupts", "/Devices/E1k%d/Interrupts/Prevented", iInstance);
5757 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatReceive, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling receive", "/Devices/E1k%d/Receive/Total", iInstance);
5758 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatReceiveFilter, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling receive filtering", "/Devices/E1k%d/Receive/Filter", iInstance);
5759 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatReceiveStore, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling receive storing", "/Devices/E1k%d/Receive/Store", iInstance);
5760 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatRxOverflow, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_OCCURENCE, "Profiling RX overflows", "/Devices/E1k%d/RxOverflow", iInstance);
5761 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatRxOverflowWakeup, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of RX overflow wakeups", "/Devices/E1k%d/RxOverflowWakeup", iInstance);
5762#endif /* VBOX_WITH_STATISTICS || E1K_REL_STATS */
5763 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatReceiveBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Amount of data received", "/Devices/E1k%d/ReceiveBytes", iInstance);
5764#if defined(VBOX_WITH_STATISTICS) || defined(E1K_REL_STATS)
5765 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatTransmit, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling transmits in HC", "/Devices/E1k%d/Transmit/Total", iInstance);
5766#endif /* VBOX_WITH_STATISTICS || E1K_REL_STATS */
5767 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatTransmitBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Amount of data transmitted", "/Devices/E1k%d/TransmitBytes", iInstance);
5768#if defined(VBOX_WITH_STATISTICS) || defined(E1K_REL_STATS)
5769 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatTransmitSend, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling send transmit in HC", "/Devices/E1k%d/Transmit/Send", iInstance);
5770
5771 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatTxDescLegacy, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of TX legacy descriptors", "/Devices/E1k%d/TxDesc/Legacy", iInstance);
5772 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatTxDescData, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of TX data descriptors", "/Devices/E1k%d/TxDesc/Data", iInstance);
5773 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatTxDescTSEData, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of TX TSE data descriptors", "/Devices/E1k%d/TxDesc/TSEData", iInstance);
5774 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatPHYAccesses, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of PHY accesses", "/Devices/E1k%d/PHYAccesses", iInstance);
5775#endif /* VBOX_WITH_STATISTICS || E1K_REL_STATS */
5776
5777 return VINF_SUCCESS;
5778}
5779
5780/**
5781 * The device registration structure.
5782 */
5783const PDMDEVREG g_DeviceE1000 =
5784{
5785 /* Structure version. PDM_DEVREG_VERSION defines the current version. */
5786 PDM_DEVREG_VERSION,
5787 /* Device name. */
5788 "e1000",
5789 /* Name of guest context module (no path).
5790 * Only evalutated if PDM_DEVREG_FLAGS_RC is set. */
5791 "VBoxDDGC.gc",
5792 /* Name of ring-0 module (no path).
5793 * Only evalutated if PDM_DEVREG_FLAGS_RC is set. */
5794 "VBoxDDR0.r0",
5795 /* The description of the device. The UTF-8 string pointed to shall, like this structure,
5796 * remain unchanged from registration till VM destruction. */
5797 "Intel PRO/1000 MT Desktop Ethernet.\n",
5798
5799 /* Flags, combination of the PDM_DEVREG_FLAGS_* \#defines. */
5800 PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
5801 /* Device class(es), combination of the PDM_DEVREG_CLASS_* \#defines. */
5802 PDM_DEVREG_CLASS_NETWORK,
5803 /* Maximum number of instances (per VM). */
5804 8,
5805 /* Size of the instance data. */
5806 sizeof(E1KSTATE),
5807
5808 /* Construct instance - required. */
5809 e1kConstruct,
5810 /* Destruct instance - optional. */
5811 e1kDestruct,
5812 /* Relocation command - optional. */
5813 e1kRelocate,
5814 /* I/O Control interface - optional. */
5815 NULL,
5816 /* Power on notification - optional. */
5817 NULL,
5818 /* Reset notification - optional. */
5819 NULL,
5820 /* Suspend notification - optional. */
5821 e1kSuspend,
5822 /* Resume notification - optional. */
5823 NULL,
5824#ifdef VBOX_DYNAMIC_NET_ATTACH
5825 /* Attach command - optional. */
5826 e1kAttach,
5827 /* Detach notification - optional. */
5828 e1kDetach,
5829#else /* !VBOX_DYNAMIC_NET_ATTACH */
5830 /* Attach command - optional. */
5831 NULL,
5832 /* Detach notification - optional. */
5833 NULL,
5834#endif /* !VBOX_DYNAMIC_NET_ATTACH */
5835 /* Query a LUN base interface - optional. */
5836 NULL,
5837 /* Init complete notification - optional. */
5838 NULL,
5839 /* Power off notification - optional. */
5840 e1kPowerOff,
5841 /* pfnSoftReset */
5842 NULL,
5843 /* u32VersionEnd */
5844 PDM_DEVREG_VERSION
5845};
5846
5847#endif /* IN_RING3 */
5848#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
5849
Note: See TracBrowser for help on using the repository browser.

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