VirtualBox

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

Last change on this file since 16684 was 15955, checked in by vboxsync, 16 years ago

fix OSE headers

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