VirtualBox

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

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

DevE1000: Shut up MSC warnings.

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

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