VirtualBox

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

Last change on this file since 17656 was 17183, checked in by vboxsync, 16 years ago

#3681: GRUB DHCP fix: fake TX descriptor write-back bursting.

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

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