VirtualBox

source: vbox/trunk/src/VBox/Devices/Network/DevPCNet.cpp@ 29354

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

Automated rebranding to Oracle copyright/license strings via filemuncher

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 204.9 KB
Line 
1/* $Id: DevPCNet.cpp 28800 2010-04-27 08:22:32Z vboxsync $ */
2/** @file
3 * DevPCNet - AMD PCnet-PCI II / PCnet-FAST III (Am79C970A / Am79C973) Ethernet Controller Emulation.
4 *
5 * This software was written to be compatible with the specifications:
6 * AMD Am79C970A PCnet-PCI II Ethernet Controller Data-Sheet
7 * AMD Publication# 19436 Rev:E Amendment/0 Issue Date: June 2000
8 * and
9 * todo
10 */
11
12/*
13 * Copyright (C) 2006-2010 Oracle Corporation
14 *
15 * This file is part of VirtualBox Open Source Edition (OSE), as
16 * available from http://www.virtualbox.org. This file is free software;
17 * you can redistribute it and/or modify it under the terms of the GNU
18 * General Public License (GPL) as published by the Free Software
19 * Foundation, in version 2 as it comes in the "COPYING" file of the
20 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
21 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
22 * --------------------------------------------------------------------
23 *
24 * This code is based on:
25 *
26 * AMD PC-Net II (Am79C970A) emulation
27 *
28 * Copyright (c) 2004 Antony T Curtis
29 *
30 * Permission is hereby granted, free of charge, to any person obtaining a copy
31 * of this software and associated documentation files (the "Software"), to deal
32 * in the Software without restriction, including without limitation the rights
33 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
34 * copies of the Software, and to permit persons to whom the Software is
35 * furnished to do so, subject to the following conditions:
36 *
37 * The above copyright notice and this permission notice shall be included in
38 * all copies or substantial portions of the Software.
39 *
40 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
41 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
42 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
43 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
44 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
45 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
46 * THE SOFTWARE.
47 */
48
49
50/*******************************************************************************
51* Header Files *
52*******************************************************************************/
53#define LOG_GROUP LOG_GROUP_DEV_PCNET
54#include <VBox/pdmdev.h>
55#include <VBox/pdmnetifs.h>
56#include <VBox/pgm.h>
57#include <VBox/DevPCNet.h>
58#include <iprt/asm.h>
59#include <iprt/assert.h>
60#include <iprt/critsect.h>
61#include <iprt/net.h>
62#include <iprt/string.h>
63#include <iprt/time.h>
64#ifdef IN_RING3
65# include <iprt/mem.h>
66# include <iprt/semaphore.h>
67# include <iprt/uuid.h>
68#endif
69
70#include "../Builtins.h"
71
72/* Enable this to catch writes to the ring descriptors instead of using excessive polling */
73/* #define PCNET_NO_POLLING */
74
75/* Enable to handle frequent io reads in the guest context (recommended) */
76#define PCNET_GC_ENABLED
77
78#if defined(LOG_ENABLED)
79#define PCNET_DEBUG_IO
80#define PCNET_DEBUG_BCR
81#define PCNET_DEBUG_CSR
82#define PCNET_DEBUG_RMD
83#define PCNET_DEBUG_TMD
84#define PCNET_DEBUG_MATCH
85#define PCNET_DEBUG_MII
86#endif
87
88#define PCNET_IOPORT_SIZE 0x20
89#define PCNET_PNPMMIO_SIZE 0x20
90
91#define PCNET_SAVEDSTATE_VERSION 10
92
93#define BCR_MAX_RAP 50
94#define MII_MAX_REG 32
95#define CSR_MAX_REG 128
96
97/* Maximum number of times we report a link down to the guest (failure to send frame) */
98#define PCNET_MAX_LINKDOWN_REPORTED 3
99
100/* Maximum frame size we handle */
101#define MAX_FRAME 1536
102
103
104typedef struct PCNetState_st PCNetState;
105
106/**
107 * PCNET state.
108 *
109 * @extends PCIDEVICE
110 * @implements PDMIBASE
111 * @implements PDMINETWORKDOWN
112 * @implements PDMINETWORKCONFIG
113 * @implements PDMILEDPORTS
114 */
115struct PCNetState_st
116{
117 PCIDEVICE PciDev;
118
119 /** Pointer to the device instance - R3. */
120 PPDMDEVINSR3 pDevInsR3;
121 /** Transmit signaller - R3. */
122 R3PTRTYPE(PPDMQUEUE) pXmitQueueR3;
123 /** Receive signaller - R3. */
124 R3PTRTYPE(PPDMQUEUE) pCanRxQueueR3;
125 /** Pointer to the connector of the attached network driver - R3. */
126 PPDMINETWORKUPR3 pDrvR3;
127 /** Pointer to the attached network driver. */
128 R3PTRTYPE(PPDMIBASE) pDrvBase;
129 /** LUN\#0 + status LUN: The base interface. */
130 PDMIBASE IBase;
131 /** LUN\#0: The network port interface. */
132 PDMINETWORKDOWN INetworkDown;
133 /** LUN\#0: The network config port interface. */
134 PDMINETWORKCONFIG INetworkConfig;
135 /** The shared memory used for the private interface - R3. */
136 R3PTRTYPE(PPCNETGUESTSHAREDMEMORY) pSharedMMIOR3;
137 /** Software Interrupt timer - R3. */
138 PTMTIMERR3 pTimerSoftIntR3;
139#ifndef PCNET_NO_POLLING
140 /** Poll timer - R3. */
141 PTMTIMERR3 pTimerPollR3;
142#endif
143 /** Restore timer.
144 * This is used to disconnect and reconnect the link after a restore. */
145 PTMTIMERR3 pTimerRestore;
146
147 /** Pointer to the device instance - R0. */
148 PPDMDEVINSR0 pDevInsR0;
149 /** Receive signaller - R0. */
150 R0PTRTYPE(PPDMQUEUE) pCanRxQueueR0;
151 /** Transmit signaller - R0. */
152 R0PTRTYPE(PPDMQUEUE) pXmitQueueR0;
153 /** Pointer to the connector of the attached network driver - R0. */
154 PPDMINETWORKUPR0 pDrvR0;
155 /** The shared memory used for the private interface - R0. */
156 R0PTRTYPE(PPCNETGUESTSHAREDMEMORY) pSharedMMIOR0;
157 /** Software Interrupt timer - R0. */
158 PTMTIMERR0 pTimerSoftIntR0;
159#ifndef PCNET_NO_POLLING
160 /** Poll timer - R0. */
161 PTMTIMERR0 pTimerPollR0;
162#endif
163
164 /** Pointer to the device instance - RC. */
165 PPDMDEVINSRC pDevInsRC;
166 /** Receive signaller - RC. */
167 RCPTRTYPE(PPDMQUEUE) pCanRxQueueRC;
168 /** Transmit signaller - RC. */
169 RCPTRTYPE(PPDMQUEUE) pXmitQueueRC;
170 /** Pointer to the connector of the attached network driver - RC. */
171 PPDMINETWORKUPRC pDrvRC;
172 /** The shared memory used for the private interface - RC. */
173 RCPTRTYPE(PPCNETGUESTSHAREDMEMORY) pSharedMMIORC;
174 /** Software Interrupt timer - RC. */
175 PTMTIMERRC pTimerSoftIntRC;
176#ifndef PCNET_NO_POLLING
177 /** Poll timer - RC. */
178 PTMTIMERRC pTimerPollRC;
179#endif
180
181#if HC_ARCH_BITS == 64
182 uint32_t Alignment1;
183#endif
184
185 /** Register Address Pointer */
186 uint32_t u32RAP;
187 /** Internal interrupt service */
188 int32_t iISR;
189 /** ??? */
190 uint32_t u32Lnkst;
191 /** Address of the RX descriptor table (ring). Loaded at init. */
192 RTGCPHYS32 GCRDRA;
193 /** Address of the TX descriptor table (ring). Loaded at init. */
194 RTGCPHYS32 GCTDRA;
195 uint8_t aPROM[16];
196 uint16_t aCSR[CSR_MAX_REG];
197 uint16_t aBCR[BCR_MAX_RAP];
198 uint16_t aMII[MII_MAX_REG];
199 uint16_t u16CSR0LastSeenByGuest;
200 uint16_t Alignment2[HC_ARCH_BITS == 32 ? 2 : 2];
201 /** Last time we polled the queues */
202 uint64_t u64LastPoll;
203
204 /** The loopback transmit buffer (avoid stack allocations). */
205 uint8_t abLoopBuf[4096];
206 /** The recv buffer. */
207 uint8_t abRecvBuf[4096];
208
209 /** Unused / padding. */
210 uint32_t u32Unused;
211
212 /** Size of a RX/TX descriptor (8 or 16 bytes according to SWSTYLE */
213 int iLog2DescSize;
214 /** Bits 16..23 in 16-bit mode */
215 RTGCPHYS32 GCUpperPhys;
216
217 /** Base address of the MMIO region. */
218 RTGCPHYS32 MMIOBase;
219 /** Base port of the I/O space region. */
220 RTIOPORT IOPortBase;
221 /** If set the link is currently up. */
222 bool fLinkUp;
223 /** If set the link is temporarily down because of a saved state load. */
224 bool fLinkTempDown;
225
226 /** Number of times we've reported the link down. */
227 RTUINT cLinkDownReported;
228 /** The configured MAC address. */
229 RTMAC MacConfigured;
230 /** Alignment padding. */
231 uint8_t Alignment4[HC_ARCH_BITS == 64 ? 2 : 2];
232
233 /** The LED. */
234 PDMLED Led;
235 /** Status LUN: The LED ports. */
236 PDMILEDPORTS ILeds;
237 /** Partner of ILeds. */
238 R3PTRTYPE(PPDMILEDCONNECTORS) pLedsConnector;
239
240 /** Access critical section. */
241 PDMCRITSECT CritSect;
242 /** Event semaphore for blocking on receive. */
243 RTSEMEVENT hEventOutOfRxSpace;
244 /** We are waiting/about to start waiting for more receive buffers. */
245 bool volatile fMaybeOutOfSpace;
246 /** True if we signal the guest that RX packets are missing. */
247 bool fSignalRxMiss;
248 uint8_t Alignment5[HC_ARCH_BITS == 64 ? 2 : 6];
249
250#ifdef PCNET_NO_POLLING
251 RTGCPHYS32 TDRAPhysOld;
252 uint32_t cbTDRAOld;
253
254 RTGCPHYS32 RDRAPhysOld;
255 uint32_t cbRDRAOld;
256
257 DECLRCCALLBACKMEMBER(int, pfnEMInterpretInstructionRC, (PVM pVM, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize));
258 DECLR0CALLBACKMEMBER(int, pfnEMInterpretInstructionR0, (PVM pVM, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize));
259#endif
260
261 /** Error counter for bad receive descriptors. */
262 uint32_t uCntBadRMD;
263
264 /** True if host and guest admitted to use the private interface. */
265 bool fPrivIfEnabled;
266 bool fGCEnabled;
267 bool fR0Enabled;
268 bool fAm79C973;
269 uint32_t u32LinkSpeed;
270
271 STAMCOUNTER StatReceiveBytes;
272 STAMCOUNTER StatTransmitBytes;
273#ifdef VBOX_WITH_STATISTICS
274 STAMPROFILEADV StatMMIOReadGC;
275 STAMPROFILEADV StatMMIOReadHC;
276 STAMPROFILEADV StatMMIOWriteGC;
277 STAMPROFILEADV StatMMIOWriteHC;
278 STAMPROFILEADV StatAPROMRead;
279 STAMPROFILEADV StatAPROMWrite;
280 STAMPROFILEADV StatIOReadGC;
281 STAMPROFILEADV StatIOReadHC;
282 STAMPROFILEADV StatIOWriteGC;
283 STAMPROFILEADV StatIOWriteHC;
284 STAMPROFILEADV StatTimer;
285 STAMPROFILEADV StatReceive;
286 STAMPROFILEADV StatTransmit;
287 STAMCOUNTER StatTransmitCase1;
288 STAMCOUNTER StatTransmitCase2;
289 STAMPROFILE StatTransmitSend;
290 STAMPROFILEADV StatTdtePollGC;
291 STAMPROFILEADV StatTdtePollHC;
292 STAMPROFILEADV StatTmdStoreGC;
293 STAMPROFILEADV StatTmdStoreHC;
294 STAMPROFILEADV StatRdtePollGC;
295 STAMPROFILEADV StatRdtePollHC;
296 STAMPROFILE StatRxOverflow;
297 STAMCOUNTER StatRxOverflowWakeup;
298 STAMCOUNTER aStatXmitFlush[16];
299 STAMCOUNTER aStatXmitChainCounts[16];
300 STAMCOUNTER StatXmitSkipCurrent;
301 STAMPROFILEADV StatInterrupt;
302 STAMPROFILEADV StatPollTimer;
303 STAMCOUNTER StatMIIReads;
304# ifdef PCNET_NO_POLLING
305 STAMCOUNTER StatRCVRingWrite;
306 STAMCOUNTER StatTXRingWrite;
307 STAMCOUNTER StatRingWriteHC;
308 STAMCOUNTER StatRingWriteR0;
309 STAMCOUNTER StatRingWriteGC;
310
311 STAMCOUNTER StatRingWriteFailedHC;
312 STAMCOUNTER StatRingWriteFailedR0;
313 STAMCOUNTER StatRingWriteFailedGC;
314
315 STAMCOUNTER StatRingWriteOutsideHC;
316 STAMCOUNTER StatRingWriteOutsideR0;
317 STAMCOUNTER StatRingWriteOutsideGC;
318# endif
319#endif /* VBOX_WITH_STATISTICS */
320};
321//AssertCompileMemberAlignment(PCNetState, StatReceiveBytes, 8);
322
323#define PCNETSTATE_2_DEVINS(pPCNet) ((pPCNet)->CTX_SUFF(pDevIns))
324#define PCIDEV_2_PCNETSTATE(pPciDev) ((PCNetState *)(pPciDev))
325#define PCNET_INST_NR (PCNETSTATE_2_DEVINS(pThis)->iInstance)
326
327/* BUS CONFIGURATION REGISTERS */
328#define BCR_MSRDA 0
329#define BCR_MSWRA 1
330#define BCR_MC 2
331#define BCR_RESERVED3 3
332#define BCR_LNKST 4
333#define BCR_LED1 5
334#define BCR_LED2 6
335#define BCR_LED3 7
336#define BCR_RESERVED8 8
337#define BCR_FDC 9
338/* 10 - 15 = reserved */
339#define BCR_IOBASEL 16 /* Reserved */
340#define BCR_IOBASEU 16 /* Reserved */
341#define BCR_BSBC 18
342#define BCR_EECAS 19
343#define BCR_SWS 20
344#define BCR_INTCON 21 /* Reserved */
345#define BCR_PLAT 22
346#define BCR_PCISVID 23
347#define BCR_PCISID 24
348#define BCR_SRAMSIZ 25
349#define BCR_SRAMB 26
350#define BCR_SRAMIC 27
351#define BCR_EBADDRL 28
352#define BCR_EBADDRU 29
353#define BCR_EBD 30
354#define BCR_STVAL 31
355#define BCR_MIICAS 32
356#define BCR_MIIADDR 33
357#define BCR_MIIMDR 34
358#define BCR_PCIVID 35
359#define BCR_PMC_A 36
360#define BCR_DATA0 37
361#define BCR_DATA1 38
362#define BCR_DATA2 39
363#define BCR_DATA3 40
364#define BCR_DATA4 41
365#define BCR_DATA5 42
366#define BCR_DATA6 43
367#define BCR_DATA7 44
368#define BCR_PMR1 45
369#define BCR_PMR2 46
370#define BCR_PMR3 47
371
372#define BCR_DWIO(S) !!((S)->aBCR[BCR_BSBC] & 0x0080)
373#define BCR_SSIZE32(S) !!((S)->aBCR[BCR_SWS ] & 0x0100)
374#define BCR_SWSTYLE(S) ((S)->aBCR[BCR_SWS ] & 0x00FF)
375
376#define CSR_INIT(S) !!((S)->aCSR[0] & 0x0001) /**< Init assertion */
377#define CSR_STRT(S) !!((S)->aCSR[0] & 0x0002) /**< Start assertion */
378#define CSR_STOP(S) !!((S)->aCSR[0] & 0x0004) /**< Stop assertion */
379#define CSR_TDMD(S) !!((S)->aCSR[0] & 0x0008) /**< Transmit demand. (perform xmit poll now (readable, settable, not clearable) */
380#define CSR_TXON(S) !!((S)->aCSR[0] & 0x0010) /**< Transmit on (readonly) */
381#define CSR_RXON(S) !!((S)->aCSR[0] & 0x0020) /**< Receive On */
382#define CSR_INEA(S) !!((S)->aCSR[0] & 0x0040) /**< Interrupt Enable */
383#define CSR_LAPPEN(S) !!((S)->aCSR[3] & 0x0020) /**< Look Ahead Packet Processing Enable */
384#define CSR_DXSUFLO(S) !!((S)->aCSR[3] & 0x0040) /**< Disable Transmit Stop on Underflow error */
385#define CSR_ASTRP_RCV(S) !!((S)->aCSR[4] & 0x0400) /**< Auto Strip Receive */
386#define CSR_DPOLL(S) !!((S)->aCSR[4] & 0x1000) /**< Disable Transmit Polling */
387#define CSR_SPND(S) !!((S)->aCSR[5] & 0x0001) /**< Suspend */
388#define CSR_LTINTEN(S) !!((S)->aCSR[5] & 0x4000) /**< Last Transmit Interrupt Enable */
389#define CSR_TOKINTD(S) !!((S)->aCSR[5] & 0x8000) /**< Transmit OK Interrupt Disable */
390
391#define CSR_STINT !!((S)->aCSR[7] & 0x0800) /**< Software Timer Interrupt */
392#define CSR_STINTE !!((S)->aCSR[7] & 0x0400) /**< Software Timer Interrupt Enable */
393
394#define CSR_DRX(S) !!((S)->aCSR[15] & 0x0001) /**< Disable Receiver */
395#define CSR_DTX(S) !!((S)->aCSR[15] & 0x0002) /**< Disable Transmit */
396#define CSR_LOOP(S) !!((S)->aCSR[15] & 0x0004) /**< Loopback Enable */
397#define CSR_DRCVPA(S) !!((S)->aCSR[15] & 0x2000) /**< Disable Receive Physical Address */
398#define CSR_DRCVBC(S) !!((S)->aCSR[15] & 0x4000) /**< Disable Receive Broadcast */
399#define CSR_PROM(S) !!((S)->aCSR[15] & 0x8000) /**< Promiscuous Mode */
400
401#if !defined(RT_ARCH_X86) && !defined(RT_ARCH_AMD64)
402#error fix macros (and more in this file) for big-endian machines
403#endif
404
405#define CSR_IADR(S) (*(uint32_t*)((S)->aCSR + 1)) /**< Initialization Block Address */
406#define CSR_CRBA(S) (*(uint32_t*)((S)->aCSR + 18)) /**< Current Receive Buffer Address */
407#define CSR_CXBA(S) (*(uint32_t*)((S)->aCSR + 20)) /**< Current Transmit Buffer Address */
408#define CSR_NRBA(S) (*(uint32_t*)((S)->aCSR + 22)) /**< Next Receive Buffer Address */
409#define CSR_BADR(S) (*(uint32_t*)((S)->aCSR + 24)) /**< Base Address of Receive Ring */
410#define CSR_NRDA(S) (*(uint32_t*)((S)->aCSR + 26)) /**< Next Receive Descriptor Address */
411#define CSR_CRDA(S) (*(uint32_t*)((S)->aCSR + 28)) /**< Current Receive Descriptor Address */
412#define CSR_BADX(S) (*(uint32_t*)((S)->aCSR + 30)) /**< Base Address of Transmit Descriptor */
413#define CSR_NXDA(S) (*(uint32_t*)((S)->aCSR + 32)) /**< Next Transmit Descriptor Address */
414#define CSR_CXDA(S) (*(uint32_t*)((S)->aCSR + 34)) /**< Current Transmit Descriptor Address */
415#define CSR_NNRD(S) (*(uint32_t*)((S)->aCSR + 36)) /**< Next Next Receive Descriptor Address */
416#define CSR_NNXD(S) (*(uint32_t*)((S)->aCSR + 38)) /**< Next Next Transmit Descriptor Address */
417#define CSR_CRBC(S) ((S)->aCSR[40]) /**< Current Receive Byte Count */
418#define CSR_CRST(S) ((S)->aCSR[41]) /**< Current Receive Status */
419#define CSR_CXBC(S) ((S)->aCSR[42]) /**< Current Transmit Byte Count */
420#define CSR_CXST(S) ((S)->aCSR[43]) /**< Current transmit status */
421#define CSR_NRBC(S) ((S)->aCSR[44]) /**< Next Receive Byte Count */
422#define CSR_NRST(S) ((S)->aCSR[45]) /**< Next Receive Status */
423#define CSR_POLL(S) ((S)->aCSR[46]) /**< Transmit Poll Time Counter */
424#define CSR_PINT(S) ((S)->aCSR[47]) /**< Transmit Polling Interval */
425#define CSR_PXDA(S) (*(uint32_t*)((S)->aCSR + 60)) /**< Previous Transmit Descriptor Address*/
426#define CSR_PXBC(S) ((S)->aCSR[62]) /**< Previous Transmit Byte Count */
427#define CSR_PXST(S) ((S)->aCSR[63]) /**< Previous Transmit Status */
428#define CSR_NXBA(S) (*(uint32_t*)((S)->aCSR + 64)) /**< Next Transmit Buffer Address */
429#define CSR_NXBC(S) ((S)->aCSR[66]) /**< Next Transmit Byte Count */
430#define CSR_NXST(S) ((S)->aCSR[67]) /**< Next Transmit Status */
431#define CSR_RCVRC(S) ((S)->aCSR[72]) /**< Receive Descriptor Ring Counter */
432#define CSR_XMTRC(S) ((S)->aCSR[74]) /**< Transmit Descriptor Ring Counter */
433#define CSR_RCVRL(S) ((S)->aCSR[76]) /**< Receive Descriptor Ring Length */
434#define CSR_XMTRL(S) ((S)->aCSR[78]) /**< Transmit Descriptor Ring Length */
435#define CSR_MISSC(S) ((S)->aCSR[112]) /**< Missed Frame Count */
436
437#define PHYSADDR(S,A) ((A) | (S)->GCUpperPhys)
438
439/* Version for the PCnet/FAST III 79C973 card */
440#define CSR_VERSION_LOW_79C973 0x5003 /* the lower two bits must be 11b for AMD */
441#define CSR_VERSION_LOW_79C970A 0x1003 /* the lower two bits must be 11b for AMD */
442#define CSR_VERSION_HIGH 0x0262
443
444/** @todo All structs: big endian? */
445
446struct INITBLK16
447{
448 uint16_t mode; /**< copied into csr15 */
449 uint16_t padr1; /**< MAC 0..15 */
450 uint16_t padr2; /**< MAC 16..32 */
451 uint16_t padr3; /**< MAC 33..47 */
452 uint16_t ladrf1; /**< logical address filter 0..15 */
453 uint16_t ladrf2; /**< logical address filter 16..31 */
454 uint16_t ladrf3; /**< logical address filter 32..47 */
455 uint16_t ladrf4; /**< logical address filter 48..63 */
456 uint32_t rdra:24; /**< address of receive descriptor ring */
457 uint32_t res1:5; /**< reserved */
458 uint32_t rlen:3; /**< number of receive descriptor ring entries */
459 uint32_t tdra:24; /**< address of transmit descriptor ring */
460 uint32_t res2:5; /**< reserved */
461 uint32_t tlen:3; /**< number of transmit descriptor ring entries */
462};
463AssertCompileSize(INITBLK16, 24);
464
465/** bird: I've changed the type for the bitfields. They should only be 16-bit all together.
466 * frank: I've changed the bitfiled types to uint32_t to prevent compiler warnings. */
467struct INITBLK32
468{
469 uint16_t mode; /**< copied into csr15 */
470 uint16_t res1:4; /**< reserved */
471 uint16_t rlen:4; /**< number of receive descriptor ring entries */
472 uint16_t res2:4; /**< reserved */
473 uint16_t tlen:4; /**< number of transmit descriptor ring entries */
474 uint16_t padr1; /**< MAC 0..15 */
475 uint16_t padr2; /**< MAC 16..31 */
476 uint16_t padr3; /**< MAC 32..47 */
477 uint16_t res3; /**< reserved */
478 uint16_t ladrf1; /**< logical address filter 0..15 */
479 uint16_t ladrf2; /**< logical address filter 16..31 */
480 uint16_t ladrf3; /**< logibal address filter 32..47 */
481 uint16_t ladrf4; /**< logical address filter 48..63 */
482 uint32_t rdra; /**< address of receive descriptor ring */
483 uint32_t tdra; /**< address of transmit descriptor ring */
484};
485AssertCompileSize(INITBLK32, 28);
486
487/** Transmit Message Descriptor */
488typedef struct TMD
489{
490 struct
491 {
492 uint32_t tbadr; /**< transmit buffer address */
493 } tmd0;
494 struct
495 {
496 uint32_t bcnt:12; /**< buffer byte count (two's complement) */
497 uint32_t ones:4; /**< must be 1111b */
498 uint32_t res:7; /**< reserved */
499 uint32_t bpe:1; /**< bus parity error */
500 uint32_t enp:1; /**< end of packet */
501 uint32_t stp:1; /**< start of packet */
502 uint32_t def:1; /**< deferred */
503 uint32_t one:1; /**< exactly one retry was needed to transmit a frame */
504 uint32_t ltint:1; /**< suppress interrupts after successful transmission */
505 uint32_t nofcs:1; /**< when set, the state of DXMTFCS is ignored and
506 transmitter FCS generation is activated. */
507 uint32_t err:1; /**< error occurred */
508 uint32_t own:1; /**< 0=owned by guest driver, 1=owned by controller */
509 } tmd1;
510 struct
511 {
512 uint32_t trc:4; /**< transmit retry count */
513 uint32_t res:12; /**< reserved */
514 uint32_t tdr:10; /**< ??? */
515 uint32_t rtry:1; /**< retry error */
516 uint32_t lcar:1; /**< loss of carrier */
517 uint32_t lcol:1; /**< late collision */
518 uint32_t exdef:1; /**< excessive deferral */
519 uint32_t uflo:1; /**< underflow error */
520 uint32_t buff:1; /**< out of buffers (ENP not found) */
521 } tmd2;
522 struct
523 {
524 uint32_t res; /**< reserved for user defined space */
525 } tmd3;
526} TMD;
527AssertCompileSize(TMD, 16);
528
529/** Receive Message Descriptor */
530typedef struct RMD
531{
532 struct
533 {
534 uint32_t rbadr; /**< receive buffer address */
535 } rmd0;
536 struct
537 {
538 uint32_t bcnt:12; /**< buffer byte count (two's complement) */
539 uint32_t ones:4; /**< must be 1111b */
540 uint32_t res:4; /**< reserved */
541 uint32_t bam:1; /**< broadcast address match */
542 uint32_t lafm:1; /**< logical filter address match */
543 uint32_t pam:1; /**< physcial address match */
544 uint32_t bpe:1; /**< bus parity error */
545 uint32_t enp:1; /**< end of packet */
546 uint32_t stp:1; /**< start of packet */
547 uint32_t buff:1; /**< buffer error */
548 uint32_t crc:1; /**< crc error on incoming frame */
549 uint32_t oflo:1; /**< overflow error (lost all or part of incoming frame) */
550 uint32_t fram:1; /**< frame error */
551 uint32_t err:1; /**< error occurred */
552 uint32_t own:1; /**< 0=owned by guest driver, 1=owned by controller */
553 } rmd1;
554 struct
555 {
556 uint32_t mcnt:12; /**< message byte count */
557 uint32_t zeros:4; /**< 0000b */
558 uint32_t rpc:8; /**< receive frame tag */
559 uint32_t rcc:8; /**< receive frame tag + reserved */
560 } rmd2;
561 struct
562 {
563 uint32_t res; /**< reserved for user defined space */
564 } rmd3;
565} RMD;
566AssertCompileSize(RMD, 16);
567
568
569#ifndef VBOX_DEVICE_STRUCT_TESTCASE
570/*******************************************************************************
571* Internal Functions *
572*******************************************************************************/
573#define PRINT_TMD(T) Log2(( \
574 "TMD0 : TBADR=%#010x\n" \
575 "TMD1 : OWN=%d, ERR=%d, FCS=%d, LTI=%d, " \
576 "ONE=%d, DEF=%d, STP=%d, ENP=%d,\n" \
577 " BPE=%d, BCNT=%d\n" \
578 "TMD2 : BUF=%d, UFL=%d, EXD=%d, LCO=%d, " \
579 "LCA=%d, RTR=%d,\n" \
580 " TDR=%d, TRC=%d\n", \
581 (T)->tmd0.tbadr, \
582 (T)->tmd1.own, (T)->tmd1.err, (T)->tmd1.nofcs, \
583 (T)->tmd1.ltint, (T)->tmd1.one, (T)->tmd1.def, \
584 (T)->tmd1.stp, (T)->tmd1.enp, (T)->tmd1.bpe, \
585 4096-(T)->tmd1.bcnt, \
586 (T)->tmd2.buff, (T)->tmd2.uflo, (T)->tmd2.exdef,\
587 (T)->tmd2.lcol, (T)->tmd2.lcar, (T)->tmd2.rtry, \
588 (T)->tmd2.tdr, (T)->tmd2.trc))
589
590#define PRINT_RMD(R) Log2(( \
591 "RMD0 : RBADR=%#010x\n" \
592 "RMD1 : OWN=%d, ERR=%d, FRAM=%d, OFLO=%d, " \
593 "CRC=%d, BUFF=%d, STP=%d, ENP=%d,\n " \
594 "BPE=%d, PAM=%d, LAFM=%d, BAM=%d, ONES=%d, BCNT=%d\n" \
595 "RMD2 : RCC=%d, RPC=%d, MCNT=%d, ZEROS=%d\n", \
596 (R)->rmd0.rbadr, \
597 (R)->rmd1.own, (R)->rmd1.err, (R)->rmd1.fram, \
598 (R)->rmd1.oflo, (R)->rmd1.crc, (R)->rmd1.buff, \
599 (R)->rmd1.stp, (R)->rmd1.enp, (R)->rmd1.bpe, \
600 (R)->rmd1.pam, (R)->rmd1.lafm, (R)->rmd1.bam, \
601 (R)->rmd1.ones, 4096-(R)->rmd1.bcnt, \
602 (R)->rmd2.rcc, (R)->rmd2.rpc, (R)->rmd2.mcnt, \
603 (R)->rmd2.zeros))
604
605static void pcnetPollTimerStart(PCNetState *pThis);
606static int pcnetXmitPending(PCNetState *pThis, bool fOnWorkerThread);
607
608
609
610/**
611 * Checks if the link is up.
612 * @returns true if the link is up.
613 * @returns false if the link is down.
614 */
615DECLINLINE(bool) pcnetIsLinkUp(PCNetState *pThis)
616{
617 return pThis->pDrvR3 && !pThis->fLinkTempDown && pThis->fLinkUp;
618}
619
620/**
621 * Load transmit message descriptor
622 * Make sure we read the own flag first.
623 *
624 * @param pThis adapter private data
625 * @param addr physical address of the descriptor
626 * @param fRetIfNotOwn return immediately after reading the own flag if we don't own the descriptor
627 * @return true if we own the descriptor, false otherwise
628 */
629DECLINLINE(bool) pcnetTmdLoad(PCNetState *pThis, TMD *tmd, RTGCPHYS32 addr, bool fRetIfNotOwn)
630{
631 PPDMDEVINS pDevIns = PCNETSTATE_2_DEVINS(pThis);
632 uint8_t ownbyte;
633
634 if (pThis->fPrivIfEnabled)
635 {
636 /* RX/TX descriptors shared between host and guest => direct copy */
637 uint8_t *pv = (uint8_t*)pThis->CTX_SUFF(pSharedMMIO)
638 + (addr - pThis->GCTDRA)
639 + pThis->CTX_SUFF(pSharedMMIO)->V.V1.offTxDescriptors;
640 if (!(pv[7] & 0x80) && fRetIfNotOwn)
641 return false;
642 memcpy(tmd, pv, 16);
643 return true;
644 }
645 else if (RT_UNLIKELY(BCR_SWSTYLE(pThis) == 0))
646 {
647 uint16_t xda[4];
648
649 PDMDevHlpPhysRead(pDevIns, addr+3, &ownbyte, 1);
650 if (!(ownbyte & 0x80) && fRetIfNotOwn)
651 return false;
652 PDMDevHlpPhysRead(pDevIns, addr, (void*)&xda[0], sizeof(xda));
653 ((uint32_t *)tmd)[0] = (uint32_t)xda[0] | ((uint32_t)(xda[1] & 0x00ff) << 16);
654 ((uint32_t *)tmd)[1] = (uint32_t)xda[2] | ((uint32_t)(xda[1] & 0xff00) << 16);
655 ((uint32_t *)tmd)[2] = (uint32_t)xda[3] << 16;
656 ((uint32_t *)tmd)[3] = 0;
657 }
658 else if (RT_LIKELY(BCR_SWSTYLE(pThis) != 3))
659 {
660 PDMDevHlpPhysRead(pDevIns, addr+7, &ownbyte, 1);
661 if (!(ownbyte & 0x80) && fRetIfNotOwn)
662 return false;
663 PDMDevHlpPhysRead(pDevIns, addr, (void*)tmd, 16);
664 }
665 else
666 {
667 uint32_t xda[4];
668 PDMDevHlpPhysRead(pDevIns, addr+7, &ownbyte, 1);
669 if (!(ownbyte & 0x80) && fRetIfNotOwn)
670 return false;
671 PDMDevHlpPhysRead(pDevIns, addr, (void*)&xda[0], sizeof(xda));
672 ((uint32_t *)tmd)[0] = xda[2];
673 ((uint32_t *)tmd)[1] = xda[1];
674 ((uint32_t *)tmd)[2] = xda[0];
675 ((uint32_t *)tmd)[3] = xda[3];
676 }
677 /* Double check the own bit; guest drivers might be buggy and lock prefixes in the recompiler are ignored by other threads. */
678#ifdef DEBUG
679 if (tmd->tmd1.own == 1 && !(ownbyte & 0x80))
680 Log(("pcnetTmdLoad: own bit flipped while reading!!\n"));
681#endif
682 if (!(ownbyte & 0x80))
683 tmd->tmd1.own = 0;
684
685 return !!tmd->tmd1.own;
686}
687
688/**
689 * Store transmit message descriptor and hand it over to the host (the VM guest).
690 * Make sure that all data are transmitted before we clear the own flag.
691 */
692DECLINLINE(void) pcnetTmdStorePassHost(PCNetState *pThis, TMD *tmd, RTGCPHYS32 addr)
693{
694 STAM_PROFILE_ADV_START(&pThis->CTXSUFF(StatTmdStore), a);
695 PPDMDEVINS pDevIns = PCNETSTATE_2_DEVINS(pThis);
696 if (pThis->fPrivIfEnabled)
697 {
698 /* RX/TX descriptors shared between host and guest => direct copy */
699 uint8_t *pv = (uint8_t*)pThis->CTX_SUFF(pSharedMMIO)
700 + (addr - pThis->GCTDRA)
701 + pThis->CTX_SUFF(pSharedMMIO)->V.V1.offTxDescriptors;
702 memcpy(pv, tmd, 16);
703 pv[7] &= ~0x80;
704 }
705 else if (RT_UNLIKELY(BCR_SWSTYLE(pThis) == 0))
706 {
707 uint16_t xda[4];
708 xda[0] = ((uint32_t *)tmd)[0] & 0xffff;
709 xda[1] = ((((uint32_t *)tmd)[0] >> 16) & 0xff) | ((((uint32_t *)tmd)[1]>>16) & 0xff00);
710 xda[2] = ((uint32_t *)tmd)[1] & 0xffff;
711 xda[3] = ((uint32_t *)tmd)[2] >> 16;
712 xda[1] |= 0x8000;
713 PDMDevHlpPhysWrite(pDevIns, addr, (void*)&xda[0], sizeof(xda));
714 xda[1] &= ~0x8000;
715 PDMDevHlpPhysWrite(pDevIns, addr+3, (uint8_t*)xda + 3, 1);
716 }
717 else if (RT_LIKELY(BCR_SWSTYLE(pThis) != 3))
718 {
719 ((uint32_t*)tmd)[1] |= 0x80000000;
720 PDMDevHlpPhysWrite(pDevIns, addr, (void*)tmd, 16);
721 ((uint32_t*)tmd)[1] &= ~0x80000000;
722 PDMDevHlpPhysWrite(pDevIns, addr+7, (uint8_t*)tmd + 7, 1);
723 }
724 else
725 {
726 uint32_t xda[4];
727 xda[0] = ((uint32_t *)tmd)[2];
728 xda[1] = ((uint32_t *)tmd)[1];
729 xda[2] = ((uint32_t *)tmd)[0];
730 xda[3] = ((uint32_t *)tmd)[3];
731 xda[1] |= 0x80000000;
732 PDMDevHlpPhysWrite(pDevIns, addr, (void*)&xda[0], sizeof(xda));
733 xda[1] &= ~0x80000000;
734 PDMDevHlpPhysWrite(pDevIns, addr+7, (uint8_t*)xda + 7, 1);
735 }
736 STAM_PROFILE_ADV_STOP(&pThis->CTXSUFF(StatTmdStore), a);
737}
738
739/**
740 * Load receive message descriptor
741 * Make sure we read the own flag first.
742 *
743 * @param pThis adapter private data
744 * @param addr physical address of the descriptor
745 * @param fRetIfNotOwn return immediately after reading the own flag if we don't own the descriptor
746 * @return true if we own the descriptor, false otherwise
747 */
748DECLINLINE(int) pcnetRmdLoad(PCNetState *pThis, RMD *rmd, RTGCPHYS32 addr, bool fRetIfNotOwn)
749{
750 PPDMDEVINS pDevIns = PCNETSTATE_2_DEVINS(pThis);
751 uint8_t ownbyte;
752
753 if (pThis->fPrivIfEnabled)
754 {
755 /* RX/TX descriptors shared between host and guest => direct copy */
756 uint8_t *pb = (uint8_t*)pThis->CTX_SUFF(pSharedMMIO)
757 + (addr - pThis->GCRDRA)
758 + pThis->CTX_SUFF(pSharedMMIO)->V.V1.offRxDescriptors;
759 if (!(pb[7] & 0x80) && fRetIfNotOwn)
760 return false;
761 memcpy(rmd, pb, 16);
762 return true;
763 }
764 else if (RT_UNLIKELY(BCR_SWSTYLE(pThis) == 0))
765 {
766 uint16_t rda[4];
767 PDMDevHlpPhysRead(pDevIns, addr+3, &ownbyte, 1);
768 if (!(ownbyte & 0x80) && fRetIfNotOwn)
769 return false;
770 PDMDevHlpPhysRead(pDevIns, addr, (void*)&rda[0], sizeof(rda));
771 ((uint32_t *)rmd)[0] = (uint32_t)rda[0] | ((rda[1] & 0x00ff) << 16);
772 ((uint32_t *)rmd)[1] = (uint32_t)rda[2] | ((rda[1] & 0xff00) << 16);
773 ((uint32_t *)rmd)[2] = (uint32_t)rda[3];
774 ((uint32_t *)rmd)[3] = 0;
775 }
776 else if (RT_LIKELY(BCR_SWSTYLE(pThis) != 3))
777 {
778 PDMDevHlpPhysRead(pDevIns, addr+7, &ownbyte, 1);
779 if (!(ownbyte & 0x80) && fRetIfNotOwn)
780 return false;
781 PDMDevHlpPhysRead(pDevIns, addr, (void*)rmd, 16);
782 }
783 else
784 {
785 uint32_t rda[4];
786 PDMDevHlpPhysRead(pDevIns, addr+7, &ownbyte, 1);
787 if (!(ownbyte & 0x80) && fRetIfNotOwn)
788 return false;
789 PDMDevHlpPhysRead(pDevIns, addr, (void*)&rda[0], sizeof(rda));
790 ((uint32_t *)rmd)[0] = rda[2];
791 ((uint32_t *)rmd)[1] = rda[1];
792 ((uint32_t *)rmd)[2] = rda[0];
793 ((uint32_t *)rmd)[3] = rda[3];
794 }
795 /* Double check the own bit; guest drivers might be buggy and lock prefixes in the recompiler are ignored by other threads. */
796#ifdef DEBUG
797 if (rmd->rmd1.own == 1 && !(ownbyte & 0x80))
798 Log(("pcnetRmdLoad: own bit flipped while reading!!\n"));
799#endif
800 if (!(ownbyte & 0x80))
801 rmd->rmd1.own = 0;
802
803 return !!rmd->rmd1.own;
804}
805
806
807/**
808 * Store receive message descriptor and hand it over to the host (the VM guest).
809 * Make sure that all data are transmitted before we clear the own flag.
810 */
811DECLINLINE(void) pcnetRmdStorePassHost(PCNetState *pThis, RMD *rmd, RTGCPHYS32 addr)
812{
813 PPDMDEVINS pDevIns = PCNETSTATE_2_DEVINS(pThis);
814 if (pThis->fPrivIfEnabled)
815 {
816 /* RX/TX descriptors shared between host and guest => direct copy */
817 uint8_t *pv = (uint8_t*)pThis->CTX_SUFF(pSharedMMIO)
818 + (addr - pThis->GCRDRA)
819 + pThis->CTX_SUFF(pSharedMMIO)->V.V1.offRxDescriptors;
820 memcpy(pv, rmd, 16);
821 pv[7] &= ~0x80;
822 }
823 else if (RT_UNLIKELY(BCR_SWSTYLE(pThis) == 0))
824 {
825 uint16_t rda[4];
826 rda[0] = ((uint32_t *)rmd)[0] & 0xffff;
827 rda[1] = ((((uint32_t *)rmd)[0]>>16) & 0xff) | ((((uint32_t *)rmd)[1]>>16) & 0xff00);
828 rda[2] = ((uint32_t *)rmd)[1] & 0xffff;
829 rda[3] = ((uint32_t *)rmd)[2] & 0xffff;
830 rda[1] |= 0x8000;
831 PDMDevHlpPhysWrite(pDevIns, addr, (void*)&rda[0], sizeof(rda));
832 rda[1] &= ~0x8000;
833 PDMDevHlpPhysWrite(pDevIns, addr+3, (uint8_t*)rda + 3, 1);
834 }
835 else if (RT_LIKELY(BCR_SWSTYLE(pThis) != 3))
836 {
837 ((uint32_t*)rmd)[1] |= 0x80000000;
838 PDMDevHlpPhysWrite(pDevIns, addr, (void*)rmd, 16);
839 ((uint32_t*)rmd)[1] &= ~0x80000000;
840 PDMDevHlpPhysWrite(pDevIns, addr+7, (uint8_t*)rmd + 7, 1);
841 }
842 else
843 {
844 uint32_t rda[4];
845 rda[0] = ((uint32_t *)rmd)[2];
846 rda[1] = ((uint32_t *)rmd)[1];
847 rda[2] = ((uint32_t *)rmd)[0];
848 rda[3] = ((uint32_t *)rmd)[3];
849 rda[1] |= 0x80000000;
850 PDMDevHlpPhysWrite(pDevIns, addr, (void*)&rda[0], sizeof(rda));
851 rda[1] &= ~0x80000000;
852 PDMDevHlpPhysWrite(pDevIns, addr+7, (uint8_t*)rda + 7, 1);
853 }
854}
855
856#ifdef IN_RING3
857/**
858 * Read+Write a TX/RX descriptor to prevent PDMDevHlpPhysWrite() allocating
859 * pages later when we shouldn't schedule to EMT. Temporarily hack.
860 */
861static void pcnetDescTouch(PCNetState *pThis, RTGCPHYS32 addr)
862{
863 PPDMDEVINS pDevIns = PCNETSTATE_2_DEVINS(pThis);
864
865 if (!pThis->fPrivIfEnabled)
866 {
867 uint8_t aBuf[16];
868 size_t cbDesc;
869 if (RT_UNLIKELY(BCR_SWSTYLE(pThis) == 0))
870 cbDesc = 8;
871 else
872 cbDesc = 16;
873 PDMDevHlpPhysRead(pDevIns, addr, aBuf, cbDesc);
874 PDMDevHlpPhysWrite(pDevIns, addr, aBuf, cbDesc);
875 }
876}
877#endif /* IN_RING3 */
878
879/** Checks if it's a bad (as in invalid) RMD.*/
880#define IS_RMD_BAD(rmd) ((rmd).rmd1.ones != 15 || (rmd).rmd2.zeros != 0)
881
882/** The network card is the owner of the RDTE/TDTE, actually it is this driver */
883#define CARD_IS_OWNER(desc) (((desc) & 0x8000))
884
885/** The host is the owner of the RDTE/TDTE -- actually the VM guest. */
886#define HOST_IS_OWNER(desc) (!((desc) & 0x8000))
887
888#ifndef ETHER_IS_MULTICAST /* Net/Open BSD macro it seems */
889#define ETHER_IS_MULTICAST(a) ((*(uint8_t *)(a)) & 1)
890#endif
891
892#define ETHER_ADDR_LEN ETH_ALEN
893#define ETH_ALEN 6
894#pragma pack(1)
895struct ether_header /** @todo Use RTNETETHERHDR */
896{
897 uint8_t ether_dhost[ETH_ALEN]; /**< destination ethernet address */
898 uint8_t ether_shost[ETH_ALEN]; /**< source ethernet address */
899 uint16_t ether_type; /**< packet type ID field */
900};
901#pragma pack()
902
903#define PRINT_PKTHDR(BUF) do { \
904 struct ether_header *hdr = (struct ether_header *)(BUF); \
905 Log(("#%d packet dhost=%02x:%02x:%02x:%02x:%02x:%02x, " \
906 "shost=%02x:%02x:%02x:%02x:%02x:%02x, " \
907 "type=%#06x (bcast=%d)\n", PCNET_INST_NR, \
908 hdr->ether_dhost[0],hdr->ether_dhost[1],hdr->ether_dhost[2], \
909 hdr->ether_dhost[3],hdr->ether_dhost[4],hdr->ether_dhost[5], \
910 hdr->ether_shost[0],hdr->ether_shost[1],hdr->ether_shost[2], \
911 hdr->ether_shost[3],hdr->ether_shost[4],hdr->ether_shost[5], \
912 htons(hdr->ether_type), \
913 !!ETHER_IS_MULTICAST(hdr->ether_dhost))); \
914} while (0)
915
916
917#ifdef IN_RING3
918/**
919 * Initialize the shared memory for the private guest interface.
920 *
921 * @note Changing this layout will break SSM for guests using the private guest interface!
922 */
923static void pcnetInitSharedMemory(PCNetState *pThis)
924{
925 /* Clear the entire block for pcnetReset usage. */
926 memset(pThis->pSharedMMIOR3, 0, PCNET_GUEST_SHARED_MEMORY_SIZE);
927
928 pThis->pSharedMMIOR3->u32Version = PCNET_GUEST_INTERFACE_VERSION;
929 uint32_t off = 2048; /* Leave some space for more fields within the header */
930
931 /*
932 * The Descriptor arrays.
933 */
934 pThis->pSharedMMIOR3->V.V1.offTxDescriptors = off;
935 off = RT_ALIGN(off + PCNET_GUEST_TX_DESCRIPTOR_SIZE * PCNET_GUEST_MAX_TX_DESCRIPTORS, 32);
936
937 pThis->pSharedMMIOR3->V.V1.offRxDescriptors = off;
938 off = RT_ALIGN(off + PCNET_GUEST_RX_DESCRIPTOR_SIZE * PCNET_GUEST_MAX_RX_DESCRIPTORS, 32);
939
940 /* Make sure all the descriptors are mapped into HMA space (and later ring-0). The 8192
941 bytes limit is hardcoded in the PDMDevHlpMMHyperMapMMIO2 call down in pcnetConstruct. */
942 AssertRelease(off <= 8192);
943
944 /*
945 * The buffer arrays.
946 */
947#if 0
948 /* Don't allocate TX buffers since Windows guests cannot use it */
949 pThis->pSharedMMIOR3->V.V1.offTxBuffers = off;
950 off = RT_ALIGN(off + PCNET_GUEST_NIC_BUFFER_SIZE * PCNET_GUEST_MAX_TX_DESCRIPTORS, 32);
951#endif
952
953 pThis->pSharedMMIOR3->V.V1.offRxBuffers = off;
954 pThis->pSharedMMIOR3->fFlags = PCNET_GUEST_FLAGS_ADMIT_HOST;
955 off = RT_ALIGN(off + PCNET_GUEST_NIC_BUFFER_SIZE * PCNET_GUEST_MAX_RX_DESCRIPTORS, 32);
956 AssertRelease(off <= PCNET_GUEST_SHARED_MEMORY_SIZE);
957
958 /* Update the header with the final size. */
959 pThis->pSharedMMIOR3->cbUsed = off;
960}
961#endif /* IN_RING3 */
962
963#define MULTICAST_FILTER_LEN 8
964
965DECLINLINE(uint32_t) lnc_mchash(const uint8_t *ether_addr)
966{
967#define LNC_POLYNOMIAL 0xEDB88320UL
968 uint32_t crc = 0xFFFFFFFF;
969 int idx, bit;
970 uint8_t data;
971
972 for (idx = 0; idx < ETHER_ADDR_LEN; idx++)
973 {
974 for (data = *ether_addr++, bit = 0; bit < MULTICAST_FILTER_LEN; bit++)
975 {
976 crc = (crc >> 1) ^ (((crc ^ data) & 1) ? LNC_POLYNOMIAL : 0);
977 data >>= 1;
978 }
979 }
980 return crc;
981#undef LNC_POLYNOMIAL
982}
983
984#define CRC(crc, ch) (crc = (crc >> 8) ^ crctab[(crc ^ (ch)) & 0xff])
985
986/* generated using the AUTODIN II polynomial
987 * x^32 + x^26 + x^23 + x^22 + x^16 +
988 * x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x^1 + 1
989 */
990static const uint32_t crctab[256] =
991{
992 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
993 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
994 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
995 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
996 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
997 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
998 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
999 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
1000 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
1001 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
1002 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
1003 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
1004 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
1005 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
1006 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
1007 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
1008 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
1009 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
1010 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
1011 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
1012 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
1013 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
1014 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
1015 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
1016 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
1017 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
1018 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
1019 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
1020 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
1021 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
1022 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
1023 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
1024 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
1025 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
1026 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
1027 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
1028 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
1029 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
1030 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
1031 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
1032 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
1033 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
1034 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
1035 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
1036 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
1037 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
1038 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
1039 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
1040 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
1041 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
1042 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
1043 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
1044 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
1045 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
1046 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
1047 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
1048 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
1049 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
1050 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
1051 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
1052 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
1053 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
1054 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
1055 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
1056};
1057
1058DECLINLINE(int) padr_match(PCNetState *pThis, const uint8_t *buf, size_t size)
1059{
1060 struct ether_header *hdr = (struct ether_header *)buf;
1061 int result;
1062#if (defined(RT_ARCH_X86) || defined(RT_ARCH_AMD64)) && !defined(PCNET_DEBUG_MATCH)
1063 result = !CSR_DRCVPA(pThis) && !memcmp(hdr->ether_dhost, pThis->aCSR + 12, 6);
1064#else
1065 uint8_t padr[6];
1066 padr[0] = pThis->aCSR[12] & 0xff;
1067 padr[1] = pThis->aCSR[12] >> 8;
1068 padr[2] = pThis->aCSR[13] & 0xff;
1069 padr[3] = pThis->aCSR[13] >> 8;
1070 padr[4] = pThis->aCSR[14] & 0xff;
1071 padr[5] = pThis->aCSR[14] >> 8;
1072 result = !CSR_DRCVPA(pThis) && !memcmp(hdr->ether_dhost, padr, 6);
1073#endif
1074
1075#ifdef PCNET_DEBUG_MATCH
1076 Log(("#%d packet dhost=%02x:%02x:%02x:%02x:%02x:%02x, "
1077 "padr=%02x:%02x:%02x:%02x:%02x:%02x => %d\n", PCNET_INST_NR,
1078 hdr->ether_dhost[0],hdr->ether_dhost[1],hdr->ether_dhost[2],
1079 hdr->ether_dhost[3],hdr->ether_dhost[4],hdr->ether_dhost[5],
1080 padr[0],padr[1],padr[2],padr[3],padr[4],padr[5], result));
1081#endif
1082 return result;
1083}
1084
1085DECLINLINE(int) padr_bcast(PCNetState *pThis, const uint8_t *buf, size_t size)
1086{
1087 static uint8_t aBCAST[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1088 struct ether_header *hdr = (struct ether_header *)buf;
1089 int result = !CSR_DRCVBC(pThis) && !memcmp(hdr->ether_dhost, aBCAST, 6);
1090#ifdef PCNET_DEBUG_MATCH
1091 Log(("#%d padr_bcast result=%d\n", PCNET_INST_NR, result));
1092#endif
1093 return result;
1094}
1095
1096static int ladr_match(PCNetState *pThis, const uint8_t *buf, size_t size)
1097{
1098 struct ether_header *hdr = (struct ether_header *)buf;
1099 if (RT_UNLIKELY(hdr->ether_dhost[0] & 0x01) && ((uint64_t *)&pThis->aCSR[8])[0] != 0LL)
1100 {
1101 int index;
1102#if defined(RT_ARCH_X86) || defined(RT_ARCH_AMD64)
1103 index = lnc_mchash(hdr->ether_dhost) >> 26;
1104 return ((uint8_t*)(pThis->aCSR + 8))[index >> 3] & (1 << (index & 7));
1105#else
1106 uint8_t ladr[8];
1107 ladr[0] = pThis->aCSR[8] & 0xff;
1108 ladr[1] = pThis->aCSR[8] >> 8;
1109 ladr[2] = pThis->aCSR[9] & 0xff;
1110 ladr[3] = pThis->aCSR[9] >> 8;
1111 ladr[4] = pThis->aCSR[10] & 0xff;
1112 ladr[5] = pThis->aCSR[10] >> 8;
1113 ladr[6] = pThis->aCSR[11] & 0xff;
1114 ladr[7] = pThis->aCSR[11] >> 8;
1115 index = lnc_mchash(hdr->ether_dhost) >> 26;
1116 return (ladr[index >> 3] & (1 << (index & 7)));
1117#endif
1118 }
1119 return 0;
1120}
1121
1122
1123/**
1124 * Get the receive descriptor ring address with a given index.
1125 */
1126DECLINLINE(RTGCPHYS32) pcnetRdraAddr(PCNetState *pThis, int idx)
1127{
1128 return pThis->GCRDRA + ((CSR_RCVRL(pThis) - idx) << pThis->iLog2DescSize);
1129}
1130
1131/**
1132 * Get the transmit descriptor ring address with a given index.
1133 */
1134DECLINLINE(RTGCPHYS32) pcnetTdraAddr(PCNetState *pThis, int idx)
1135{
1136 return pThis->GCTDRA + ((CSR_XMTRL(pThis) - idx) << pThis->iLog2DescSize);
1137}
1138
1139RT_C_DECLS_BEGIN
1140PDMBOTHCBDECL(int) pcnetIOPortRead(PPDMDEVINS pDevIns, void *pvUser,
1141 RTIOPORT Port, uint32_t *pu32, unsigned cb);
1142PDMBOTHCBDECL(int) pcnetIOPortWrite(PPDMDEVINS pDevIns, void *pvUser,
1143 RTIOPORT Port, uint32_t u32, unsigned cb);
1144PDMBOTHCBDECL(int) pcnetIOPortAPromWrite(PPDMDEVINS pDevIns, void *pvUser,
1145 RTIOPORT Port, uint32_t u32, unsigned cb);
1146PDMBOTHCBDECL(int) pcnetIOPortAPromRead(PPDMDEVINS pDevIns, void *pvUser,
1147 RTIOPORT Port, uint32_t *pu32, unsigned cb);
1148PDMBOTHCBDECL(int) pcnetMMIORead(PPDMDEVINS pDevIns, void *pvUser,
1149 RTGCPHYS GCPhysAddr, void *pv, unsigned cb);
1150PDMBOTHCBDECL(int) pcnetMMIOWrite(PPDMDEVINS pDevIns, void *pvUser,
1151 RTGCPHYS GCPhysAddr, void *pv, unsigned cb);
1152#ifndef IN_RING3
1153DECLEXPORT(int) pcnetHandleRingWrite(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame,
1154 RTGCPTR pvFault, RTGCPHYS GCPhysFault, void *pvUser);
1155#endif
1156RT_C_DECLS_END
1157
1158#undef htonl
1159#define htonl(x) ASMByteSwapU32(x)
1160#undef htons
1161#define htons(x) ( (((x) & 0xff00) >> 8) | (((x) & 0x00ff) << 8) )
1162
1163static void pcnetPollRxTx(PCNetState *pThis);
1164static void pcnetPollTimer(PCNetState *pThis);
1165static void pcnetUpdateIrq(PCNetState *pThis);
1166static uint32_t pcnetBCRReadU16(PCNetState *pThis, uint32_t u32RAP);
1167static int pcnetBCRWriteU16(PCNetState *pThis, uint32_t u32RAP, uint32_t val);
1168
1169
1170#ifdef PCNET_NO_POLLING
1171# ifndef IN_RING3
1172
1173/**
1174 * #PF Virtual Handler callback for Guest write access to the ring descriptor page(pThis)
1175 *
1176 * @return VBox status code (appropriate for trap handling and GC return).
1177 * @param pVM VM Handle.
1178 * @param uErrorCode CPU Error code.
1179 * @param pRegFrame Trap register frame.
1180 * @param pvFault The fault address (cr2).
1181 * @param GCPhysFault The GC physical address corresponding to pvFault.
1182 * @param pvUser User argument.
1183 */
1184DECLEXPORT(int) pcnetHandleRingWrite(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame,
1185 RTGCPTR pvFault, RTGCPHYS GCPhysFault, void *pvUser)
1186{
1187 PCNetState *pThis = (PCNetState *)pvUser;
1188
1189 Log(("#%d pcnetHandleRingWriteGC: write to %#010x\n", PCNET_INST_NR, GCPhysFault));
1190
1191 uint32_t cb;
1192 int rc = CTXALLSUFF(pThis->pfnEMInterpretInstruction)(pVM, pRegFrame, pvFault, &cb);
1193 if (RT_SUCCESS(rc) && cb)
1194 {
1195 if ( (GCPhysFault >= pThis->GCTDRA && GCPhysFault + cb < pcnetTdraAddr(pThis, 0))
1196#ifdef PCNET_MONITOR_RECEIVE_RING
1197 || (GCPhysFault >= pThis->GCRDRA && GCPhysFault + cb < pcnetRdraAddr(pThis, 0))
1198#endif
1199 )
1200 {
1201 uint32_t offsetTDRA = (GCPhysFault - pThis->GCTDRA);
1202
1203 int rc = PDMCritSectEnter(&pThis->CritSect, VERR_SEM_BUSY);
1204 if (RT_SUCCESS(rc))
1205 {
1206 STAM_COUNTER_INC(&CTXALLSUFF(pThis->StatRingWrite)); ;
1207
1208 /* Check if we can do something now */
1209 pcnetPollRxTx(pThis);
1210 pcnetUpdateIrq(pThis);
1211
1212 PDMCritSectLeave(&pThis->CritSect);
1213 return VINF_SUCCESS;
1214 }
1215 }
1216 else
1217 {
1218 STAM_COUNTER_INC(&CTXALLSUFF(pThis->StatRingWriteOutside)); ;
1219 return VINF_SUCCESS; /* outside of the ring range */
1220 }
1221 }
1222 STAM_COUNTER_INC(&CTXALLSUFF(pThis->StatRingWriteFailed)); ;
1223 return VINF_IOM_HC_MMIO_WRITE; /* handle in ring3 */
1224}
1225
1226# else /* IN_RING3 */
1227
1228/**
1229 * #PF Handler callback for physical access handler ranges (MMIO among others) in HC.
1230 *
1231 * The handler can not raise any faults, it's mainly for monitoring write access
1232 * to certain pages.
1233 *
1234 * @returns VINF_SUCCESS if the handler have carried out the operation.
1235 * @returns VINF_PGM_HANDLER_DO_DEFAULT if the caller should carry out the access operation.
1236 * @param pVM VM Handle.
1237 * @param GCPhys The physical address the guest is writing to.
1238 * @param pvPhys The HC mapping of that address.
1239 * @param pvBuf What the guest is reading/writing.
1240 * @param cbBuf How much it's reading/writing.
1241 * @param enmAccessType The access type.
1242 * @param pvUser User argument.
1243 */
1244static DECLCALLBACK(int) pcnetHandleRingWrite(PVM pVM, RTGCPHYS GCPhys, void *pvPhys, void *pvBuf,
1245 size_t cbBuf, PGMACCESSTYPE enmAccessType, void *pvUser)
1246{
1247 PPDMDEVINS pDevIns = (PPDMDEVINS)pvUser;
1248 PCNetState *pThis = PDMINS_2_DATA(pDevIns, PCNetState *);
1249
1250 Log(("#%d pcnetHandleRingWrite: write to %#010x\n", PCNET_INST_NR, GCPhys));
1251#ifdef VBOX_WITH_STATISTICS
1252 STAM_COUNTER_INC(&CTXSUFF(pThis->StatRingWrite));
1253 if (GCPhys >= pThis->GCRDRA && GCPhys < pcnetRdraAddr(pThis, 0))
1254 STAM_COUNTER_INC(&pThis->StatRCVRingWrite);
1255 else if (GCPhys >= pThis->GCTDRA && GCPhys < pcnetTdraAddr(pThis, 0))
1256 STAM_COUNTER_INC(&pThis->StatTXRingWrite);
1257#endif
1258 /* Perform the actual write */
1259 memcpy((char *)pvPhys, pvBuf, cbBuf);
1260
1261 /* Writes done by our code don't require polling of course */
1262 if (PDMCritSectIsOwner(&pThis->CritSect) == false)
1263 {
1264 if ( (GCPhys >= pThis->GCTDRA && GCPhys + cbBuf < pcnetTdraAddr(pThis, 0))
1265#ifdef PCNET_MONITOR_RECEIVE_RING
1266 || (GCPhys >= pThis->GCRDRA && GCPhys + cbBuf < pcnetRdraAddr(pThis, 0))
1267#endif
1268 )
1269 {
1270 int rc = PDMCritSectEnter(&pThis->CritSect, VERR_SEM_BUSY);
1271 AssertReleaseRC(rc);
1272 /* Check if we can do something now */
1273 pcnetPollRxTx(pThis);
1274 pcnetUpdateIrq(pThis);
1275 PDMCritSectLeave(&pThis->CritSect);
1276 }
1277 }
1278 return VINF_SUCCESS;
1279}
1280# endif /* !IN_RING3 */
1281#endif /* PCNET_NO_POLLING */
1282
1283static void pcnetSoftReset(PCNetState *pThis)
1284{
1285 Log(("#%d pcnetSoftReset:\n", PCNET_INST_NR));
1286
1287 pThis->u32Lnkst = 0x40;
1288 pThis->GCRDRA = 0;
1289 pThis->GCTDRA = 0;
1290 pThis->u32RAP = 0;
1291
1292 pThis->aCSR[0] = 0x0004;
1293 pThis->aCSR[3] = 0x0000;
1294 pThis->aCSR[4] = 0x0115;
1295 pThis->aCSR[5] = 0x0000;
1296 pThis->aCSR[6] = 0x0000;
1297 pThis->aCSR[8] = 0;
1298 pThis->aCSR[9] = 0;
1299 pThis->aCSR[10] = 0;
1300 pThis->aCSR[11] = 0;
1301 pThis->aCSR[12] = RT_LE2H_U16(((uint16_t *)&pThis->aPROM[0])[0]);
1302 pThis->aCSR[13] = RT_LE2H_U16(((uint16_t *)&pThis->aPROM[0])[1]);
1303 pThis->aCSR[14] = RT_LE2H_U16(((uint16_t *)&pThis->aPROM[0])[2]);
1304 pThis->aCSR[15] &= 0x21c4;
1305 CSR_RCVRC(pThis) = 1;
1306 CSR_XMTRC(pThis) = 1;
1307 CSR_RCVRL(pThis) = 1;
1308 CSR_XMTRL(pThis) = 1;
1309 pThis->aCSR[80] = 0x1410;
1310 pThis->aCSR[88] = pThis->fAm79C973 ? CSR_VERSION_LOW_79C973 : CSR_VERSION_LOW_79C970A;
1311 pThis->aCSR[89] = CSR_VERSION_HIGH;
1312 pThis->aCSR[94] = 0x0000;
1313 pThis->aCSR[100] = 0x0200;
1314 pThis->aCSR[103] = 0x0105;
1315 pThis->aCSR[103] = 0x0105;
1316 CSR_MISSC(pThis) = 0;
1317 pThis->aCSR[114] = 0x0000;
1318 pThis->aCSR[122] = 0x0000;
1319 pThis->aCSR[124] = 0x0000;
1320}
1321
1322/**
1323 * Check if we have to send an interrupt to the guest. An interrupt can occur on
1324 * - csr0 (written quite often)
1325 * - csr4 (only written by pcnetSoftReset(), pcnetStop() or by the guest driver)
1326 * - csr5 (only written by pcnetSoftReset(), pcnetStop or by the driver guest)
1327 */
1328static void pcnetUpdateIrq(PCNetState *pThis)
1329{
1330 register int iISR = 0;
1331 register uint16_t csr0 = pThis->aCSR[0];
1332
1333 csr0 &= ~0x0080; /* clear INTR */
1334
1335 STAM_PROFILE_ADV_START(&pThis->StatInterrupt, a);
1336
1337 /* Linux guests set csr4=0x0915
1338 * W2k guests set csr3=0x4940 (disable BABL, MERR, IDON, DXSUFLO */
1339
1340#if 1
1341 if ( ( (csr0 & ~pThis->aCSR[3]) & 0x5f00)
1342 || (((pThis->aCSR[4]>>1) & ~pThis->aCSR[4]) & 0x0115)
1343 || (((pThis->aCSR[5]>>1) & pThis->aCSR[5]) & 0x0048))
1344#else
1345 if ( ( !(pThis->aCSR[3] & 0x4000) && !!(csr0 & 0x4000)) /* BABL */
1346 ||( !(pThis->aCSR[3] & 0x1000) && !!(csr0 & 0x1000)) /* MISS */
1347 ||( !(pThis->aCSR[3] & 0x0100) && !!(csr0 & 0x0100)) /* IDON */
1348 ||( !(pThis->aCSR[3] & 0x0200) && !!(csr0 & 0x0200)) /* TINT */
1349 ||( !(pThis->aCSR[3] & 0x0400) && !!(csr0 & 0x0400)) /* RINT */
1350 ||( !(pThis->aCSR[3] & 0x0800) && !!(csr0 & 0x0800)) /* MERR */
1351 ||( !(pThis->aCSR[4] & 0x0001) && !!(pThis->aCSR[4] & 0x0002)) /* JAB */
1352 ||( !(pThis->aCSR[4] & 0x0004) && !!(pThis->aCSR[4] & 0x0008)) /* TXSTRT */
1353 ||( !(pThis->aCSR[4] & 0x0010) && !!(pThis->aCSR[4] & 0x0020)) /* RCVO */
1354 ||( !(pThis->aCSR[4] & 0x0100) && !!(pThis->aCSR[4] & 0x0200)) /* MFCO */
1355 ||(!!(pThis->aCSR[5] & 0x0040) && !!(pThis->aCSR[5] & 0x0080)) /* EXDINT */
1356 ||(!!(pThis->aCSR[5] & 0x0008) && !!(pThis->aCSR[5] & 0x0010)) /* MPINT */)
1357#endif
1358 {
1359 iISR = !!(csr0 & 0x0040); /* CSR_INEA */
1360 csr0 |= 0x0080; /* set INTR */
1361 }
1362
1363#ifdef VBOX
1364 if (pThis->aCSR[4] & 0x0080) /* UINTCMD */
1365 {
1366 pThis->aCSR[4] &= ~0x0080; /* clear UINTCMD */
1367 pThis->aCSR[4] |= 0x0040; /* set UINT */
1368 Log(("#%d user int\n", PCNET_INST_NR));
1369 }
1370 if (pThis->aCSR[4] & csr0 & 0x0040 /* CSR_INEA */)
1371 {
1372 csr0 |= 0x0080; /* set INTR */
1373 iISR = 1;
1374 }
1375#else /* !VBOX */
1376 if (!!(pThis->aCSR[4] & 0x0080) && CSR_INEA(pThis)) /* UINTCMD */
1377 {
1378 pThis->aCSR[4] &= ~0x0080;
1379 pThis->aCSR[4] |= 0x0040; /* set UINT */
1380 csr0 |= 0x0080; /* set INTR */
1381 iISR = 1;
1382 Log(("#%d user int\n", PCNET_INST_NR));
1383 }
1384#endif /* !VBOX */
1385
1386#if 1
1387 if (((pThis->aCSR[5]>>1) & pThis->aCSR[5]) & 0x0500)
1388#else
1389 if ( (!!(pThis->aCSR[5] & 0x0400) && !!(pThis->aCSR[5] & 0x0800)) /* SINT */
1390 ||(!!(pThis->aCSR[5] & 0x0100) && !!(pThis->aCSR[5] & 0x0200)) /* SLPINT */)
1391#endif
1392 {
1393 iISR = 1;
1394 csr0 |= 0x0080; /* INTR */
1395 }
1396
1397 if ((pThis->aCSR[7] & 0x0C00) == 0x0C00) /* STINT + STINTE */
1398 iISR = 1;
1399
1400 pThis->aCSR[0] = csr0;
1401
1402 Log2(("#%d set irq iISR=%d\n", PCNET_INST_NR, iISR));
1403
1404 /* normal path is to _not_ change the IRQ status */
1405 if (RT_UNLIKELY(iISR != pThis->iISR))
1406 {
1407 Log(("#%d INTA=%d\n", PCNET_INST_NR, iISR));
1408 PDMDevHlpPCISetIrqNoWait(PCNETSTATE_2_DEVINS(pThis), 0, iISR);
1409 pThis->iISR = iISR;
1410 }
1411 STAM_PROFILE_ADV_STOP(&pThis->StatInterrupt, a);
1412}
1413
1414/**
1415 * Enable/disable the private guest interface.
1416 */
1417static void pcnetEnablePrivateIf(PCNetState *pThis)
1418{
1419 bool fPrivIfEnabled = pThis->pSharedMMIOR3
1420 && !!(pThis->CTX_SUFF(pSharedMMIO)->fFlags & PCNET_GUEST_FLAGS_ADMIT_GUEST);
1421 if (fPrivIfEnabled != pThis->fPrivIfEnabled)
1422 {
1423 pThis->fPrivIfEnabled = fPrivIfEnabled;
1424 LogRel(("PCNet#%d: %s private interface\n", PCNET_INST_NR, fPrivIfEnabled ? "Enabling" : "Disabling"));
1425 }
1426}
1427
1428#ifdef IN_RING3
1429#ifdef PCNET_NO_POLLING
1430static void pcnetUpdateRingHandlers(PCNetState *pThis)
1431{
1432 PPDMDEVINS pDevIns = PCNETSTATE_2_DEVINS(pThis);
1433 int rc;
1434
1435 Log(("pcnetUpdateRingHandlers TD %RX32 size %#x -> %RX32 ?size? %#x\n", pThis->TDRAPhysOld, pThis->cbTDRAOld, pThis->GCTDRA, pcnetTdraAddr(pThis, 0)));
1436 Log(("pcnetUpdateRingHandlers RX %RX32 size %#x -> %RX32 ?size? %#x\n", pThis->RDRAPhysOld, pThis->cbRDRAOld, pThis->GCRDRA, pcnetRdraAddr(pThis, 0)));
1437
1438 /** @todo unregister order not correct! */
1439
1440#ifdef PCNET_MONITOR_RECEIVE_RING
1441 if (pThis->GCRDRA != pThis->RDRAPhysOld || CSR_RCVRL(pThis) != pThis->cbRDRAOld)
1442 {
1443 if (pThis->RDRAPhysOld != 0)
1444 PGMHandlerPhysicalDeregister(PDMDevHlpGetVM(pDevIns),
1445 pThis->RDRAPhysOld & ~PAGE_OFFSET_MASK);
1446
1447 rc = PGMR3HandlerPhysicalRegister(PDMDevHlpGetVM(pDevIns),
1448 PGMPHYSHANDLERTYPE_PHYSICAL_WRITE,
1449 pThis->GCRDRA & ~PAGE_OFFSET_MASK,
1450 RT_ALIGN(pcnetRdraAddr(pThis, 0), PAGE_SIZE) - 1,
1451 pcnetHandleRingWrite, pDevIns,
1452 g_DevicePCNet.szR0Mod, "pcnetHandleRingWrite",
1453 pThis->pDevInsHC->pvInstanceDataHC,
1454 g_DevicePCNet.szRCMod, "pcnetHandleRingWrite",
1455 pThis->pDevInsHC->pvInstanceDataRC,
1456 "PCNet receive ring write access handler");
1457 AssertRC(rc);
1458
1459 pThis->RDRAPhysOld = pThis->GCRDRA;
1460 pThis->cbRDRAOld = pcnetRdraAddr(pThis, 0);
1461 }
1462#endif /* PCNET_MONITOR_RECEIVE_RING */
1463
1464#ifdef PCNET_MONITOR_RECEIVE_RING
1465 /* 3 possibilities:
1466 * 1) TDRA on different physical page as RDRA
1467 * 2) TDRA completely on same physical page as RDRA
1468 * 3) TDRA & RDRA overlap partly with different physical pages
1469 */
1470 RTGCPHYS32 RDRAPageStart = pThis->GCRDRA & ~PAGE_OFFSET_MASK;
1471 RTGCPHYS32 RDRAPageEnd = (pcnetRdraAddr(pThis, 0) - 1) & ~PAGE_OFFSET_MASK;
1472 RTGCPHYS32 TDRAPageStart = pThis->GCTDRA & ~PAGE_OFFSET_MASK;
1473 RTGCPHYS32 TDRAPageEnd = (pcnetTdraAddr(pThis, 0) - 1) & ~PAGE_OFFSET_MASK;
1474
1475 if ( RDRAPageStart > TDRAPageEnd
1476 || TDRAPageStart > RDRAPageEnd)
1477 {
1478#endif /* PCNET_MONITOR_RECEIVE_RING */
1479 /* 1) */
1480 if (pThis->GCTDRA != pThis->TDRAPhysOld || CSR_XMTRL(pThis) != pThis->cbTDRAOld)
1481 {
1482 if (pThis->TDRAPhysOld != 0)
1483 PGMHandlerPhysicalDeregister(PDMDevHlpGetVM(pDevIns),
1484 pThis->TDRAPhysOld & ~PAGE_OFFSET_MASK);
1485
1486 rc = PGMR3HandlerPhysicalRegister(PDMDevHlpGetVM(pDevIns),
1487 PGMPHYSHANDLERTYPE_PHYSICAL_WRITE,
1488 pThis->GCTDRA & ~PAGE_OFFSET_MASK,
1489 RT_ALIGN(pcnetTdraAddr(pThis, 0), PAGE_SIZE) - 1,
1490 pcnetHandleRingWrite, pDevIns,
1491 g_DevicePCNet.szR0Mod, "pcnetHandleRingWrite",
1492 pThis->pDevInsHC->pvInstanceDataHC,
1493 g_DevicePCNet.szRCMod, "pcnetHandleRingWrite",
1494 pThis->pDevInsHC->pvInstanceDataRC,
1495 "PCNet transmit ring write access handler");
1496 AssertRC(rc);
1497
1498 pThis->TDRAPhysOld = pThis->GCTDRA;
1499 pThis->cbTDRAOld = pcnetTdraAddr(pThis, 0);
1500 }
1501#ifdef PCNET_MONITOR_RECEIVE_RING
1502 }
1503 else
1504 if ( RDRAPageStart != TDRAPageStart
1505 && ( TDRAPageStart == RDRAPageEnd
1506 || TDRAPageEnd == RDRAPageStart
1507 )
1508 )
1509 {
1510 /* 3) */
1511 AssertFailed();
1512 }
1513 /* else 2) */
1514#endif
1515}
1516#endif /* PCNET_NO_POLLING */
1517
1518static void pcnetInit(PCNetState *pThis)
1519{
1520 PPDMDEVINS pDevIns = PCNETSTATE_2_DEVINS(pThis);
1521 Log(("#%d pcnetInit: init_addr=%#010x\n", PCNET_INST_NR, PHYSADDR(pThis, CSR_IADR(pThis))));
1522
1523 /** @todo Documentation says that RCVRL and XMTRL are stored as two's complement!
1524 * Software is allowed to write these registers directly. */
1525#define PCNET_INIT() do { \
1526 PDMDevHlpPhysRead(pDevIns, PHYSADDR(pThis, CSR_IADR(pThis)), \
1527 (uint8_t *)&initblk, sizeof(initblk)); \
1528 pThis->aCSR[15] = RT_LE2H_U16(initblk.mode); \
1529 CSR_RCVRL(pThis) = (initblk.rlen < 9) ? (1 << initblk.rlen) : 512; \
1530 CSR_XMTRL(pThis) = (initblk.tlen < 9) ? (1 << initblk.tlen) : 512; \
1531 pThis->aCSR[ 6] = (initblk.tlen << 12) | (initblk.rlen << 8); \
1532 pThis->aCSR[ 8] = RT_LE2H_U16(initblk.ladrf1); \
1533 pThis->aCSR[ 9] = RT_LE2H_U16(initblk.ladrf2); \
1534 pThis->aCSR[10] = RT_LE2H_U16(initblk.ladrf3); \
1535 pThis->aCSR[11] = RT_LE2H_U16(initblk.ladrf4); \
1536 pThis->aCSR[12] = RT_LE2H_U16(initblk.padr1); \
1537 pThis->aCSR[13] = RT_LE2H_U16(initblk.padr2); \
1538 pThis->aCSR[14] = RT_LE2H_U16(initblk.padr3); \
1539 pThis->GCRDRA = PHYSADDR(pThis, initblk.rdra); \
1540 pThis->GCTDRA = PHYSADDR(pThis, initblk.tdra); \
1541} while (0)
1542
1543 pcnetEnablePrivateIf(pThis);
1544
1545 if (BCR_SSIZE32(pThis))
1546 {
1547 struct INITBLK32 initblk;
1548 pThis->GCUpperPhys = 0;
1549 PCNET_INIT();
1550 Log(("#%d initblk.rlen=%#04x, initblk.tlen=%#04x\n",
1551 PCNET_INST_NR, initblk.rlen, initblk.tlen));
1552 }
1553 else
1554 {
1555 struct INITBLK16 initblk;
1556 pThis->GCUpperPhys = (0xff00 & (uint32_t)pThis->aCSR[2]) << 16;
1557 PCNET_INIT();
1558 Log(("#%d initblk.rlen=%#04x, initblk.tlen=%#04x\n",
1559 PCNET_INST_NR, initblk.rlen, initblk.tlen));
1560 }
1561
1562#undef PCNET_INIT
1563
1564 size_t cbRxBuffers = 0;
1565 for (int i = CSR_RCVRL(pThis); i >= 1; i--)
1566 {
1567 RMD rmd;
1568 RTGCPHYS32 rdaddr = PHYSADDR(pThis, pcnetRdraAddr(pThis, i));
1569
1570 pcnetDescTouch(pThis, rdaddr);
1571 /* At this time it is not guaranteed that the buffers are already initialized. */
1572 if (pcnetRmdLoad(pThis, &rmd, rdaddr, false))
1573 {
1574 uint32_t cbBuf = 4096U-rmd.rmd1.bcnt;
1575 cbRxBuffers += cbBuf;
1576 }
1577 }
1578
1579 for (int i = CSR_XMTRL(pThis); i >= 1; i--)
1580 {
1581 RTGCPHYS32 tdaddr = PHYSADDR(pThis, pcnetTdraAddr(pThis, i));
1582
1583 pcnetDescTouch(pThis, tdaddr);
1584 }
1585
1586 /*
1587 * Heuristics: The Solaris pcn driver allocates too few RX buffers (128 buffers of a
1588 * size of 128 bytes are 16KB in summary) leading to frequent RX buffer overflows. In
1589 * that case we don't signal RX overflows through the CSR0_MISS flag as the driver
1590 * re-initializes the device on every miss. Other guests use at least 32 buffers of
1591 * usually 1536 bytes and should therefore not run into condition. If they are still
1592 * short in RX buffers we notify this condition.
1593 */
1594 pThis->fSignalRxMiss = (cbRxBuffers == 0 || cbRxBuffers >= 32*_1K);
1595
1596 if (pThis->pDrvR3)
1597 pThis->pDrvR3->pfnSetPromiscuousMode(pThis->pDrvR3, CSR_PROM(pThis));
1598
1599 CSR_RCVRC(pThis) = CSR_RCVRL(pThis);
1600 CSR_XMTRC(pThis) = CSR_XMTRL(pThis);
1601
1602#ifdef PCNET_NO_POLLING
1603 pcnetUpdateRingHandlers(pThis);
1604#endif
1605
1606 /* Reset cached RX and TX states */
1607 CSR_CRST(pThis) = CSR_CRBC(pThis) = CSR_NRST(pThis) = CSR_NRBC(pThis) = 0;
1608 CSR_CXST(pThis) = CSR_CXBC(pThis) = CSR_NXST(pThis) = CSR_NXBC(pThis) = 0;
1609
1610 LogRel(("PCNet#%d: Init: ss32=%d GCRDRA=%#010x[%d] GCTDRA=%#010x[%d]%s\n",
1611 PCNET_INST_NR, BCR_SSIZE32(pThis),
1612 pThis->GCRDRA, CSR_RCVRL(pThis), pThis->GCTDRA, CSR_XMTRL(pThis),
1613 !pThis->fSignalRxMiss ? " (CSR0_MISS disabled)" : ""));
1614
1615 pThis->aCSR[0] |= 0x0101; /* Initialization done */
1616 pThis->aCSR[0] &= ~0x0004; /* clear STOP bit */
1617}
1618#endif /* IN_RING3 */
1619
1620/**
1621 * Start RX/TX operation.
1622 */
1623static void pcnetStart(PCNetState *pThis)
1624{
1625 Log(("#%d pcnetStart:\n", PCNET_INST_NR));
1626 if (!CSR_DTX(pThis))
1627 pThis->aCSR[0] |= 0x0010; /* set TXON */
1628 if (!CSR_DRX(pThis))
1629 pThis->aCSR[0] |= 0x0020; /* set RXON */
1630 pcnetEnablePrivateIf(pThis);
1631 pThis->aCSR[0] &= ~0x0004; /* clear STOP bit */
1632 pThis->aCSR[0] |= 0x0002; /* STRT */
1633 pcnetPollTimerStart(pThis); /* start timer if it was stopped */
1634}
1635
1636/**
1637 * Stop RX/TX operation.
1638 */
1639static void pcnetStop(PCNetState *pThis)
1640{
1641 Log(("#%d pcnetStop:\n", PCNET_INST_NR));
1642 pThis->aCSR[0] &= ~0x7feb;
1643 pThis->aCSR[0] |= 0x0014;
1644 pThis->aCSR[4] &= ~0x02c2;
1645 pThis->aCSR[5] &= ~0x0011;
1646 pcnetEnablePrivateIf(pThis);
1647 pcnetPollTimer(pThis);
1648}
1649
1650#ifdef IN_RING3
1651static DECLCALLBACK(void) pcnetWakeupReceive(PPDMDEVINS pDevIns)
1652{
1653 PCNetState *pThis = PDMINS_2_DATA(pDevIns, PCNetState *);
1654 STAM_COUNTER_INC(&pThis->StatRxOverflowWakeup);
1655 if (pThis->hEventOutOfRxSpace != NIL_RTSEMEVENT)
1656 RTSemEventSignal(pThis->hEventOutOfRxSpace);
1657}
1658
1659static DECLCALLBACK(bool) pcnetCanRxQueueConsumer(PPDMDEVINS pDevIns, PPDMQUEUEITEMCORE pItem)
1660{
1661 pcnetWakeupReceive(pDevIns);
1662 return true;
1663}
1664#endif /* IN_RING3 */
1665
1666
1667/**
1668 * Poll Receive Descriptor Table Entry and cache the results in the appropriate registers.
1669 * Note: Once a descriptor belongs to the network card (this driver), it cannot be changed
1670 * by the host (the guest driver) anymore. Well, it could but the results are undefined by
1671 * definition.
1672 * @param fSkipCurrent if true, don't scan the current RDTE.
1673 */
1674static void pcnetRdtePoll(PCNetState *pThis, bool fSkipCurrent=false)
1675{
1676 STAM_PROFILE_ADV_START(&pThis->CTXSUFF(StatRdtePoll), a);
1677 /* assume lack of a next receive descriptor */
1678 CSR_NRST(pThis) = 0;
1679
1680 if (RT_LIKELY(pThis->GCRDRA))
1681 {
1682 /*
1683 * The current receive message descriptor.
1684 */
1685 RMD rmd;
1686 int i = CSR_RCVRC(pThis);
1687 RTGCPHYS32 addr;
1688
1689 if (i < 1)
1690 i = CSR_RCVRL(pThis);
1691
1692 if (!fSkipCurrent)
1693 {
1694 addr = pcnetRdraAddr(pThis, i);
1695 CSR_CRDA(pThis) = CSR_CRBA(pThis) = 0;
1696 CSR_CRBC(pThis) = CSR_CRST(pThis) = 0;
1697 if (!pcnetRmdLoad(pThis, &rmd, PHYSADDR(pThis, addr), true))
1698 {
1699 STAM_PROFILE_ADV_STOP(&pThis->CTXSUFF(StatRdtePoll), a);
1700 return;
1701 }
1702 if (RT_LIKELY(!IS_RMD_BAD(rmd)))
1703 {
1704 CSR_CRDA(pThis) = addr; /* Receive Descriptor Address */
1705 CSR_CRBA(pThis) = rmd.rmd0.rbadr; /* Receive Buffer Address */
1706 CSR_CRBC(pThis) = rmd.rmd1.bcnt; /* Receive Byte Count */
1707 CSR_CRST(pThis) = ((uint32_t *)&rmd)[1] >> 16; /* Receive Status */
1708 if (pThis->fMaybeOutOfSpace)
1709 {
1710#ifdef IN_RING3
1711 pcnetWakeupReceive(PCNETSTATE_2_DEVINS(pThis));
1712#else
1713 PPDMQUEUEITEMCORE pItem = PDMQueueAlloc(pThis->CTX_SUFF(pCanRxQueue));
1714 if (pItem)
1715 PDMQueueInsert(pThis->CTX_SUFF(pCanRxQueue), pItem);
1716#endif
1717 }
1718 }
1719 else
1720 {
1721 STAM_PROFILE_ADV_STOP(&pThis->CTXSUFF(StatRdtePoll), a);
1722 /* This is not problematic since we don't own the descriptor
1723 * We actually do own it, otherwise pcnetRmdLoad would have returned false.
1724 * Don't flood the release log with errors.
1725 */
1726 if (++pThis->uCntBadRMD < 50)
1727 LogRel(("PCNet#%d: BAD RMD ENTRIES AT %#010x (i=%d)\n",
1728 PCNET_INST_NR, addr, i));
1729 return;
1730 }
1731 }
1732
1733 /*
1734 * The next descriptor.
1735 */
1736 if (--i < 1)
1737 i = CSR_RCVRL(pThis);
1738 addr = pcnetRdraAddr(pThis, i);
1739 CSR_NRDA(pThis) = CSR_NRBA(pThis) = 0;
1740 CSR_NRBC(pThis) = 0;
1741 if (!pcnetRmdLoad(pThis, &rmd, PHYSADDR(pThis, addr), true))
1742 {
1743 STAM_PROFILE_ADV_STOP(&pThis->CTXSUFF(StatRdtePoll), a);
1744 return;
1745 }
1746 if (RT_LIKELY(!IS_RMD_BAD(rmd)))
1747 {
1748 CSR_NRDA(pThis) = addr; /* Receive Descriptor Address */
1749 CSR_NRBA(pThis) = rmd.rmd0.rbadr; /* Receive Buffer Address */
1750 CSR_NRBC(pThis) = rmd.rmd1.bcnt; /* Receive Byte Count */
1751 CSR_NRST(pThis) = ((uint32_t *)&rmd)[1] >> 16; /* Receive Status */
1752 }
1753 else
1754 {
1755 STAM_PROFILE_ADV_STOP(&pThis->CTXSUFF(StatRdtePoll), a);
1756 /* This is not problematic since we don't own the descriptor
1757 * We actually do own it, otherwise pcnetRmdLoad would have returned false.
1758 * Don't flood the release log with errors.
1759 */
1760 if (++pThis->uCntBadRMD < 50)
1761 LogRel(("PCNet#%d: BAD RMD ENTRIES + AT %#010x (i=%d)\n",
1762 PCNET_INST_NR, addr, i));
1763 return;
1764 }
1765
1766 /**
1767 * @todo NNRD
1768 */
1769 }
1770 else
1771 {
1772 CSR_CRDA(pThis) = CSR_CRBA(pThis) = CSR_NRDA(pThis) = CSR_NRBA(pThis) = 0;
1773 CSR_CRBC(pThis) = CSR_NRBC(pThis) = CSR_CRST(pThis) = 0;
1774 }
1775 STAM_PROFILE_ADV_STOP(&pThis->CTXSUFF(StatRdtePoll), a);
1776}
1777
1778/**
1779 * Poll Transmit Descriptor Table Entry
1780 * @return true if transmit descriptors available
1781 */
1782static int pcnetTdtePoll(PCNetState *pThis, TMD *tmd)
1783{
1784 STAM_PROFILE_ADV_START(&pThis->CTXSUFF(StatTdtePoll), a);
1785 if (RT_LIKELY(pThis->GCTDRA))
1786 {
1787 RTGCPHYS32 cxda = pcnetTdraAddr(pThis, CSR_XMTRC(pThis));
1788
1789 if (!pcnetTmdLoad(pThis, tmd, PHYSADDR(pThis, cxda), true))
1790 {
1791 STAM_PROFILE_ADV_STOP(&pThis->CTXSUFF(StatTdtePoll), a);
1792 return 0;
1793 }
1794
1795 if (RT_UNLIKELY(tmd->tmd1.ones != 15))
1796 {
1797 STAM_PROFILE_ADV_STOP(&pThis->CTXSUFF(StatTdtePoll), a);
1798 LogRel(("PCNet#%d: BAD TMD XDA=%#010x\n",
1799 PCNET_INST_NR, PHYSADDR(pThis, cxda)));
1800 return 0;
1801 }
1802
1803 /* previous xmit descriptor */
1804 CSR_PXDA(pThis) = CSR_CXDA(pThis);
1805 CSR_PXBC(pThis) = CSR_CXBC(pThis);
1806 CSR_PXST(pThis) = CSR_CXST(pThis);
1807
1808 /* set current trasmit decriptor. */
1809 CSR_CXDA(pThis) = cxda;
1810 CSR_CXBC(pThis) = tmd->tmd1.bcnt;
1811 CSR_CXST(pThis) = ((uint32_t *)tmd)[1] >> 16;
1812 STAM_PROFILE_ADV_STOP(&pThis->CTXSUFF(StatTdtePoll), a);
1813 return CARD_IS_OWNER(CSR_CXST(pThis));
1814 }
1815 else
1816 {
1817 /** @todo consistency with previous receive descriptor */
1818 CSR_CXDA(pThis) = 0;
1819 CSR_CXBC(pThis) = CSR_CXST(pThis) = 0;
1820 STAM_PROFILE_ADV_STOP(&pThis->CTXSUFF(StatTdtePoll), a);
1821 return 0;
1822 }
1823}
1824
1825
1826/**
1827 * Write data into guest receive buffers.
1828 */
1829static void pcnetReceiveNoSync(PCNetState *pThis, const uint8_t *buf, size_t cbToRecv)
1830{
1831 PPDMDEVINS pDevIns = PCNETSTATE_2_DEVINS(pThis);
1832 int is_padr = 0, is_bcast = 0, is_ladr = 0;
1833 unsigned iRxDesc;
1834 int cbPacket;
1835
1836 if (RT_UNLIKELY(CSR_DRX(pThis) || CSR_STOP(pThis) || CSR_SPND(pThis) || !cbToRecv))
1837 return;
1838
1839 /*
1840 * Drop packets if the VM is not running yet/anymore.
1841 */
1842 VMSTATE enmVMState = PDMDevHlpVMState(pDevIns);
1843 if ( enmVMState != VMSTATE_RUNNING
1844 && enmVMState != VMSTATE_RUNNING_LS)
1845 return;
1846
1847 /*
1848 * Drop packets if the cable is not connected
1849 */
1850 if (!pcnetIsLinkUp(pThis))
1851 return;
1852
1853 Log(("#%d pcnetReceiveNoSync: size=%d\n", PCNET_INST_NR, cbToRecv));
1854
1855 /*
1856 * Perform address matching.
1857 */
1858 if ( CSR_PROM(pThis)
1859 || (is_padr = padr_match(pThis, buf, cbToRecv))
1860 || (is_bcast = padr_bcast(pThis, buf, cbToRecv))
1861 || (is_ladr = ladr_match(pThis, buf, cbToRecv)))
1862 {
1863 if (HOST_IS_OWNER(CSR_CRST(pThis)))
1864 pcnetRdtePoll(pThis);
1865 if (RT_UNLIKELY(HOST_IS_OWNER(CSR_CRST(pThis))))
1866 {
1867 /* Not owned by controller. This should not be possible as
1868 * we already called pcnetCanReceive(). */
1869 LogRel(("PCNet#%d: no buffer: RCVRC=%d\n",
1870 PCNET_INST_NR, CSR_RCVRC(pThis)));
1871 /* Dump the status of all RX descriptors */
1872 const unsigned cb = 1 << pThis->iLog2DescSize;
1873 RTGCPHYS32 GCPhys = pThis->GCRDRA;
1874 iRxDesc = CSR_RCVRL(pThis);
1875 while (iRxDesc-- > 0)
1876 {
1877 RMD rmd;
1878 pcnetRmdLoad(pThis, &rmd, PHYSADDR(pThis, GCPhys), false);
1879 LogRel((" %#010x\n", rmd.rmd1));
1880 GCPhys += cb;
1881 }
1882 pThis->aCSR[0] |= 0x1000; /* Set MISS flag */
1883 CSR_MISSC(pThis)++;
1884 }
1885 else
1886 {
1887 uint8_t *src = &pThis->abRecvBuf[8];
1888 RTGCPHYS32 crda = CSR_CRDA(pThis);
1889 RTGCPHYS32 next_crda;
1890 RMD rmd, next_rmd;
1891
1892 memcpy(src, buf, cbToRecv);
1893 if (!CSR_ASTRP_RCV(pThis))
1894 {
1895 uint32_t fcs = ~0;
1896 uint8_t *p = src;
1897
1898 while (cbToRecv < 60)
1899 src[cbToRecv++] = 0;
1900 while (p != &src[cbToRecv])
1901 CRC(fcs, *p++);
1902 ((uint32_t *)&src[cbToRecv])[0] = htonl(fcs);
1903 /* FCS at end of packet */
1904 }
1905 cbToRecv += 4;
1906 cbPacket = (int)cbToRecv; Assert((size_t)cbPacket == cbToRecv);
1907
1908#ifdef PCNET_DEBUG_MATCH
1909 PRINT_PKTHDR(buf);
1910#endif
1911
1912 pcnetRmdLoad(pThis, &rmd, PHYSADDR(pThis, crda), false);
1913 /*if (!CSR_LAPPEN(pThis))*/
1914 rmd.rmd1.stp = 1;
1915
1916 size_t cbBuf = RT_MIN(4096 - (size_t)rmd.rmd1.bcnt, cbToRecv);
1917 RTGCPHYS32 rbadr = PHYSADDR(pThis, rmd.rmd0.rbadr);
1918
1919 /* save the old value to check if it was changed as long as we didn't
1920 * hold the critical section */
1921 iRxDesc = CSR_RCVRC(pThis);
1922
1923 /* We have to leave the critical section here or we risk deadlocking
1924 * with EMT when the write is to an unallocated page or has an access
1925 * handler associated with it.
1926 *
1927 * This shouldn't be a problem because:
1928 * - any modification to the RX descriptor by the driver is
1929 * forbidden as long as it is owned by the device
1930 * - we don't cache any register state beyond this point
1931 */
1932 PDMCritSectLeave(&pThis->CritSect);
1933 PDMDevHlpPhysWrite(pDevIns, rbadr, src, cbBuf);
1934 int rc = PDMCritSectEnter(&pThis->CritSect, VERR_SEM_BUSY);
1935 AssertReleaseRC(rc);
1936
1937 /* RX disabled in the meantime? If so, abort RX. */
1938 if (RT_UNLIKELY(CSR_DRX(pThis) || CSR_STOP(pThis) || CSR_SPND(pThis)))
1939 return;
1940
1941 /* Was the register modified in the meantime? If so, don't touch the
1942 * register but still update the RX descriptor. */
1943 if (RT_LIKELY(iRxDesc == CSR_RCVRC(pThis)))
1944 {
1945 if (iRxDesc-- < 2)
1946 iRxDesc = CSR_RCVRL(pThis);
1947 CSR_RCVRC(pThis) = iRxDesc;
1948 }
1949 else
1950 iRxDesc = CSR_RCVRC(pThis);
1951
1952 src += cbBuf;
1953 cbToRecv -= cbBuf;
1954
1955 while (cbToRecv > 0)
1956 {
1957 /* Read the entire next descriptor as we're likely to need it. */
1958 next_crda = pcnetRdraAddr(pThis, iRxDesc);
1959
1960 /* Check next descriptor's own bit. If we don't own it, we have
1961 * to quit and write error status into the last descriptor we own.
1962 */
1963 if (!pcnetRmdLoad(pThis, &next_rmd, PHYSADDR(pThis, next_crda), true))
1964 break;
1965
1966 /* Write back current descriptor, clear the own bit. */
1967 pcnetRmdStorePassHost(pThis, &rmd, PHYSADDR(pThis, crda));
1968
1969 /* Switch to the next descriptor */
1970 crda = next_crda;
1971 rmd = next_rmd;
1972
1973 cbBuf = RT_MIN(4096 - (size_t)rmd.rmd1.bcnt, cbToRecv);
1974 RTGCPHYS32 rbadr2 = PHYSADDR(pThis, rmd.rmd0.rbadr);
1975
1976 /* We have to leave the critical section here or we risk deadlocking
1977 * with EMT when the write is to an unallocated page or has an access
1978 * handler associated with it. See above for additional comments. */
1979 PDMCritSectLeave(&pThis->CritSect);
1980 PDMDevHlpPhysWrite(pDevIns, rbadr2, src, cbBuf);
1981 rc = PDMCritSectEnter(&pThis->CritSect, VERR_SEM_BUSY);
1982 AssertReleaseRC(rc);
1983
1984 /* RX disabled in the meantime? If so, abort RX. */
1985 if (RT_UNLIKELY(CSR_DRX(pThis) || CSR_STOP(pThis) || CSR_SPND(pThis)))
1986 return;
1987
1988 /* Was the register modified in the meantime? If so, don't touch the
1989 * register but still update the RX descriptor. */
1990 if (RT_LIKELY(iRxDesc == CSR_RCVRC(pThis)))
1991 {
1992 if (iRxDesc-- < 2)
1993 iRxDesc = CSR_RCVRL(pThis);
1994 CSR_RCVRC(pThis) = iRxDesc;
1995 }
1996 else
1997 iRxDesc = CSR_RCVRC(pThis);
1998
1999 src += cbBuf;
2000 cbToRecv -= cbBuf;
2001 }
2002
2003 if (RT_LIKELY(cbToRecv == 0))
2004 {
2005 rmd.rmd1.enp = 1;
2006 rmd.rmd1.pam = !CSR_PROM(pThis) && is_padr;
2007 rmd.rmd1.lafm = !CSR_PROM(pThis) && is_ladr;
2008 rmd.rmd1.bam = !CSR_PROM(pThis) && is_bcast;
2009 rmd.rmd2.mcnt = cbPacket;
2010
2011 STAM_REL_COUNTER_ADD(&pThis->StatReceiveBytes, cbPacket);
2012 }
2013 else
2014 {
2015 Log(("#%d: Overflow by %ubytes\n", PCNET_INST_NR, cbToRecv));
2016 rmd.rmd1.oflo = 1;
2017 rmd.rmd1.buff = 1;
2018 rmd.rmd1.err = 1;
2019 }
2020
2021 /* write back, clear the own bit */
2022 pcnetRmdStorePassHost(pThis, &rmd, PHYSADDR(pThis, crda));
2023
2024 pThis->aCSR[0] |= 0x0400;
2025
2026 Log(("#%d RCVRC=%d CRDA=%#010x\n", PCNET_INST_NR,
2027 CSR_RCVRC(pThis), PHYSADDR(pThis, CSR_CRDA(pThis))));
2028#ifdef PCNET_DEBUG_RMD
2029 PRINT_RMD(&rmd);
2030#endif
2031
2032 /* guest driver is owner: force repoll of current and next RDTEs */
2033 CSR_CRST(pThis) = 0;
2034 }
2035 }
2036
2037 /* see description of TXDPOLL:
2038 * ``transmit polling will take place following receive activities'' */
2039 pcnetPollRxTx(pThis);
2040 pcnetUpdateIrq(pThis);
2041}
2042
2043
2044/**
2045 * Transmit queue consumer
2046 * This is just a very simple way of delaying sending to R3.
2047 *
2048 * @returns Success indicator.
2049 * If false the item will not be removed and the flushing will stop.
2050 * @param pDevIns The device instance.
2051 * @param pItem The item to consume. Upon return this item will be freed.
2052 */
2053static DECLCALLBACK(bool) pcnetXmitQueueConsumer(PPDMDEVINS pDevIns, PPDMQUEUEITEMCORE pItem)
2054{
2055 PCNetState *pThis = PDMINS_2_DATA(pDevIns, PCNetState *);
2056 NOREF(pItem);
2057
2058 /*
2059 * Transmit as much as we can.
2060 */
2061 pcnetXmitPending(pThis, true /*fOnWorkerThread*/);
2062
2063 return true;
2064}
2065
2066
2067/**
2068 * Allocates a scatter/gather buffer for a transfer.
2069 *
2070 * @returns See PPDMINETWORKUP::pfnAllocBuf.
2071 * @param pThis The device instance.
2072 * @param cbMin The minimum buffer size.
2073 * @param fLoopback Set if we're in loopback mode.
2074 * @param pSgLoop Pointer to stack storage for the loopback SG.
2075 * @param ppSgBuf Where to return the SG buffer descriptor on success.
2076 * Always set.
2077 */
2078DECLINLINE(int) pcnetXmitAllocBuf(PCNetState *pThis, size_t cbMin, bool fLoopback,
2079 PPDMSCATTERGATHER pSgLoop, PPPDMSCATTERGATHER ppSgBuf)
2080{
2081 int rc;
2082
2083 if (RT_UNLIKELY(fLoopback)) /* hope that loopback mode is rare */
2084 {
2085 pSgLoop->fFlags = PDMSCATTERGATHER_FLAGS_MAGIC | PDMSCATTERGATHER_FLAGS_OWNER_1;
2086 pSgLoop->cbUsed = 0;
2087 pSgLoop->cbAvailable = sizeof(pThis->abLoopBuf);
2088 pSgLoop->pvAllocator = pThis;
2089 pSgLoop->pvUser = NULL;
2090 pSgLoop->cSegs = 1;
2091 pSgLoop->aSegs[0].cbSeg = sizeof(pThis->abLoopBuf);
2092 pSgLoop->aSegs[0].pvSeg = pThis->abLoopBuf;
2093 *ppSgBuf = pSgLoop;
2094 rc = VINF_SUCCESS;
2095 }
2096 else
2097 {
2098 PPDMINETWORKUP pDrv = pThis->CTX_SUFF(pDrv);
2099 if (RT_LIKELY(pDrv))
2100 {
2101 rc = pDrv->pfnAllocBuf(pDrv, cbMin, NULL /*pGso*/, ppSgBuf);
2102 AssertMsg(rc == VINF_SUCCESS || rc == VERR_TRY_AGAIN || rc == VERR_NET_DOWN || rc == VERR_NO_MEMORY, ("%Rrc\n", rc));
2103 if (RT_FAILURE(rc))
2104 *ppSgBuf = NULL;
2105 }
2106 else
2107 {
2108 rc = VERR_NET_DOWN;
2109 *ppSgBuf = NULL;
2110 }
2111 }
2112 return rc;
2113}
2114
2115
2116/**
2117 * Frees an unsent buffer.
2118 *
2119 * @param pThis The device instance.
2120 * @param fLoopback Set if we're in loopback mode.
2121 * @param pSgBuf The SG to free. Can be NULL.
2122 */
2123DECLINLINE(void) pcnetXmitFreeBuf(PCNetState *pThis, bool fLoopback, PPDMSCATTERGATHER pSgBuf)
2124{
2125 if (pSgBuf)
2126 {
2127 if (RT_UNLIKELY(fLoopback))
2128 pSgBuf->pvAllocator = NULL;
2129 else
2130 {
2131 PPDMINETWORKUP pDrv = pThis->CTX_SUFF(pDrv);
2132 if (RT_LIKELY(pDrv))
2133 pDrv->pfnFreeBuf(pDrv, pSgBuf);
2134 }
2135 }
2136}
2137
2138
2139/**
2140 * Sends the scatter/gather buffer.
2141 *
2142 * Wrapper around PDMINETWORKUP::pfnSendBuf, so check it out for the fine print.
2143 *
2144 * @returns See PDMINETWORKUP::pfnSendBuf.
2145 * @param pThis The device instance.
2146 * @param fLoopback Set if we're in loopback mode.
2147 * @param pSgBuf The SG to send.
2148 * @param fOnWorkerThread Set if we're being called on a work thread. Clear
2149 * if an EMT.
2150 */
2151DECLINLINE(int) pcnetXmitSendBuf(PCNetState *pThis, bool fLoopback, PPDMSCATTERGATHER pSgBuf, bool fOnWorkerThread)
2152{
2153 int rc;
2154 STAM_REL_COUNTER_ADD(&pThis->StatTransmitBytes, pSgBuf->cbUsed);
2155 if (RT_UNLIKELY(fLoopback)) /* hope that loopback mode is rare */
2156 {
2157 Assert(pSgBuf->pvAllocator == (void *)pThis);
2158 pThis->Led.Asserted.s.fReading = pThis->Led.Actual.s.fReading = 1;
2159 if (HOST_IS_OWNER(CSR_CRST(pThis)))
2160 pcnetRdtePoll(pThis);
2161
2162 pcnetReceiveNoSync(pThis, pThis->abLoopBuf, pSgBuf->cbUsed);
2163 pThis->Led.Actual.s.fReading = 0;
2164 rc = VINF_SUCCESS;
2165 }
2166 else
2167 {
2168 /** @todo We used to leave the critsect here, not sure if that's necessary any
2169 * longer. If we could avoid that we could cache a bit more info in
2170 * the loop and make it part of the driver<->device contract, saving
2171 * critsect mess down in DrvIntNet. */
2172 STAM_PROFILE_START(&pThis->StatTransmitSend, a);
2173 if (pSgBuf->cbUsed > 70) /* unqualified guess */
2174 pThis->Led.Asserted.s.fWriting = pThis->Led.Actual.s.fWriting = 1;
2175
2176 PPDMINETWORKUP pDrv = pThis->CTX_SUFF(pDrv);
2177 if (RT_LIKELY(pDrv))
2178 {
2179 rc = pDrv->pfnSendBuf(pDrv, pSgBuf, fOnWorkerThread);
2180 AssertMsg(rc == VINF_SUCCESS || rc == VERR_NET_DOWN || rc == VERR_NET_NO_BUFFER_SPACE, ("%Rrc\n", rc));
2181 }
2182 else
2183 rc = VERR_NET_DOWN;
2184
2185 pThis->Led.Actual.s.fWriting = 0;
2186 STAM_PROFILE_STOP(&pThis->StatTransmitSend, a);
2187 }
2188 return rc;
2189}
2190
2191
2192/**
2193 * pcnetXmitRead1st worker that handles the unlikely + slower segmented code
2194 * path.
2195 */
2196static void pcnetXmitRead1stSlow(PCNetState *pThis, RTGCPHYS32 GCPhysFrame, unsigned cbFrame,
2197 PPDMSCATTERGATHER pSgBuf)
2198{
2199 AssertFailed(); /* This path is not suppost to be taken atm */
2200
2201 pSgBuf->cbUsed = cbFrame;
2202 for (uint32_t iSeg = 0; ; iSeg++)
2203 {
2204 Assert(iSeg < pSgBuf->cSegs);
2205 uint32_t cbRead = (uint32_t)RT_MIN(cbFrame, pSgBuf->aSegs[iSeg].cbSeg);
2206 PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns), GCPhysFrame, pSgBuf->aSegs[iSeg].pvSeg, cbRead);
2207 cbFrame -= cbRead;
2208 if (!cbFrame)
2209 return;
2210 GCPhysFrame += cbRead;
2211 }
2212}
2213
2214
2215/**
2216 * pcnetXmitSgReadMore worker that handles the unlikely + slower segmented code
2217 * path.
2218 */
2219static void pcnetXmitReadMoreSlow(PCNetState *pThis, RTGCPHYS32 GCPhysFrame, unsigned cbFrame,
2220 PPDMSCATTERGATHER pSgBuf)
2221{
2222 AssertFailed(); /* This path is not suppost to be taken atm */
2223
2224 /* Find the segment which we'll put the next byte into. */
2225 size_t off = pSgBuf->cbUsed;
2226 size_t offSeg = 0;
2227 uint32_t iSeg = 0;
2228 while (offSeg + pSgBuf->aSegs[iSeg].cbSeg <= off)
2229 {
2230 offSeg += pSgBuf->aSegs[iSeg].cbSeg;
2231 iSeg++;
2232 Assert(iSeg < pSgBuf->cSegs);
2233 }
2234
2235 /* Commit before we start copying so we can decrement cbFrame. */
2236 pSgBuf->cbUsed = off + cbFrame;
2237
2238 /* Deal with the first segment if we at an offset into it. */
2239 if (off != offSeg)
2240 {
2241 size_t offIntoSeg = off - offSeg;
2242 uint32_t cbRead = (uint32_t)RT_MIN(pSgBuf->aSegs[iSeg].cbSeg - offIntoSeg, cbFrame);
2243 PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns), GCPhysFrame,
2244 (uint8_t *)pSgBuf->aSegs[iSeg].pvSeg + offIntoSeg, cbRead);
2245 cbFrame -= cbRead;
2246 if (!cbFrame)
2247 return;
2248 GCPhysFrame += cbRead;
2249 iSeg++;
2250 }
2251
2252 /* For the remainder, we've got whole segments. */
2253 for (;; iSeg++)
2254 {
2255 Assert(iSeg < pSgBuf->cSegs);
2256
2257 uint32_t cbRead = (uint32_t)RT_MIN(pSgBuf->aSegs[iSeg].cbSeg, cbFrame);
2258 PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns), GCPhysFrame, pSgBuf->aSegs[iSeg].pvSeg, cbRead);
2259 cbFrame -= cbRead;
2260 if (!cbFrame)
2261 return;
2262 GCPhysFrame += cbFrame;
2263 }
2264}
2265
2266
2267/**
2268 * Reads the first part of a frame into the scatter gather buffer.
2269 */
2270DECLINLINE(void) pcnetXmitRead1st(PCNetState *pThis, RTGCPHYS32 GCPhysFrame, const unsigned cbFrame,
2271 PPDMSCATTERGATHER pSgBuf)
2272{
2273 Assert(PDMCritSectIsOwner(&pThis->CritSect));
2274 Assert(pSgBuf->cbAvailable >= cbFrame);
2275
2276 if (RT_LIKELY(pSgBuf->aSegs[0].cbSeg >= cbFrame)) /* justification: all drivers returns a single segment atm. */
2277 {
2278 pSgBuf->cbUsed = cbFrame;
2279 PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns), GCPhysFrame, pSgBuf->aSegs[0].pvSeg, cbFrame);
2280 }
2281 else
2282 pcnetXmitRead1stSlow(pThis, GCPhysFrame, cbFrame, pSgBuf);
2283}
2284
2285/**
2286 * Reads more into the current frame.
2287 */
2288DECLINLINE(void) pcnetXmitReadMore(PCNetState *pThis, RTGCPHYS32 GCPhysFrame, const unsigned cbFrame,
2289 PPDMSCATTERGATHER pSgBuf)
2290{
2291 size_t off = pSgBuf->cbUsed;
2292 Assert(pSgBuf->cbAvailable >= cbFrame + off);
2293
2294 if (RT_LIKELY(pSgBuf->aSegs[0].cbSeg >= cbFrame + off))
2295 {
2296 pSgBuf->cbUsed = cbFrame + off;
2297 PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns), GCPhysFrame,
2298 (uint8_t *)pSgBuf->aSegs[0].pvSeg + off, cbFrame);
2299 }
2300 else
2301 pcnetXmitReadMoreSlow(pThis, GCPhysFrame, cbFrame, pSgBuf);
2302}
2303
2304
2305/**
2306 * Fails a TMD with a link down error.
2307 */
2308static void pcnetXmitFailTMDLinkDown(PCNetState *pThis, TMD *pTmd)
2309{
2310 /* make carrier error - hope this is correct. */
2311 pThis->cLinkDownReported++;
2312 pTmd->tmd2.lcar = pTmd->tmd1.err = 1;
2313 pThis->aCSR[0] |= RT_BIT(15) | RT_BIT(13); /* ERR | CERR */
2314 pThis->Led.Asserted.s.fError = pThis->Led.Actual.s.fError = 1;
2315 Log(("#%d pcnetTransmit: Signaling send error. swstyle=%#x\n",
2316 PCNET_INST_NR, pThis->aBCR[BCR_SWS]));
2317}
2318
2319/**
2320 * Fails a TMD with a generic error.
2321 */
2322static void pcnetXmitFailTMDGeneric(PCNetState *pThis, TMD *pTmd)
2323{
2324 /* make carrier error - hope this is correct. */
2325 pTmd->tmd2.lcar = pTmd->tmd1.err = 1;
2326 pThis->aCSR[0] |= RT_BIT(15) | RT_BIT(13); /* ERR | CERR */
2327 pThis->Led.Asserted.s.fError = pThis->Led.Actual.s.fError = 1;
2328 Log(("#%d pcnetTransmit: Signaling send error. swstyle=%#x\n",
2329 PCNET_INST_NR, pThis->aBCR[BCR_SWS]));
2330}
2331
2332
2333/**
2334 * Try to transmit frames
2335 */
2336static void pcnetTransmit(PCNetState *pThis)
2337{
2338 if (RT_UNLIKELY(!CSR_TXON(pThis)))
2339 {
2340 pThis->aCSR[0] &= ~0x0008; /* Clear TDMD */
2341 return;
2342 }
2343
2344 /*
2345 * Check the current transmit descriptors.
2346 */
2347 TMD tmd;
2348 if (!pcnetTdtePoll(pThis, &tmd))
2349 return;
2350
2351 /*
2352 * Clear TDMD.
2353 */
2354 pThis->aCSR[0] &= ~0x0008;
2355
2356 /*
2357 * Transmit pending packets if possible, defere it if we cannot do it
2358 * in the current context.
2359 */
2360#if defined(IN_RING0) || defined(IN_RC)
2361 if (!pThis->CTX_SUFF(pDrv))
2362 {
2363 PPDMQUEUEITEMCORE pItem = PDMQueueAlloc(pThis->CTX_SUFF(pXmitQueue));
2364 if (RT_UNLIKELY(pItem))
2365 PDMQueueInsert(pThis->CTX_SUFF(pXmitQueue), pItem);
2366 }
2367 else
2368#endif
2369 {
2370 int rc = pcnetXmitPending(pThis, false /*fOnWorkerThread*/);
2371 if (rc == VERR_TRY_AGAIN)
2372 rc = VINF_SUCCESS;
2373 AssertRC(rc);
2374 }
2375}
2376
2377
2378/**
2379 * Actually try transmit frames.
2380 *
2381 * @threads TX or EMT.
2382 */
2383static int pcnetAsyncTransmit(PCNetState *pThis, bool fOnWorkerThread)
2384{
2385 Assert(PDMCritSectIsOwner(&pThis->CritSect));
2386
2387 /*
2388 * Just cleard transmit demand if the transmitter is off.
2389 */
2390 if (RT_UNLIKELY(!CSR_TXON(pThis)))
2391 {
2392 pThis->aCSR[0] &= ~0x0008; /* Clear TDMD */
2393 return VINF_SUCCESS;
2394 }
2395
2396 /*
2397 * Iterate the transmit descriptors.
2398 */
2399 int rc;
2400 unsigned cFlushIrq = 0;
2401 STAM_PROFILE_ADV_START(&pThis->StatTransmit, a);
2402 do
2403 {
2404#ifdef VBOX_WITH_STATISTICS
2405 unsigned cBuffers = 1;
2406#endif
2407 TMD tmd;
2408 if (!pcnetTdtePoll(pThis, &tmd))
2409 break;
2410
2411 /* Don't continue sending packets when the link is down. */
2412 if (RT_UNLIKELY( !pcnetIsLinkUp(pThis)
2413 && pThis->cLinkDownReported > PCNET_MAX_LINKDOWN_REPORTED)
2414 )
2415 break;
2416
2417#ifdef PCNET_DEBUG_TMD
2418 Log2(("#%d TMDLOAD %#010x\n", PCNET_INST_NR, PHYSADDR(pThis, CSR_CXDA(pThis))));
2419 PRINT_TMD(&tmd);
2420#endif
2421 bool const fLoopback = CSR_LOOP(pThis);
2422 PDMSCATTERGATHER SgLoop;
2423 PPDMSCATTERGATHER pSgBuf;
2424
2425 /*
2426 * The typical case - a complete packet.
2427 */
2428 if (tmd.tmd1.stp && tmd.tmd1.enp)
2429 {
2430 const unsigned cb = 4096 - tmd.tmd1.bcnt;
2431 Log(("#%d pcnetAsyncTransmit: stp&enp: cb=%d xmtrc=%#x\n", PCNET_INST_NR, cb, CSR_XMTRC(pThis)));
2432 STAM_COUNTER_INC(&pThis->StatTransmitCase1);
2433
2434 if (RT_LIKELY(pcnetIsLinkUp(pThis) || fLoopback))
2435 {
2436 /* From the manual: ``A zero length buffer is acceptable as
2437 * long as it is not the last buffer in a chain (STP = 0 and
2438 * ENP = 1).'' That means that the first buffer might have a
2439 * zero length if it is not the last one in the chain. */
2440 if (RT_LIKELY(cb <= MAX_FRAME))
2441 {
2442 rc = pcnetXmitAllocBuf(pThis, cb, fLoopback, &SgLoop, &pSgBuf);
2443 if (RT_SUCCESS(rc))
2444 {
2445 pcnetXmitRead1st(pThis, PHYSADDR(pThis, tmd.tmd0.tbadr), cb, pSgBuf);
2446 rc = pcnetXmitSendBuf(pThis, fLoopback, pSgBuf, fOnWorkerThread);
2447 }
2448 else if (rc == VERR_TRY_AGAIN)
2449 {
2450 STAM_PROFILE_ADV_STOP(&pThis->StatTransmit, a);
2451 return VINF_SUCCESS;
2452 }
2453 if (RT_FAILURE(rc))
2454 pcnetXmitFailTMDLinkDown(pThis, &tmd);
2455 }
2456 else if (cb == 4096)
2457 {
2458 /* The Windows NT4 pcnet driver sometimes marks the first
2459 * unused descriptor as owned by us. Ignore that (by
2460 * passing it back). Do not update the ring counter in this
2461 * case (otherwise that driver becomes even more confused,
2462 * which causes transmit to stall for about 10 seconds).
2463 * This is just a workaround, not a final solution. */
2464 /* r=frank: IMHO this is the correct implementation. The
2465 * manual says: ``If the OWN bit is set and the buffer
2466 * length is 0, the OWN bit will be cleared. In the C-LANCE
2467 * the buffer length of 0 is interpreted as a 4096-byte
2468 * buffer.'' */
2469 LogRel(("PCNet#%d: pcnetAsyncTransmit: illegal 4kb frame -> ignoring\n", PCNET_INST_NR));
2470 pcnetTmdStorePassHost(pThis, &tmd, PHYSADDR(pThis, CSR_CXDA(pThis)));
2471 break;
2472 }
2473 else
2474 {
2475 /* Signal error, as this violates the Ethernet specs. */
2476 /** @todo check if the correct error is generated. */
2477 LogRel(("PCNet#%d: pcnetAsyncTransmit: illegal 4kb frame -> signalling error\n", PCNET_INST_NR));
2478
2479 pcnetXmitFailTMDGeneric(pThis, &tmd);
2480 }
2481 }
2482 else
2483 pcnetXmitFailTMDLinkDown(pThis, &tmd);
2484
2485 /* Write back the TMD and pass it to the host (clear own bit). */
2486 pcnetTmdStorePassHost(pThis, &tmd, PHYSADDR(pThis, CSR_CXDA(pThis)));
2487
2488 /* advance the ring counter register */
2489 if (CSR_XMTRC(pThis) < 2)
2490 CSR_XMTRC(pThis) = CSR_XMTRL(pThis);
2491 else
2492 CSR_XMTRC(pThis)--;
2493 }
2494 else if (tmd.tmd1.stp)
2495 {
2496 STAM_COUNTER_INC(&pThis->StatTransmitCase2);
2497
2498 /*
2499 * Read TMDs until end-of-packet or tdte poll fails (underflow).
2500 *
2501 * We allocate a maximum sized buffer here since we do not wish to
2502 * waste time finding out how much space we actually need even if
2503 * we could reliably do that on SMP guests.
2504 */
2505 unsigned cb = 4096 - tmd.tmd1.bcnt;
2506 rc = pcnetXmitAllocBuf(pThis, RT_MAX(MAX_FRAME, cb), fLoopback, &SgLoop, &pSgBuf);
2507 if (rc == VERR_TRY_AGAIN)
2508 {
2509 STAM_PROFILE_ADV_STOP(&pThis->StatTransmit, a);
2510 return VINF_SUCCESS;
2511 }
2512
2513 bool fDropFrame = RT_FAILURE(rc);
2514 if (!fDropFrame)
2515 pcnetXmitRead1st(pThis, PHYSADDR(pThis, tmd.tmd0.tbadr), cb, pSgBuf);
2516
2517 for (;;)
2518 {
2519 /*
2520 * Advance the ring counter register and check the next tmd.
2521 */
2522#ifdef LOG_ENABLED
2523 const uint32_t iStart = CSR_XMTRC(pThis);
2524#endif
2525 const uint32_t GCPhysPrevTmd = PHYSADDR(pThis, CSR_CXDA(pThis));
2526 if (CSR_XMTRC(pThis) < 2)
2527 CSR_XMTRC(pThis) = CSR_XMTRL(pThis);
2528 else
2529 CSR_XMTRC(pThis)--;
2530
2531 TMD dummy;
2532 if (!pcnetTdtePoll(pThis, &dummy))
2533 {
2534 /*
2535 * Underflow!
2536 */
2537 tmd.tmd2.buff = tmd.tmd2.uflo = tmd.tmd1.err = 1;
2538 pThis->aCSR[0] |= 0x0200; /* set TINT */
2539 if (!CSR_DXSUFLO(pThis)) /* stop on xmit underflow */
2540 pThis->aCSR[0] &= ~0x0010; /* clear TXON */
2541 pcnetTmdStorePassHost(pThis, &tmd, GCPhysPrevTmd);
2542 AssertMsgFailed(("pcnetAsyncTransmit: Underflow!!!\n"));
2543 pcnetXmitFreeBuf(pThis, fLoopback, pSgBuf);
2544 break;
2545 }
2546
2547 /* release & save the previous tmd, pass it to the host */
2548 pcnetTmdStorePassHost(pThis, &tmd, GCPhysPrevTmd);
2549
2550 /*
2551 * The next tmd.
2552 */
2553#ifdef VBOX_WITH_STATISTICS
2554 cBuffers++;
2555#endif
2556 pcnetTmdLoad(pThis, &tmd, PHYSADDR(pThis, CSR_CXDA(pThis)), false);
2557 cb = 4096 - tmd.tmd1.bcnt;
2558 if ( !fDropFrame
2559 && pSgBuf->cbUsed + cb <= MAX_FRAME) /** @todo this used to be ... + cb < MAX_FRAME. */
2560 pcnetXmitReadMore(pThis, PHYSADDR(pThis, tmd.tmd0.tbadr), cb, pSgBuf);
2561 else
2562 {
2563 AssertMsg(fDropFrame, ("pcnetAsyncTransmit: Frame is too big!!! %d bytes\n", pSgBuf->cbUsed + cb));
2564 fDropFrame = true;
2565 }
2566
2567 /*
2568 * Done already?
2569 */
2570 if (tmd.tmd1.enp)
2571 {
2572 Log(("#%d pcnetAsyncTransmit: stp: cb=%d xmtrc=%#x-%#x\n", PCNET_INST_NR,
2573 pSgBuf ? pSgBuf->cbUsed : 0, iStart, CSR_XMTRC(pThis)));
2574 if (!fDropFrame && (pcnetIsLinkUp(pThis) || fLoopback))
2575 {
2576 rc = pcnetXmitSendBuf(pThis, fLoopback, pSgBuf, fOnWorkerThread);
2577 fDropFrame = RT_FAILURE(rc);
2578 }
2579 else
2580 pcnetXmitFreeBuf(pThis, fLoopback, pSgBuf);
2581 if (fDropFrame)
2582 pcnetXmitFailTMDLinkDown(pThis, &tmd);
2583
2584 /* Write back the TMD, pass it to the host */
2585 pcnetTmdStorePassHost(pThis, &tmd, PHYSADDR(pThis, CSR_CXDA(pThis)));
2586
2587 /* advance the ring counter register */
2588 if (CSR_XMTRC(pThis) < 2)
2589 CSR_XMTRC(pThis) = CSR_XMTRL(pThis);
2590 else
2591 CSR_XMTRC(pThis)--;
2592 break;
2593 }
2594 } /* the loop */
2595 }
2596 else
2597 {
2598 /*
2599 * We underflowed in a previous transfer, or the driver is giving us shit.
2600 * Simply stop the transmitting for now.
2601 */
2602 /** @todo according to the specs we're supposed to clear the own bit and move on to the next one. */
2603 Log(("#%d pcnetAsyncTransmit: guest is giving us shit!\n", PCNET_INST_NR));
2604 break;
2605 }
2606 /* Update TDMD, TXSTRT and TINT. */
2607 pThis->aCSR[0] &= ~0x0008; /* clear TDMD */
2608
2609 pThis->aCSR[4] |= 0x0008; /* set TXSTRT */
2610 if ( !CSR_TOKINTD(pThis) /* Transmit OK Interrupt Disable, no infl. on errors. */
2611 || (CSR_LTINTEN(pThis) && tmd.tmd1.ltint)
2612 || tmd.tmd1.err)
2613 {
2614 cFlushIrq++;
2615 }
2616
2617 /** @todo should we continue after an error (tmd.tmd1.err) or not? */
2618
2619 STAM_COUNTER_INC(&pThis->aStatXmitChainCounts[RT_MIN(cBuffers,
2620 RT_ELEMENTS(pThis->aStatXmitChainCounts)) - 1]);
2621 } while (CSR_TXON(pThis)); /* transfer on */
2622
2623 if (cFlushIrq)
2624 {
2625 STAM_COUNTER_INC(&pThis->aStatXmitFlush[RT_MIN(cFlushIrq, RT_ELEMENTS(pThis->aStatXmitFlush)) - 1]);
2626 pThis->aCSR[0] |= 0x0200; /* set TINT */
2627 pcnetUpdateIrq(pThis);
2628 }
2629
2630 STAM_PROFILE_ADV_STOP(&pThis->StatTransmit, a);
2631
2632 return VINF_SUCCESS;
2633}
2634
2635
2636/**
2637 * Transmit pending descriptors.
2638 *
2639 * @returns VBox status code. VERR_TRY_AGAIN is returned if we're busy.
2640 *
2641 * @param pThis The PCNet instance data.
2642 * @param fOnWorkerThread Whether we're on a worker thread or on an EMT.
2643 */
2644static int pcnetXmitPending(PCNetState *pThis, bool fOnWorkerThread)
2645{
2646 int rc = VINF_SUCCESS;
2647
2648 /*
2649 * Grab the xmit lock of the driver as well as the E1K device state.
2650 */
2651 PPDMINETWORKUP pDrv = pThis->CTX_SUFF(pDrv);
2652 if (pDrv)
2653 {
2654 rc = pDrv->pfnBeginXmit(pDrv, false /*fOnWorkerThread*/);
2655 if (RT_FAILURE(rc))
2656 return rc;
2657 }
2658 rc = PDMCritSectEnter(&pThis->CritSect, VERR_SEM_BUSY);
2659 if (RT_SUCCESS(rc))
2660 {
2661 /** @todo check if we're supposed to suspend now. */
2662 /*
2663 * Do the transmitting.
2664 */
2665 int rc2 = pcnetAsyncTransmit(pThis, false /*fOnWorkerThread*/);
2666 AssertReleaseRC(rc2);
2667
2668 /*
2669 * Release the locks.
2670 */
2671 PDMCritSectLeave(&pThis->CritSect);
2672 }
2673 else
2674 AssertLogRelRC(rc);
2675 if (pDrv)
2676 pDrv->pfnEndXmit(pDrv);
2677
2678 return rc;
2679}
2680
2681
2682/**
2683 * Poll for changes in RX and TX descriptor rings.
2684 */
2685static void pcnetPollRxTx(PCNetState *pThis)
2686{
2687 if (CSR_RXON(pThis))
2688 {
2689 /*
2690 * The second case is important for pcnetWaitReceiveAvail(): If CSR_CRST(pThis) was
2691 * true but pcnetCanReceive() returned false for some other reason we need to check
2692 * _now_ if we have to wakeup pcnetWaitReceiveAvail().
2693 */
2694 if ( HOST_IS_OWNER(CSR_CRST(pThis)) /* only poll RDTEs if none available or ... */
2695 || pThis->fMaybeOutOfSpace) /* ... for waking up pcnetWaitReceiveAvail() */
2696 pcnetRdtePoll(pThis);
2697 }
2698
2699 if (CSR_TDMD(pThis) || (CSR_TXON(pThis) && !CSR_DPOLL(pThis)))
2700 pcnetTransmit(pThis);
2701}
2702
2703
2704/**
2705 * Start the poller timer.
2706 * Poll timer interval is fixed to 500Hz. Don't stop it.
2707 * @thread EMT, TAP.
2708 */
2709static void pcnetPollTimerStart(PCNetState *pThis)
2710{
2711 TMTimerSetMillies(pThis->CTX_SUFF(pTimerPoll), 2);
2712}
2713
2714
2715/**
2716 * Update the poller timer.
2717 * @thread EMT.
2718 */
2719static void pcnetPollTimer(PCNetState *pThis)
2720{
2721 STAM_PROFILE_ADV_START(&pThis->StatPollTimer, a);
2722
2723#ifdef LOG_ENABLED
2724 TMD dummy;
2725 if (CSR_STOP(pThis) || CSR_SPND(pThis))
2726 Log2(("#%d pcnetPollTimer time=%#010llx CSR_STOP=%d CSR_SPND=%d\n",
2727 PCNET_INST_NR, RTTimeMilliTS(), CSR_STOP(pThis), CSR_SPND(pThis)));
2728 else
2729 Log2(("#%d pcnetPollTimer time=%#010llx TDMD=%d TXON=%d POLL=%d TDTE=%d TDRA=%#x\n",
2730 PCNET_INST_NR, RTTimeMilliTS(), CSR_TDMD(pThis), CSR_TXON(pThis),
2731 !CSR_DPOLL(pThis), pcnetTdtePoll(pThis, &dummy), pThis->GCTDRA));
2732 Log2(("#%d pcnetPollTimer: CSR_CXDA=%#x CSR_XMTRL=%d CSR_XMTRC=%d\n",
2733 PCNET_INST_NR, CSR_CXDA(pThis), CSR_XMTRL(pThis), CSR_XMTRC(pThis)));
2734#endif
2735#ifdef PCNET_DEBUG_TMD
2736 if (CSR_CXDA(pThis))
2737 {
2738 TMD tmd;
2739 pcnetTmdLoad(pThis, &tmd, PHYSADDR(pThis, CSR_CXDA(pThis)), false);
2740 Log2(("#%d pcnetPollTimer: TMDLOAD %#010x\n", PCNET_INST_NR, PHYSADDR(pThis, CSR_CXDA(pThis))));
2741 PRINT_TMD(&tmd);
2742 }
2743#endif
2744 if (CSR_TDMD(pThis))
2745 pcnetTransmit(pThis);
2746
2747 pcnetUpdateIrq(pThis);
2748
2749 /* If the receive thread is waiting for new descriptors, poll TX/RX even if polling
2750 * disabled. We wouldn't need to poll for new TX descriptors in that case but it will
2751 * not hurt as waiting for RX descriptors should happen very seldom */
2752 if (RT_LIKELY( !CSR_STOP(pThis)
2753 && !CSR_SPND(pThis)
2754 && ( !CSR_DPOLL(pThis)
2755 || pThis->fMaybeOutOfSpace)))
2756 {
2757 /* We ensure that we poll at least every 2ms (500Hz) but not more often than
2758 * 5000 times per second. This way we completely prevent the overhead from
2759 * heavy reprogramming the timer which turned out to be very CPU-intensive.
2760 * The drawback is that csr46 and csr47 are not updated properly anymore
2761 * but so far I have not seen any guest depending on these values. The 2ms
2762 * interval is the default polling interval of the PCNet card (65536/33MHz). */
2763#ifdef PCNET_NO_POLLING
2764 pcnetPollRxTx(pThis);
2765#else
2766 uint64_t u64Now = TMTimerGet(pThis->CTX_SUFF(pTimerPoll));
2767 if (RT_UNLIKELY(u64Now - pThis->u64LastPoll > 200000))
2768 {
2769 pThis->u64LastPoll = u64Now;
2770 pcnetPollRxTx(pThis);
2771 }
2772 if (!TMTimerIsActive(pThis->CTX_SUFF(pTimerPoll)))
2773 pcnetPollTimerStart(pThis);
2774#endif
2775 }
2776 STAM_PROFILE_ADV_STOP(&pThis->StatPollTimer, a);
2777}
2778
2779
2780static int pcnetCSRWriteU16(PCNetState *pThis, uint32_t u32RAP, uint32_t val)
2781{
2782 int rc = VINF_SUCCESS;
2783#ifdef PCNET_DEBUG_CSR
2784 Log(("#%d pcnetCSRWriteU16: rap=%d val=%#06x\n", PCNET_INST_NR, u32RAP, val));
2785#endif
2786 switch (u32RAP)
2787 {
2788 case 0:
2789 {
2790 uint16_t csr0 = pThis->aCSR[0];
2791 /* Clear any interrupt flags.
2792 * Don't clear an interrupt flag which was not seen by the guest yet. */
2793 csr0 &= ~(val & 0x7f00 & pThis->u16CSR0LastSeenByGuest);
2794 csr0 = (csr0 & ~0x0040) | (val & 0x0048);
2795 val = (val & 0x007f) | (csr0 & 0x7f00);
2796
2797 /* Iff STOP, STRT and INIT are set, clear STRT and INIT */
2798 if ((val & 7) == 7)
2799 val &= ~3;
2800
2801 Log(("#%d CSR0: old=%#06x new=%#06x\n", PCNET_INST_NR, pThis->aCSR[0], csr0));
2802
2803#ifndef IN_RING3
2804 if (!(csr0 & 0x0001/*init*/) && (val & 1))
2805 {
2806 Log(("#%d pcnetCSRWriteU16: pcnetInit requested => HC\n", PCNET_INST_NR));
2807 return VINF_IOM_HC_IOPORT_WRITE;
2808 }
2809#endif
2810 pThis->aCSR[0] = csr0;
2811
2812 if (!CSR_STOP(pThis) && (val & 4))
2813 pcnetStop(pThis);
2814
2815#ifdef IN_RING3
2816 if (!CSR_INIT(pThis) && (val & 1))
2817 pcnetInit(pThis);
2818#endif
2819
2820 if (!CSR_STRT(pThis) && (val & 2))
2821 pcnetStart(pThis);
2822
2823 if (CSR_TDMD(pThis))
2824 pcnetTransmit(pThis);
2825
2826 return rc;
2827 }
2828 case 1: /* IADRL */
2829 case 2: /* IADRH */
2830 case 8: /* LADRF 0..15 */
2831 case 9: /* LADRF 16..31 */
2832 case 10: /* LADRF 32..47 */
2833 case 11: /* LADRF 48..63 */
2834 case 12: /* PADR 0..15 */
2835 case 13: /* PADR 16..31 */
2836 case 14: /* PADR 32..47 */
2837 case 18: /* CRBAL */
2838 case 19: /* CRBAU */
2839 case 20: /* CXBAL */
2840 case 21: /* CXBAU */
2841 case 22: /* NRBAL */
2842 case 23: /* NRBAU */
2843 case 26: /* NRDAL */
2844 case 27: /* NRDAU */
2845 case 28: /* CRDAL */
2846 case 29: /* CRDAU */
2847 case 32: /* NXDAL */
2848 case 33: /* NXDAU */
2849 case 34: /* CXDAL */
2850 case 35: /* CXDAU */
2851 case 36: /* NNRDL */
2852 case 37: /* NNRDU */
2853 case 38: /* NNXDL */
2854 case 39: /* NNXDU */
2855 case 40: /* CRBCL */
2856 case 41: /* CRBCU */
2857 case 42: /* CXBCL */
2858 case 43: /* CXBCU */
2859 case 44: /* NRBCL */
2860 case 45: /* NRBCU */
2861 case 46: /* POLL */
2862 case 47: /* POLLINT */
2863 case 72: /* RCVRC */
2864 case 74: /* XMTRC */
2865 case 112: /* MISSC */
2866 if (CSR_STOP(pThis) || CSR_SPND(pThis))
2867 break;
2868 case 3: /* Interrupt Mask and Deferral Control */
2869 break;
2870 case 4: /* Test and Features Control */
2871 pThis->aCSR[4] &= ~(val & 0x026a);
2872 val &= ~0x026a;
2873 val |= pThis->aCSR[4] & 0x026a;
2874 break;
2875 case 5: /* Extended Control and Interrupt 1 */
2876 pThis->aCSR[5] &= ~(val & 0x0a90);
2877 val &= ~0x0a90;
2878 val |= pThis->aCSR[5] & 0x0a90;
2879 break;
2880 case 7: /* Extended Control and Interrupt 2 */
2881 {
2882 uint16_t csr7 = pThis->aCSR[7];
2883 csr7 &= ~0x0400 ;
2884 csr7 &= ~(val & 0x0800);
2885 csr7 |= (val & 0x0400);
2886 pThis->aCSR[7] = csr7;
2887 return rc;
2888 }
2889 case 15: /* Mode */
2890 if ((pThis->aCSR[15] & 0x8000) != (uint16_t)(val & 0x8000) && pThis->pDrvR3)
2891 {
2892 Log(("#%d: promiscuous mode changed to %d\n", PCNET_INST_NR, !!(val & 0x8000)));
2893#ifndef IN_RING3
2894 return VINF_IOM_HC_IOPORT_WRITE;
2895#else
2896 /* check for promiscuous mode change */
2897 if (pThis->pDrvR3)
2898 pThis->pDrvR3->pfnSetPromiscuousMode(pThis->pDrvR3, !!(val & 0x8000));
2899#endif
2900 }
2901 break;
2902 case 16: /* IADRL */
2903 return pcnetCSRWriteU16(pThis, 1, val);
2904 case 17: /* IADRH */
2905 return pcnetCSRWriteU16(pThis, 2, val);
2906
2907 /*
2908 * 24 and 25 are the Base Address of Receive Descriptor.
2909 * We combine and mirror these in GCRDRA.
2910 */
2911 case 24: /* BADRL */
2912 case 25: /* BADRU */
2913 if (!CSR_STOP(pThis) && !CSR_SPND(pThis))
2914 {
2915 Log(("#%d: WRITE CSR%d, %#06x !!\n", PCNET_INST_NR, u32RAP, val));
2916 return rc;
2917 }
2918 if (u32RAP == 24)
2919 pThis->GCRDRA = (pThis->GCRDRA & 0xffff0000) | (val & 0x0000ffff);
2920 else
2921 pThis->GCRDRA = (pThis->GCRDRA & 0x0000ffff) | ((val & 0x0000ffff) << 16);
2922 Log(("#%d: WRITE CSR%d, %#06x => GCRDRA=%08x (alt init)\n", PCNET_INST_NR, u32RAP, val, pThis->GCRDRA));
2923 break;
2924
2925 /*
2926 * 30 & 31 are the Base Address of Transmit Descriptor.
2927 * We combine and mirrorthese in GCTDRA.
2928 */
2929 case 30: /* BADXL */
2930 case 31: /* BADXU */
2931 if (!CSR_STOP(pThis) && !CSR_SPND(pThis))
2932 {
2933 Log(("#%d: WRITE CSR%d, %#06x !!\n", PCNET_INST_NR, u32RAP, val));
2934 return rc;
2935 }
2936 if (u32RAP == 30)
2937 pThis->GCTDRA = (pThis->GCTDRA & 0xffff0000) | (val & 0x0000ffff);
2938 else
2939 pThis->GCTDRA = (pThis->GCTDRA & 0x0000ffff) | ((val & 0x0000ffff) << 16);
2940 Log(("#%d: WRITE CSR%d, %#06x => GCTDRA=%08x (alt init)\n", PCNET_INST_NR, u32RAP, val, pThis->GCTDRA));
2941 break;
2942
2943 case 58: /* Software Style */
2944 rc = pcnetBCRWriteU16(pThis, BCR_SWS, val);
2945 break;
2946
2947 /*
2948 * Registers 76 and 78 aren't stored correctly (see todos), but I'm don't dare
2949 * try fix that right now. So, as a quick hack for 'alt init' I'll just correct them here.
2950 */
2951 case 76: /* RCVRL */ /** @todo call pcnetUpdateRingHandlers */
2952 /** @todo receive ring length is stored in two's complement! */
2953 case 78: /* XMTRL */ /** @todo call pcnetUpdateRingHandlers */
2954 /** @todo transmit ring length is stored in two's complement! */
2955 if (!CSR_STOP(pThis) && !CSR_SPND(pThis))
2956 {
2957 Log(("#%d: WRITE CSR%d, %#06x !!\n", PCNET_INST_NR, u32RAP, val));
2958 return rc;
2959 }
2960 Log(("#%d: WRITE CSR%d, %#06x (hacked %#06x) (alt init)\n", PCNET_INST_NR,
2961 u32RAP, val, 1 + ~(uint16_t)val));
2962 val = 1 + ~(uint16_t)val;
2963
2964 /*
2965 * HACK ALERT! Set the counter registers too.
2966 */
2967 pThis->aCSR[u32RAP - 4] = val;
2968 break;
2969
2970 default:
2971 return rc;
2972 }
2973 pThis->aCSR[u32RAP] = val;
2974 return rc;
2975}
2976
2977/**
2978 * Encode a 32-bit link speed into a custom 16-bit floating-point value
2979 */
2980static uint32_t pcnetLinkSpd(uint32_t speed)
2981{
2982 unsigned exp = 0;
2983
2984 while (speed & 0xFFFFE000)
2985 {
2986 speed /= 10;
2987 ++exp;
2988 }
2989 return (exp << 13) | speed;
2990}
2991
2992static uint32_t pcnetCSRReadU16(PCNetState *pThis, uint32_t u32RAP)
2993{
2994 uint32_t val;
2995 switch (u32RAP)
2996 {
2997 case 0:
2998 pcnetUpdateIrq(pThis);
2999 val = pThis->aCSR[0];
3000 val |= (val & 0x7800) ? 0x8000 : 0;
3001 pThis->u16CSR0LastSeenByGuest = val;
3002 break;
3003 case 16:
3004 return pcnetCSRReadU16(pThis, 1);
3005 case 17:
3006 return pcnetCSRReadU16(pThis, 2);
3007 case 58:
3008 return pcnetBCRReadU16(pThis, BCR_SWS);
3009 case 68: /* Custom register to pass link speed to driver */
3010 return pcnetLinkSpd(pThis->u32LinkSpeed);
3011 case 88:
3012 val = pThis->aCSR[89];
3013 val <<= 16;
3014 val |= pThis->aCSR[88];
3015 break;
3016 default:
3017 val = pThis->aCSR[u32RAP];
3018 }
3019#ifdef PCNET_DEBUG_CSR
3020 Log(("#%d pcnetCSRReadU16: rap=%d val=%#06x\n", PCNET_INST_NR, u32RAP, val));
3021#endif
3022 return val;
3023}
3024
3025static int pcnetBCRWriteU16(PCNetState *pThis, uint32_t u32RAP, uint32_t val)
3026{
3027 int rc = VINF_SUCCESS;
3028 u32RAP &= 0x7f;
3029#ifdef PCNET_DEBUG_BCR
3030 Log2(("#%d pcnetBCRWriteU16: rap=%d val=%#06x\n", PCNET_INST_NR, u32RAP, val));
3031#endif
3032 switch (u32RAP)
3033 {
3034 case BCR_SWS:
3035 if (!(CSR_STOP(pThis) || CSR_SPND(pThis)))
3036 return rc;
3037 val &= ~0x0300;
3038 switch (val & 0x00ff)
3039 {
3040 default:
3041 Log(("#%d Bad SWSTYLE=%#04x\n", PCNET_INST_NR, val & 0xff));
3042 // fall through
3043 case 0:
3044 val |= 0x0200; /* 16 bit */
3045 pThis->iLog2DescSize = 3;
3046 pThis->GCUpperPhys = (0xff00 & (uint32_t)pThis->aCSR[2]) << 16;
3047 break;
3048 case 1:
3049 val |= 0x0100; /* 32 bit */
3050 pThis->iLog2DescSize = 4;
3051 pThis->GCUpperPhys = 0;
3052 break;
3053 case 2:
3054 case 3:
3055 val |= 0x0300; /* 32 bit */
3056 pThis->iLog2DescSize = 4;
3057 pThis->GCUpperPhys = 0;
3058 break;
3059 }
3060 Log(("#%d BCR_SWS=%#06x\n", PCNET_INST_NR, val));
3061 pThis->aCSR[58] = val;
3062 /* fall through */
3063 case BCR_LNKST:
3064 case BCR_LED1:
3065 case BCR_LED2:
3066 case BCR_LED3:
3067 case BCR_MC:
3068 case BCR_FDC:
3069 case BCR_BSBC:
3070 case BCR_EECAS:
3071 case BCR_PLAT:
3072 case BCR_MIICAS:
3073 case BCR_MIIADDR:
3074 pThis->aBCR[u32RAP] = val;
3075 break;
3076
3077 case BCR_STVAL:
3078 val &= 0xffff;
3079 pThis->aBCR[BCR_STVAL] = val;
3080 if (pThis->fAm79C973)
3081 TMTimerSetNano(pThis->CTX_SUFF(pTimerSoftInt), 12800U * val);
3082 break;
3083
3084 case BCR_MIIMDR:
3085 pThis->aMII[pThis->aBCR[BCR_MIIADDR] & 0x1f] = val;
3086#ifdef PCNET_DEBUG_MII
3087 Log(("#%d pcnet: mii write %d <- %#x\n", PCNET_INST_NR, pThis->aBCR[BCR_MIIADDR] & 0x1f, val));
3088#endif
3089 break;
3090
3091 default:
3092 break;
3093 }
3094 return rc;
3095}
3096
3097static uint32_t pcnetMIIReadU16(PCNetState *pThis, uint32_t miiaddr)
3098{
3099 uint32_t val;
3100 bool autoneg, duplex, fast;
3101 STAM_COUNTER_INC(&pThis->StatMIIReads);
3102
3103 autoneg = (pThis->aBCR[BCR_MIICAS] & 0x20) != 0;
3104 duplex = (pThis->aBCR[BCR_MIICAS] & 0x10) != 0;
3105 fast = (pThis->aBCR[BCR_MIICAS] & 0x08) != 0;
3106
3107 switch (miiaddr)
3108 {
3109 case 0:
3110 /* MII basic mode control register. */
3111 val = 0;
3112 if (autoneg)
3113 val |= 0x1000; /* Enable auto negotiation. */
3114 if (fast)
3115 val |= 0x2000; /* 100 Mbps */
3116 if (duplex) /* Full duplex forced */
3117 val |= 0x0100; /* Full duplex */
3118 break;
3119
3120 case 1:
3121 /* MII basic mode status register. */
3122 val = 0x7800 /* Can do 100mbps FD/HD and 10mbps FD/HD. */
3123 | 0x0040 /* Mgmt frame preamble not required. */
3124 | 0x0020 /* Auto-negotiation complete. */
3125 | 0x0008 /* Able to do auto-negotiation. */
3126 | 0x0004 /* Link up. */
3127 | 0x0001; /* Extended Capability, i.e. registers 4+ valid. */
3128 if (!pThis->fLinkUp || pThis->fLinkTempDown) {
3129 val &= ~(0x0020 | 0x0004);
3130 pThis->cLinkDownReported++;
3131 }
3132 if (!autoneg) {
3133 /* Auto-negotiation disabled. */
3134 val &= ~(0x0020 | 0x0008);
3135 if (duplex)
3136 /* Full duplex forced. */
3137 val &= ~0x2800;
3138 else
3139 /* Half duplex forced. */
3140 val &= ~0x5000;
3141
3142 if (fast)
3143 /* 100 Mbps forced */
3144 val &= ~0x1800;
3145 else
3146 /* 10 Mbps forced */
3147 val &= ~0x6000;
3148 }
3149 break;
3150
3151 case 2:
3152 /* PHY identifier 1. */
3153 val = 0x22; /* Am79C874 PHY */
3154 break;
3155
3156 case 3:
3157 /* PHY identifier 2. */
3158 val = 0x561b; /* Am79C874 PHY */
3159 break;
3160
3161 case 4:
3162 /* Advertisement control register. */
3163 val = 0x01e0 /* Try 100mbps FD/HD and 10mbps FD/HD. */
3164#if 0
3165 // Advertising flow control is a) not the default, and b) confuses
3166 // the link speed detection routine in Windows PCnet driver
3167 | 0x0400 /* Try flow control. */
3168#endif
3169 | 0x0001; /* CSMA selector. */
3170 break;
3171
3172 case 5:
3173 /* Link partner ability register. */
3174 if (pThis->fLinkUp && !pThis->fLinkTempDown)
3175 val = 0x8000 /* Next page bit. */
3176 | 0x4000 /* Link partner acked us. */
3177 | 0x0400 /* Can do flow control. */
3178 | 0x01e0 /* Can do 100mbps FD/HD and 10mbps FD/HD. */
3179 | 0x0001; /* Use CSMA selector. */
3180 else
3181 {
3182 val = 0;
3183 pThis->cLinkDownReported++;
3184 }
3185 break;
3186
3187 case 6:
3188 /* Auto negotiation expansion register. */
3189 if (pThis->fLinkUp && !pThis->fLinkTempDown)
3190 val = 0x0008 /* Link partner supports npage. */
3191 | 0x0004 /* Enable npage words. */
3192 | 0x0001; /* Can do N-way auto-negotiation. */
3193 else
3194 {
3195 val = 0;
3196 pThis->cLinkDownReported++;
3197 }
3198 break;
3199
3200 default:
3201 val = 0;
3202 break;
3203 }
3204
3205#ifdef PCNET_DEBUG_MII
3206 Log(("#%d pcnet: mii read %d -> %#x\n", PCNET_INST_NR, miiaddr, val));
3207#endif
3208 return val;
3209}
3210
3211static uint32_t pcnetBCRReadU16(PCNetState *pThis, uint32_t u32RAP)
3212{
3213 uint32_t val;
3214 u32RAP &= 0x7f;
3215 switch (u32RAP)
3216 {
3217 case BCR_LNKST:
3218 case BCR_LED1:
3219 case BCR_LED2:
3220 case BCR_LED3:
3221 val = pThis->aBCR[u32RAP] & ~0x8000;
3222 /* Clear LNKSTE if we're not connected or if we've just loaded a VM state. */
3223 if (!pThis->pDrvR3 || pThis->fLinkTempDown || !pThis->fLinkUp)
3224 {
3225 if (u32RAP == 4)
3226 pThis->cLinkDownReported++;
3227 val &= ~0x40;
3228 }
3229 val |= (val & 0x017f & pThis->u32Lnkst) ? 0x8000 : 0;
3230 break;
3231
3232 case BCR_MIIMDR:
3233 if (pThis->fAm79C973 && (pThis->aBCR[BCR_MIIADDR] >> 5 & 0x1f) == 0)
3234 {
3235 uint32_t miiaddr = pThis->aBCR[BCR_MIIADDR] & 0x1f;
3236 val = pcnetMIIReadU16(pThis, miiaddr);
3237 }
3238 else
3239 val = 0xffff;
3240 break;
3241
3242 default:
3243 val = u32RAP < BCR_MAX_RAP ? pThis->aBCR[u32RAP] : 0;
3244 break;
3245 }
3246#ifdef PCNET_DEBUG_BCR
3247 Log2(("#%d pcnetBCRReadU16: rap=%d val=%#06x\n", PCNET_INST_NR, u32RAP, val));
3248#endif
3249 return val;
3250}
3251
3252#ifdef IN_RING3 /* move down */
3253static void pcnetHardReset(PCNetState *pThis)
3254{
3255 int i;
3256 uint16_t checksum;
3257
3258 /* Initialize the PROM */
3259 Assert(sizeof(pThis->MacConfigured) == 6);
3260 memcpy(pThis->aPROM, &pThis->MacConfigured, sizeof(pThis->MacConfigured));
3261 pThis->aPROM[ 8] = 0x00;
3262 pThis->aPROM[ 9] = 0x11;
3263 pThis->aPROM[12] = pThis->aPROM[13] = 0x00;
3264 pThis->aPROM[14] = pThis->aPROM[15] = 0x57;
3265
3266 for (i = 0, checksum = 0; i < 16; i++)
3267 checksum += pThis->aPROM[i];
3268 *(uint16_t *)&pThis->aPROM[12] = RT_H2LE_U16(checksum);
3269
3270 pThis->aBCR[BCR_MSRDA] = 0x0005;
3271 pThis->aBCR[BCR_MSWRA] = 0x0005;
3272 pThis->aBCR[BCR_MC ] = 0x0002;
3273 pThis->aBCR[BCR_LNKST] = 0x00c0;
3274 pThis->aBCR[BCR_LED1 ] = 0x0084;
3275 pThis->aBCR[BCR_LED2 ] = 0x0088;
3276 pThis->aBCR[BCR_LED3 ] = 0x0090;
3277 pThis->aBCR[BCR_FDC ] = 0x0000;
3278 pThis->aBCR[BCR_BSBC ] = 0x9001;
3279 pThis->aBCR[BCR_EECAS] = 0x0002;
3280 pThis->aBCR[BCR_STVAL] = 0xffff;
3281 pThis->aCSR[58 ] = /* CSR58 is an alias for BCR20 */
3282 pThis->aBCR[BCR_SWS ] = 0x0200;
3283 pThis->iLog2DescSize = 3;
3284 pThis->aBCR[BCR_PLAT ] = 0xff06;
3285 pThis->aBCR[BCR_MIIADDR ] = 0; /* Internal PHY on Am79C973 would be (0x1e << 5) */
3286 pThis->aBCR[BCR_PCIVID] = PCIDevGetVendorId(&pThis->PciDev);
3287 pThis->aBCR[BCR_PCISID] = PCIDevGetSubSystemId(&pThis->PciDev);
3288 pThis->aBCR[BCR_PCISVID] = PCIDevGetSubSystemVendorId(&pThis->PciDev);
3289
3290 /* Reset the error counter. */
3291 pThis->uCntBadRMD = 0;
3292
3293 pcnetSoftReset(pThis);
3294}
3295#endif /* IN_RING3 */
3296
3297static void pcnetAPROMWriteU8(PCNetState *pThis, uint32_t addr, uint32_t val)
3298{
3299 addr &= 0x0f;
3300 val &= 0xff;
3301 Log(("#%d pcnetAPROMWriteU8: addr=%#010x val=%#04x\n", PCNET_INST_NR, addr, val));
3302 /* Check APROMWE bit to enable write access */
3303 if (pcnetBCRReadU16(pThis, 2) & 0x80)
3304 pThis->aPROM[addr] = val;
3305}
3306
3307static uint32_t pcnetAPROMReadU8(PCNetState *pThis, uint32_t addr)
3308{
3309 uint32_t val = pThis->aPROM[addr &= 0x0f];
3310 Log(("#%d pcnetAPROMReadU8: addr=%#010x val=%#04x\n", PCNET_INST_NR, addr, val));
3311 return val;
3312}
3313
3314static int pcnetIoportWriteU8(PCNetState *pThis, uint32_t addr, uint32_t val)
3315{
3316 int rc = VINF_SUCCESS;
3317
3318#ifdef PCNET_DEBUG_IO
3319 Log2(("#%d pcnetIoportWriteU8: addr=%#010x val=%#06x\n", PCNET_INST_NR,
3320 addr, val));
3321#endif
3322 if (RT_LIKELY(!BCR_DWIO(pThis)))
3323 {
3324 switch (addr & 0x0f)
3325 {
3326 case 0x04: /* RESET */
3327 break;
3328 }
3329 }
3330 else
3331 Log(("#%d pcnetIoportWriteU8: addr=%#010x val=%#06x BCR_DWIO !!\n", PCNET_INST_NR, addr, val));
3332
3333 return rc;
3334}
3335
3336static uint32_t pcnetIoportReadU8(PCNetState *pThis, uint32_t addr, int *pRC)
3337{
3338 uint32_t val = ~0U;
3339
3340 *pRC = VINF_SUCCESS;
3341
3342 if (RT_LIKELY(!BCR_DWIO(pThis)))
3343 {
3344 switch (addr & 0x0f)
3345 {
3346 case 0x04: /* RESET */
3347 pcnetSoftReset(pThis);
3348 val = 0;
3349 break;
3350 }
3351 }
3352 else
3353 Log(("#%d pcnetIoportReadU8: addr=%#010x val=%#06x BCR_DWIO !!\n", PCNET_INST_NR, addr, val & 0xff));
3354
3355 pcnetUpdateIrq(pThis);
3356
3357#ifdef PCNET_DEBUG_IO
3358 Log2(("#%d pcnetIoportReadU8: addr=%#010x val=%#06x\n", PCNET_INST_NR, addr, val & 0xff));
3359#endif
3360 return val;
3361}
3362
3363static int pcnetIoportWriteU16(PCNetState *pThis, uint32_t addr, uint32_t val)
3364{
3365 int rc = VINF_SUCCESS;
3366
3367#ifdef PCNET_DEBUG_IO
3368 Log2(("#%d pcnetIoportWriteU16: addr=%#010x val=%#06x\n", PCNET_INST_NR,
3369 addr, val));
3370#endif
3371 if (RT_LIKELY(!BCR_DWIO(pThis)))
3372 {
3373 switch (addr & 0x0f)
3374 {
3375 case 0x00: /* RDP */
3376 pcnetPollTimer(pThis);
3377 rc = pcnetCSRWriteU16(pThis, pThis->u32RAP, val);
3378 pcnetUpdateIrq(pThis);
3379 break;
3380 case 0x02: /* RAP */
3381 pThis->u32RAP = val & 0x7f;
3382 break;
3383 case 0x06: /* BDP */
3384 rc = pcnetBCRWriteU16(pThis, pThis->u32RAP, val);
3385 break;
3386 }
3387 }
3388 else
3389 Log(("#%d pcnetIoportWriteU16: addr=%#010x val=%#06x BCR_DWIO !!\n", PCNET_INST_NR, addr, val));
3390
3391 return rc;
3392}
3393
3394static uint32_t pcnetIoportReadU16(PCNetState *pThis, uint32_t addr, int *pRC)
3395{
3396 uint32_t val = ~0U;
3397
3398 *pRC = VINF_SUCCESS;
3399
3400 if (RT_LIKELY(!BCR_DWIO(pThis)))
3401 {
3402 switch (addr & 0x0f)
3403 {
3404 case 0x00: /* RDP */
3405 /** @note if we're not polling, then the guest will tell us when to poll by setting TDMD in CSR0 */
3406 /** Polling is then useless here and possibly expensive. */
3407 if (!CSR_DPOLL(pThis))
3408 pcnetPollTimer(pThis);
3409
3410 val = pcnetCSRReadU16(pThis, pThis->u32RAP);
3411 if (pThis->u32RAP == 0) // pcnetUpdateIrq() already called by pcnetCSRReadU16()
3412 goto skip_update_irq;
3413 break;
3414 case 0x02: /* RAP */
3415 val = pThis->u32RAP;
3416 goto skip_update_irq;
3417 case 0x04: /* RESET */
3418 pcnetSoftReset(pThis);
3419 val = 0;
3420 break;
3421 case 0x06: /* BDP */
3422 val = pcnetBCRReadU16(pThis, pThis->u32RAP);
3423 break;
3424 }
3425 }
3426 else
3427 Log(("#%d pcnetIoportReadU16: addr=%#010x val=%#06x BCR_DWIO !!\n", PCNET_INST_NR, addr, val & 0xffff));
3428
3429 pcnetUpdateIrq(pThis);
3430
3431skip_update_irq:
3432#ifdef PCNET_DEBUG_IO
3433 Log2(("#%d pcnetIoportReadU16: addr=%#010x val=%#06x\n", PCNET_INST_NR, addr, val & 0xffff));
3434#endif
3435 return val;
3436}
3437
3438static int pcnetIoportWriteU32(PCNetState *pThis, uint32_t addr, uint32_t val)
3439{
3440 int rc = VINF_SUCCESS;
3441
3442#ifdef PCNET_DEBUG_IO
3443 Log2(("#%d pcnetIoportWriteU32: addr=%#010x val=%#010x\n", PCNET_INST_NR,
3444 addr, val));
3445#endif
3446 if (RT_LIKELY(BCR_DWIO(pThis)))
3447 {
3448 switch (addr & 0x0f)
3449 {
3450 case 0x00: /* RDP */
3451 pcnetPollTimer(pThis);
3452 rc = pcnetCSRWriteU16(pThis, pThis->u32RAP, val & 0xffff);
3453 pcnetUpdateIrq(pThis);
3454 break;
3455 case 0x04: /* RAP */
3456 pThis->u32RAP = val & 0x7f;
3457 break;
3458 case 0x0c: /* BDP */
3459 rc = pcnetBCRWriteU16(pThis, pThis->u32RAP, val & 0xffff);
3460 break;
3461 }
3462 }
3463 else if ((addr & 0x0f) == 0)
3464 {
3465 /* switch device to dword I/O mode */
3466 pcnetBCRWriteU16(pThis, BCR_BSBC, pcnetBCRReadU16(pThis, BCR_BSBC) | 0x0080);
3467#ifdef PCNET_DEBUG_IO
3468 Log2(("device switched into dword i/o mode\n"));
3469#endif
3470 }
3471 else
3472 Log(("#%d pcnetIoportWriteU32: addr=%#010x val=%#010x !BCR_DWIO !!\n", PCNET_INST_NR, addr, val));
3473
3474 return rc;
3475}
3476
3477static uint32_t pcnetIoportReadU32(PCNetState *pThis, uint32_t addr, int *pRC)
3478{
3479 uint32_t val = ~0U;
3480
3481 *pRC = VINF_SUCCESS;
3482
3483 if (RT_LIKELY(BCR_DWIO(pThis)))
3484 {
3485 switch (addr & 0x0f)
3486 {
3487 case 0x00: /* RDP */
3488 /** @note if we're not polling, then the guest will tell us when to poll by setting TDMD in CSR0 */
3489 /** Polling is then useless here and possibly expensive. */
3490 if (!CSR_DPOLL(pThis))
3491 pcnetPollTimer(pThis);
3492
3493 val = pcnetCSRReadU16(pThis, pThis->u32RAP);
3494 if (pThis->u32RAP == 0) // pcnetUpdateIrq() already called by pcnetCSRReadU16()
3495 goto skip_update_irq;
3496 break;
3497 case 0x04: /* RAP */
3498 val = pThis->u32RAP;
3499 goto skip_update_irq;
3500 case 0x08: /* RESET */
3501 pcnetSoftReset(pThis);
3502 val = 0;
3503 break;
3504 case 0x0c: /* BDP */
3505 val = pcnetBCRReadU16(pThis, pThis->u32RAP);
3506 break;
3507 }
3508 }
3509 else
3510 Log(("#%d pcnetIoportReadU32: addr=%#010x val=%#010x !BCR_DWIO !!\n", PCNET_INST_NR, addr, val));
3511 pcnetUpdateIrq(pThis);
3512
3513skip_update_irq:
3514#ifdef PCNET_DEBUG_IO
3515 Log2(("#%d pcnetIoportReadU32: addr=%#010x val=%#010x\n", PCNET_INST_NR, addr, val));
3516#endif
3517 return val;
3518}
3519
3520static void pcnetMMIOWriteU8(PCNetState *pThis, RTGCPHYS addr, uint32_t val)
3521{
3522#ifdef PCNET_DEBUG_IO
3523 Log2(("#%d pcnetMMIOWriteU8: addr=%#010x val=%#04x\n", PCNET_INST_NR, addr, val));
3524#endif
3525 if (!(addr & 0x10))
3526 pcnetAPROMWriteU8(pThis, addr, val);
3527}
3528
3529static uint32_t pcnetMMIOReadU8(PCNetState *pThis, RTGCPHYS addr)
3530{
3531 uint32_t val = ~0U;
3532 if (!(addr & 0x10))
3533 val = pcnetAPROMReadU8(pThis, addr);
3534#ifdef PCNET_DEBUG_IO
3535 Log2(("#%d pcnetMMIOReadU8: addr=%#010x val=%#04x\n", PCNET_INST_NR, addr, val & 0xff));
3536#endif
3537 return val;
3538}
3539
3540static void pcnetMMIOWriteU16(PCNetState *pThis, RTGCPHYS addr, uint32_t val)
3541{
3542#ifdef PCNET_DEBUG_IO
3543 Log2(("#%d pcnetMMIOWriteU16: addr=%#010x val=%#06x\n", PCNET_INST_NR, addr, val));
3544#endif
3545 if (addr & 0x10)
3546 pcnetIoportWriteU16(pThis, addr & 0x0f, val);
3547 else
3548 {
3549 pcnetAPROMWriteU8(pThis, addr, val );
3550 pcnetAPROMWriteU8(pThis, addr+1, val >> 8);
3551 }
3552}
3553
3554static uint32_t pcnetMMIOReadU16(PCNetState *pThis, RTGCPHYS addr)
3555{
3556 uint32_t val = ~0U;
3557 int rc;
3558
3559 if (addr & 0x10)
3560 val = pcnetIoportReadU16(pThis, addr & 0x0f, &rc);
3561 else
3562 {
3563 val = pcnetAPROMReadU8(pThis, addr+1);
3564 val <<= 8;
3565 val |= pcnetAPROMReadU8(pThis, addr);
3566 }
3567#ifdef PCNET_DEBUG_IO
3568 Log2(("#%d pcnetMMIOReadU16: addr=%#010x val = %#06x\n", PCNET_INST_NR, addr, val & 0xffff));
3569#endif
3570 return val;
3571}
3572
3573static void pcnetMMIOWriteU32(PCNetState *pThis, RTGCPHYS addr, uint32_t val)
3574{
3575#ifdef PCNET_DEBUG_IO
3576 Log2(("#%d pcnetMMIOWriteU32: addr=%#010x val=%#010x\n", PCNET_INST_NR, addr, val));
3577#endif
3578 if (addr & 0x10)
3579 pcnetIoportWriteU32(pThis, addr & 0x0f, val);
3580 else
3581 {
3582 pcnetAPROMWriteU8(pThis, addr, val );
3583 pcnetAPROMWriteU8(pThis, addr+1, val >> 8);
3584 pcnetAPROMWriteU8(pThis, addr+2, val >> 16);
3585 pcnetAPROMWriteU8(pThis, addr+3, val >> 24);
3586 }
3587}
3588
3589static uint32_t pcnetMMIOReadU32(PCNetState *pThis, RTGCPHYS addr)
3590{
3591 uint32_t val;
3592 int rc;
3593
3594 if (addr & 0x10)
3595 val = pcnetIoportReadU32(pThis, addr & 0x0f, &rc);
3596 else
3597 {
3598 val = pcnetAPROMReadU8(pThis, addr+3);
3599 val <<= 8;
3600 val |= pcnetAPROMReadU8(pThis, addr+2);
3601 val <<= 8;
3602 val |= pcnetAPROMReadU8(pThis, addr+1);
3603 val <<= 8;
3604 val |= pcnetAPROMReadU8(pThis, addr );
3605 }
3606#ifdef PCNET_DEBUG_IO
3607 Log2(("#%d pcnetMMIOReadU32: addr=%#010x val=%#010x\n", PCNET_INST_NR, addr, val));
3608#endif
3609 return val;
3610}
3611
3612
3613/**
3614 * Port I/O Handler for IN operations.
3615 *
3616 * @returns VBox status code.
3617 *
3618 * @param pDevIns The device instance.
3619 * @param pvUser User argument.
3620 * @param Port Port number used for the IN operation.
3621 * @param pu32 Where to store the result.
3622 * @param cb Number of bytes read.
3623 */
3624PDMBOTHCBDECL(int) pcnetIOPortAPromRead(PPDMDEVINS pDevIns, void *pvUser,
3625 RTIOPORT Port, uint32_t *pu32, unsigned cb)
3626{
3627 PCNetState *pThis = PDMINS_2_DATA(pDevIns, PCNetState *);
3628 int rc;
3629
3630 STAM_PROFILE_ADV_START(&pThis->StatAPROMRead, a);
3631 rc = PDMCritSectEnter(&pThis->CritSect, VINF_IOM_HC_IOPORT_WRITE);
3632 if (rc == VINF_SUCCESS)
3633 {
3634
3635 /* FreeBSD is accessing in dwords. */
3636 if (cb == 1)
3637 *pu32 = pcnetAPROMReadU8(pThis, Port);
3638 else if (cb == 2 && !BCR_DWIO(pThis))
3639 *pu32 = pcnetAPROMReadU8(pThis, Port)
3640 | (pcnetAPROMReadU8(pThis, Port + 1) << 8);
3641 else if (cb == 4 && BCR_DWIO(pThis))
3642 *pu32 = pcnetAPROMReadU8(pThis, Port)
3643 | (pcnetAPROMReadU8(pThis, Port + 1) << 8)
3644 | (pcnetAPROMReadU8(pThis, Port + 2) << 16)
3645 | (pcnetAPROMReadU8(pThis, Port + 3) << 24);
3646 else
3647 {
3648 Log(("#%d pcnetIOPortAPromRead: Port=%RTiop cb=%d BCR_DWIO !!\n", PCNET_INST_NR, Port, cb));
3649 rc = VERR_IOM_IOPORT_UNUSED;
3650 }
3651 PDMCritSectLeave(&pThis->CritSect);
3652 }
3653 STAM_PROFILE_ADV_STOP(&pThis->StatAPROMRead, a);
3654 LogFlow(("#%d pcnetIOPortAPromRead: Port=%RTiop *pu32=%#RX32 cb=%d rc=%Rrc\n", PCNET_INST_NR, Port, *pu32, cb, rc));
3655 return rc;
3656}
3657
3658
3659/**
3660 * Port I/O Handler for OUT operations.
3661 *
3662 * @returns VBox status code.
3663 *
3664 * @param pDevIns The device instance.
3665 * @param pvUser User argument.
3666 * @param Port Port number used for the IN operation.
3667 * @param u32 The value to output.
3668 * @param cb The value size in bytes.
3669 */
3670PDMBOTHCBDECL(int) pcnetIOPortAPromWrite(PPDMDEVINS pDevIns, void *pvUser,
3671 RTIOPORT Port, uint32_t u32, unsigned cb)
3672{
3673 PCNetState *pThis = PDMINS_2_DATA(pDevIns, PCNetState *);
3674 int rc;
3675
3676 if (cb == 1)
3677 {
3678 STAM_PROFILE_ADV_START(&pThis->StatAPROMWrite, a);
3679 rc = PDMCritSectEnter(&pThis->CritSect, VINF_IOM_HC_IOPORT_WRITE);
3680 if (RT_LIKELY(rc == VINF_SUCCESS))
3681 {
3682 pcnetAPROMWriteU8(pThis, Port, u32);
3683 PDMCritSectLeave(&pThis->CritSect);
3684 }
3685 STAM_PROFILE_ADV_STOP(&pThis->StatAPROMWrite, a);
3686 }
3687 else
3688 {
3689 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
3690 rc = VINF_SUCCESS;
3691 }
3692 LogFlow(("#%d pcnetIOPortAPromWrite: Port=%RTiop u32=%#RX32 cb=%d rc=%Rrc\n", PCNET_INST_NR, Port, u32, cb, rc));
3693#ifdef LOG_ENABLED
3694 if (rc == VINF_IOM_HC_IOPORT_WRITE)
3695 LogFlow(("#%d => HC\n", PCNET_INST_NR));
3696#endif
3697 return rc;
3698}
3699
3700
3701/**
3702 * Port I/O Handler for IN operations.
3703 *
3704 * @returns VBox status code.
3705 *
3706 * @param pDevIns The device instance.
3707 * @param pvUser User argument.
3708 * @param Port Port number used for the IN operation.
3709 * @param pu32 Where to store the result.
3710 * @param cb Number of bytes read.
3711 */
3712PDMBOTHCBDECL(int) pcnetIOPortRead(PPDMDEVINS pDevIns, void *pvUser,
3713 RTIOPORT Port, uint32_t *pu32, unsigned cb)
3714{
3715 PCNetState *pThis = PDMINS_2_DATA(pDevIns, PCNetState *);
3716 int rc = VINF_SUCCESS;
3717
3718 STAM_PROFILE_ADV_START(&pThis->CTXSUFF(StatIORead), a);
3719 rc = PDMCritSectEnter(&pThis->CritSect, VINF_IOM_HC_IOPORT_READ);
3720 if (RT_LIKELY(rc == VINF_SUCCESS))
3721 {
3722 switch (cb)
3723 {
3724 case 1: *pu32 = pcnetIoportReadU8(pThis, Port, &rc); break;
3725 case 2: *pu32 = pcnetIoportReadU16(pThis, Port, &rc); break;
3726 case 4: *pu32 = pcnetIoportReadU32(pThis, Port, &rc); break;
3727 default:
3728 rc = PDMDevHlpDBGFStop(pThis->CTX_SUFF(pDevIns), RT_SRC_POS,
3729 "pcnetIOPortRead: unsupported op size: offset=%#10x cb=%u\n",
3730 Port, cb);
3731 }
3732 PDMCritSectLeave(&pThis->CritSect);
3733 }
3734 STAM_PROFILE_ADV_STOP(&pThis->CTXSUFF(StatIORead), a);
3735 Log2(("#%d pcnetIOPortRead: Port=%RTiop *pu32=%#RX32 cb=%d rc=%Rrc\n", PCNET_INST_NR, Port, *pu32, cb, rc));
3736#ifdef LOG_ENABLED
3737 if (rc == VINF_IOM_HC_IOPORT_READ)
3738 LogFlow(("#%d pcnetIOPortRead/critsect failed in GC => HC\n", PCNET_INST_NR));
3739#endif
3740 return rc;
3741}
3742
3743
3744/**
3745 * Port I/O Handler for OUT operations.
3746 *
3747 * @returns VBox status code.
3748 *
3749 * @param pDevIns The device instance.
3750 * @param pvUser User argument.
3751 * @param Port Port number used for the IN operation.
3752 * @param u32 The value to output.
3753 * @param cb The value size in bytes.
3754 */
3755PDMBOTHCBDECL(int) pcnetIOPortWrite(PPDMDEVINS pDevIns, void *pvUser,
3756 RTIOPORT Port, uint32_t u32, unsigned cb)
3757{
3758 PCNetState *pThis = PDMINS_2_DATA(pDevIns, PCNetState *);
3759 int rc = VINF_SUCCESS;
3760
3761 STAM_PROFILE_ADV_START(&pThis->CTXSUFF(StatIOWrite), a);
3762 rc = PDMCritSectEnter(&pThis->CritSect, VINF_IOM_HC_IOPORT_WRITE);
3763 if (RT_LIKELY(rc == VINF_SUCCESS))
3764 {
3765 switch (cb)
3766 {
3767 case 1: rc = pcnetIoportWriteU8(pThis, Port, u32); break;
3768 case 2: rc = pcnetIoportWriteU16(pThis, Port, u32); break;
3769 case 4: rc = pcnetIoportWriteU32(pThis, Port, u32); break;
3770 default:
3771 rc = PDMDevHlpDBGFStop(pThis->CTX_SUFF(pDevIns), RT_SRC_POS,
3772 "pcnetIOPortWrite: unsupported op size: offset=%#10x cb=%u\n",
3773 Port, cb);
3774 }
3775 PDMCritSectLeave(&pThis->CritSect);
3776 }
3777 STAM_PROFILE_ADV_STOP(&pThis->CTXSUFF(StatIOWrite), a);
3778 Log2(("#%d pcnetIOPortWrite: Port=%RTiop u32=%#RX32 cb=%d rc=%Rrc\n", PCNET_INST_NR, Port, u32, cb, rc));
3779#ifdef LOG_ENABLED
3780 if (rc == VINF_IOM_HC_IOPORT_WRITE)
3781 LogFlow(("#%d pcnetIOPortWrite/critsect failed in GC => HC\n", PCNET_INST_NR));
3782#endif
3783 return rc;
3784}
3785
3786
3787/**
3788 * Memory mapped I/O Handler for read operations.
3789 *
3790 * @returns VBox status code.
3791 *
3792 * @param pDevIns The device instance.
3793 * @param pvUser User argument.
3794 * @param GCPhysAddr Physical address (in GC) where the read starts.
3795 * @param pv Where to store the result.
3796 * @param cb Number of bytes read.
3797 */
3798PDMBOTHCBDECL(int) pcnetMMIORead(PPDMDEVINS pDevIns, void *pvUser,
3799 RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
3800{
3801 PCNetState *pThis = (PCNetState *)pvUser;
3802 int rc = VINF_SUCCESS;
3803
3804 /*
3805 * We have to check the range, because we're page aligning the MMIO stuff presently.
3806 */
3807 if (GCPhysAddr - pThis->MMIOBase < PCNET_PNPMMIO_SIZE)
3808 {
3809 STAM_PROFILE_ADV_START(&pThis->CTXSUFF(StatMMIORead), a);
3810 rc = PDMCritSectEnter(&pThis->CritSect, VINF_IOM_HC_MMIO_READ);
3811 if (RT_LIKELY(rc == VINF_SUCCESS))
3812 {
3813 switch (cb)
3814 {
3815 case 1: *(uint8_t *)pv = pcnetMMIOReadU8 (pThis, GCPhysAddr); break;
3816 case 2: *(uint16_t *)pv = pcnetMMIOReadU16(pThis, GCPhysAddr); break;
3817 case 4: *(uint32_t *)pv = pcnetMMIOReadU32(pThis, GCPhysAddr); break;
3818 default:
3819 rc = PDMDevHlpDBGFStop(pThis->CTX_SUFF(pDevIns), RT_SRC_POS,
3820 "pcnetMMIORead: unsupported op size: address=%RGp cb=%u\n",
3821 GCPhysAddr, cb);
3822 }
3823 PDMCritSectLeave(&pThis->CritSect);
3824 }
3825 STAM_PROFILE_ADV_STOP(&pThis->CTXSUFF(StatMMIORead), a);
3826 }
3827 else
3828 memset(pv, 0, cb);
3829
3830 LogFlow(("#%d pcnetMMIORead: pvUser=%p:{%.*Rhxs} cb=%d GCPhysAddr=%RGp rc=%Rrc\n",
3831 PCNET_INST_NR, pv, cb, pv, cb, GCPhysAddr, rc));
3832#ifdef LOG_ENABLED
3833 if (rc == VINF_IOM_HC_MMIO_READ)
3834 LogFlow(("#%d => HC\n", PCNET_INST_NR));
3835#endif
3836 return rc;
3837}
3838
3839
3840/**
3841 * Port I/O Handler for write operations.
3842 *
3843 * @returns VBox status code.
3844 *
3845 * @param pDevIns The device instance.
3846 * @param pvUser User argument.
3847 * @param GCPhysAddr Physical address (in GC) where the read starts.
3848 * @param pv Where to fetch the result.
3849 * @param cb Number of bytes to write.
3850 */
3851PDMBOTHCBDECL(int) pcnetMMIOWrite(PPDMDEVINS pDevIns, void *pvUser,
3852 RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
3853{
3854 PCNetState *pThis = (PCNetState *)pvUser;
3855 int rc = VINF_SUCCESS;
3856
3857 /*
3858 * We have to check the range, because we're page aligning the MMIO stuff presently.
3859 */
3860 if (GCPhysAddr - pThis->MMIOBase < PCNET_PNPMMIO_SIZE)
3861 {
3862 STAM_PROFILE_ADV_START(&pThis->CTXSUFF(StatMMIOWrite), a);
3863 rc = PDMCritSectEnter(&pThis->CritSect, VINF_IOM_HC_MMIO_WRITE);
3864 if (RT_LIKELY(rc == VINF_SUCCESS))
3865 {
3866 switch (cb)
3867 {
3868 case 1: pcnetMMIOWriteU8 (pThis, GCPhysAddr, *(uint8_t *)pv); break;
3869 case 2: pcnetMMIOWriteU16(pThis, GCPhysAddr, *(uint16_t *)pv); break;
3870 case 4: pcnetMMIOWriteU32(pThis, GCPhysAddr, *(uint32_t *)pv); break;
3871 default:
3872 rc = PDMDevHlpDBGFStop(pThis->CTX_SUFF(pDevIns), RT_SRC_POS,
3873 "pcnetMMIOWrite: unsupported op size: address=%RGp cb=%u\n",
3874 GCPhysAddr, cb);
3875 }
3876 PDMCritSectLeave(&pThis->CritSect);
3877 }
3878 // else rc == VINF_IOM_HC_MMIO_WRITE => handle in ring3
3879
3880 STAM_PROFILE_ADV_STOP(&pThis->CTXSUFF(StatMMIOWrite), a);
3881 }
3882 LogFlow(("#%d pcnetMMIOWrite: pvUser=%p:{%.*Rhxs} cb=%d GCPhysAddr=%RGp rc=%Rrc\n",
3883 PCNET_INST_NR, pv, cb, pv, cb, GCPhysAddr, rc));
3884#ifdef LOG_ENABLED
3885 if (rc == VINF_IOM_HC_MMIO_WRITE)
3886 LogFlow(("#%d => HC\n", PCNET_INST_NR));
3887#endif
3888 return rc;
3889}
3890
3891
3892#ifdef IN_RING3
3893/**
3894 * Device timer callback function.
3895 *
3896 * @param pDevIns Device instance of the device which registered the timer.
3897 * @param pTimer The timer handle.
3898 * @thread EMT
3899 */
3900static DECLCALLBACK(void) pcnetTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
3901{
3902 PCNetState *pThis = (PCNetState *)pvUser;
3903 STAM_PROFILE_ADV_START(&pThis->StatTimer, a);
3904 pcnetPollTimer(pThis);
3905 STAM_PROFILE_ADV_STOP(&pThis->StatTimer, a);
3906}
3907
3908
3909/**
3910 * Software interrupt timer callback function.
3911 *
3912 * @param pDevIns Device instance of the device which registered the timer.
3913 * @param pTimer The timer handle.
3914 * @thread EMT
3915 */
3916static DECLCALLBACK(void) pcnetTimerSoftInt(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
3917{
3918 PCNetState *pThis = (PCNetState *)pvUser;
3919
3920/** @todo why aren't we taking any critsect here?!? */
3921 pThis->aCSR[7] |= 0x0800; /* STINT */
3922 pcnetUpdateIrq(pThis);
3923 TMTimerSetNano(pThis->CTX_SUFF(pTimerSoftInt), 12800U * (pThis->aBCR[BCR_STVAL] & 0xffff));
3924}
3925
3926
3927/**
3928 * Restore timer callback.
3929 *
3930 * This is only called when've restored a saved state and temporarily
3931 * disconnected the network link to inform the guest that network connections
3932 * should be considered lost.
3933 *
3934 * @param pDevIns Device instance of the device which registered the timer.
3935 * @param pTimer The timer handle.
3936 */
3937static DECLCALLBACK(void) pcnetTimerRestore(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
3938{
3939 PCNetState *pThis = PDMINS_2_DATA(pDevIns, PCNetState *);
3940 int rc = PDMCritSectEnter(&pThis->CritSect, VERR_SEM_BUSY);
3941 AssertReleaseRC(rc);
3942
3943 rc = VERR_GENERAL_FAILURE;
3944 if (pThis->cLinkDownReported <= PCNET_MAX_LINKDOWN_REPORTED)
3945 rc = TMTimerSetMillies(pThis->pTimerRestore, 1500);
3946 if (RT_FAILURE(rc))
3947 {
3948 pThis->fLinkTempDown = false;
3949 if (pThis->fLinkUp)
3950 {
3951 LogRel(("PCNet#%d: The link is back up again after the restore.\n",
3952 pDevIns->iInstance));
3953 Log(("#%d pcnetTimerRestore: Clearing ERR and CERR after load. cLinkDownReported=%d\n",
3954 pDevIns->iInstance, pThis->cLinkDownReported));
3955 pThis->aCSR[0] &= ~(RT_BIT(15) | RT_BIT(13)); /* ERR | CERR - probably not 100% correct either... */
3956 pThis->Led.Actual.s.fError = 0;
3957 }
3958 }
3959 else
3960 Log(("#%d pcnetTimerRestore: cLinkDownReported=%d, wait another 1500ms...\n",
3961 pDevIns->iInstance, pThis->cLinkDownReported));
3962
3963 PDMCritSectLeave(&pThis->CritSect);
3964}
3965
3966/**
3967 * Callback function for mapping an PCI I/O region.
3968 *
3969 * @return VBox status code.
3970 * @param pPciDev Pointer to PCI device. Use pPciDev->pDevIns to get the device instance.
3971 * @param iRegion The region number.
3972 * @param GCPhysAddress Physical address of the region. If iType is PCI_ADDRESS_SPACE_IO, this is an
3973 * I/O port, else it's a physical address.
3974 * This address is *NOT* relative to pci_mem_base like earlier!
3975 * @param cb Region size.
3976 * @param enmType One of the PCI_ADDRESS_SPACE_* values.
3977 */
3978static DECLCALLBACK(int) pcnetIOPortMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion,
3979 RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
3980{
3981 int rc;
3982 PPDMDEVINS pDevIns = pPciDev->pDevIns;
3983 RTIOPORT Port = (RTIOPORT)GCPhysAddress;
3984 PCNetState *pThis = PCIDEV_2_PCNETSTATE(pPciDev);
3985
3986 Assert(enmType == PCI_ADDRESS_SPACE_IO);
3987 Assert(cb >= 0x20);
3988
3989 rc = PDMDevHlpIOPortRegister(pDevIns, Port, 0x10, 0, pcnetIOPortAPromWrite,
3990 pcnetIOPortAPromRead, NULL, NULL, "PCNet ARPOM");
3991 if (RT_FAILURE(rc))
3992 return rc;
3993 rc = PDMDevHlpIOPortRegister(pDevIns, Port + 0x10, 0x10, 0, pcnetIOPortWrite,
3994 pcnetIOPortRead, NULL, NULL, "PCNet");
3995 if (RT_FAILURE(rc))
3996 return rc;
3997
3998 if (pThis->fGCEnabled)
3999 {
4000 rc = PDMDevHlpIOPortRegisterRC(pDevIns, Port, 0x10, 0, "pcnetIOPortAPromWrite",
4001 "pcnetIOPortAPromRead", NULL, NULL, "PCNet aprom");
4002 if (RT_FAILURE(rc))
4003 return rc;
4004 rc = PDMDevHlpIOPortRegisterRC(pDevIns, Port + 0x10, 0x10, 0, "pcnetIOPortWrite",
4005 "pcnetIOPortRead", NULL, NULL, "PCNet");
4006 if (RT_FAILURE(rc))
4007 return rc;
4008 }
4009 if (pThis->fR0Enabled)
4010 {
4011 rc = PDMDevHlpIOPortRegisterR0(pDevIns, Port, 0x10, 0, "pcnetIOPortAPromWrite",
4012 "pcnetIOPortAPromRead", NULL, NULL, "PCNet aprom");
4013 if (RT_FAILURE(rc))
4014 return rc;
4015 rc = PDMDevHlpIOPortRegisterR0(pDevIns, Port + 0x10, 0x10, 0, "pcnetIOPortWrite",
4016 "pcnetIOPortRead", NULL, NULL, "PCNet");
4017 if (RT_FAILURE(rc))
4018 return rc;
4019 }
4020
4021 pThis->IOPortBase = Port;
4022 return VINF_SUCCESS;
4023}
4024
4025
4026/**
4027 * Callback function for mapping the MMIO region.
4028 *
4029 * @return VBox status code.
4030 * @param pPciDev Pointer to PCI device. Use pPciDev->pDevIns to get the device instance.
4031 * @param iRegion The region number.
4032 * @param GCPhysAddress Physical address of the region. If iType is PCI_ADDRESS_SPACE_IO, this is an
4033 * I/O port, else it's a physical address.
4034 * This address is *NOT* relative to pci_mem_base like earlier!
4035 * @param cb Region size.
4036 * @param enmType One of the PCI_ADDRESS_SPACE_* values.
4037 */
4038static DECLCALLBACK(int) pcnetMMIOMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion,
4039 RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
4040{
4041 PCNetState *pThis = PCIDEV_2_PCNETSTATE(pPciDev);
4042 int rc;
4043
4044 Assert(enmType == PCI_ADDRESS_SPACE_MEM);
4045 Assert(cb >= PCNET_PNPMMIO_SIZE);
4046
4047 /* We use the assigned size here, because we currently only support page aligned MMIO ranges. */
4048 rc = PDMDevHlpMMIORegister(pPciDev->pDevIns, GCPhysAddress, cb, pThis,
4049 pcnetMMIOWrite, pcnetMMIORead, NULL, "PCNet");
4050 if (RT_FAILURE(rc))
4051 return rc;
4052 pThis->MMIOBase = GCPhysAddress;
4053 return rc;
4054}
4055
4056
4057/**
4058 * Callback function for mapping the MMIO region.
4059 *
4060 * @return VBox status code.
4061 * @param pPciDev Pointer to PCI device. Use pPciDev->pDevIns to get the device instance.
4062 * @param iRegion The region number.
4063 * @param GCPhysAddress Physical address of the region. If iType is PCI_ADDRESS_SPACE_IO, this is an
4064 * I/O port, else it's a physical address.
4065 * This address is *NOT* relative to pci_mem_base like earlier!
4066 * @param cb Region size.
4067 * @param enmType One of the PCI_ADDRESS_SPACE_* values.
4068 */
4069static DECLCALLBACK(int) pcnetMMIOSharedMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion,
4070 RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
4071{
4072 if (GCPhysAddress != NIL_RTGCPHYS)
4073 return PDMDevHlpMMIO2Map(pPciDev->pDevIns, iRegion, GCPhysAddress);
4074
4075 /* nothing to clean up */
4076 return VINF_SUCCESS;
4077}
4078
4079
4080/**
4081 * PCNET status info callback.
4082 *
4083 * @param pDevIns The device instance.
4084 * @param pHlp The output helpers.
4085 * @param pszArgs The arguments.
4086 */
4087static DECLCALLBACK(void) pcnetInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
4088{
4089 PCNetState *pThis = PDMINS_2_DATA(pDevIns, PCNetState *);
4090 bool fRcvRing = false;
4091 bool fXmtRing = false;
4092
4093 /*
4094 * Parse args.
4095 */
4096 if (pszArgs)
4097 {
4098 fRcvRing = strstr(pszArgs, "verbose") || strstr(pszArgs, "rcv");
4099 fXmtRing = strstr(pszArgs, "verbose") || strstr(pszArgs, "xmt");
4100 }
4101
4102 /*
4103 * Show info.
4104 */
4105 pHlp->pfnPrintf(pHlp,
4106 "pcnet #%d: port=%RTiop mmio=%RX32 mac-cfg=%RTmac %s\n",
4107 pDevIns->iInstance,
4108 pThis->IOPortBase, pThis->MMIOBase, &pThis->MacConfigured,
4109 pThis->fAm79C973 ? "Am79C973" : "Am79C970A", pThis->fGCEnabled ? " GC" : "", pThis->fR0Enabled ? " R0" : "");
4110
4111 PDMCritSectEnter(&pThis->CritSect, VERR_INTERNAL_ERROR); /* Take it here so we know why we're hanging... */
4112
4113 pHlp->pfnPrintf(pHlp,
4114 "CSR0=%#06x:\n",
4115 pThis->aCSR[0]);
4116
4117 pHlp->pfnPrintf(pHlp,
4118 "CSR1=%#06x:\n",
4119 pThis->aCSR[1]);
4120
4121 pHlp->pfnPrintf(pHlp,
4122 "CSR2=%#06x:\n",
4123 pThis->aCSR[2]);
4124
4125 pHlp->pfnPrintf(pHlp,
4126 "CSR3=%#06x: BSWP=%d EMBA=%d DXMT2PD=%d LAPPEN=%d DXSUFLO=%d IDONM=%d TINTM=%d RINTM=%d MERRM=%d MISSM=%d BABLM=%d\n",
4127 pThis->aCSR[3],
4128 !!(pThis->aCSR[3] & RT_BIT(2)), !!(pThis->aCSR[3] & RT_BIT(3)), !!(pThis->aCSR[3] & RT_BIT(4)), CSR_LAPPEN(pThis),
4129 CSR_DXSUFLO(pThis), !!(pThis->aCSR[3] & RT_BIT(8)), !!(pThis->aCSR[3] & RT_BIT(9)), !!(pThis->aCSR[3] & RT_BIT(10)),
4130 !!(pThis->aCSR[3] & RT_BIT(11)), !!(pThis->aCSR[3] & RT_BIT(12)), !!(pThis->aCSR[3] & RT_BIT(14)));
4131
4132 pHlp->pfnPrintf(pHlp,
4133 "CSR4=%#06x: JABM=%d JAB=%d TXSTRM=%d TXSTRT=%d RCVCOOM=%d RCVCCO=%d UINT=%d UINTCMD=%d\n"
4134 " MFCOM=%d MFCO=%d ASTRP_RCV=%d APAD_XMT=%d DPOLL=%d TIMER=%d EMAPLUS=%d EN124=%d\n",
4135 pThis->aCSR[4],
4136 !!(pThis->aCSR[4] & RT_BIT( 0)), !!(pThis->aCSR[4] & RT_BIT( 1)), !!(pThis->aCSR[4] & RT_BIT( 2)), !!(pThis->aCSR[4] & RT_BIT( 3)),
4137 !!(pThis->aCSR[4] & RT_BIT( 4)), !!(pThis->aCSR[4] & RT_BIT( 5)), !!(pThis->aCSR[4] & RT_BIT( 6)), !!(pThis->aCSR[4] & RT_BIT( 7)),
4138 !!(pThis->aCSR[4] & RT_BIT( 8)), !!(pThis->aCSR[4] & RT_BIT( 9)), !!(pThis->aCSR[4] & RT_BIT(10)), !!(pThis->aCSR[4] & RT_BIT(11)),
4139 !!(pThis->aCSR[4] & RT_BIT(12)), !!(pThis->aCSR[4] & RT_BIT(13)), !!(pThis->aCSR[4] & RT_BIT(14)), !!(pThis->aCSR[4] & RT_BIT(15)));
4140
4141 pHlp->pfnPrintf(pHlp,
4142 "CSR5=%#06x:\n",
4143 pThis->aCSR[5]);
4144
4145 pHlp->pfnPrintf(pHlp,
4146 "CSR6=%#06x: RLEN=%#x* TLEN=%#x* [* encoded]\n",
4147 pThis->aCSR[6],
4148 (pThis->aCSR[6] >> 8) & 0xf, (pThis->aCSR[6] >> 12) & 0xf);
4149
4150 pHlp->pfnPrintf(pHlp,
4151 "CSR8..11=%#06x,%#06x,%#06x,%#06x: LADRF=%#018llx\n",
4152 pThis->aCSR[8], pThis->aCSR[9], pThis->aCSR[10], pThis->aCSR[11],
4153 (uint64_t)(pThis->aCSR[ 8] & 0xffff)
4154 | (uint64_t)(pThis->aCSR[ 9] & 0xffff) << 16
4155 | (uint64_t)(pThis->aCSR[10] & 0xffff) << 32
4156 | (uint64_t)(pThis->aCSR[11] & 0xffff) << 48);
4157
4158 pHlp->pfnPrintf(pHlp,
4159 "CSR12..14=%#06x,%#06x,%#06x: PADR=%02x:%02x:%02x:%02x:%02x:%02x (Current MAC Address)\n",
4160 pThis->aCSR[12], pThis->aCSR[13], pThis->aCSR[14],
4161 pThis->aCSR[12] & 0xff,
4162 (pThis->aCSR[12] >> 8) & 0xff,
4163 pThis->aCSR[13] & 0xff,
4164 (pThis->aCSR[13] >> 8) & 0xff,
4165 pThis->aCSR[14] & 0xff,
4166 (pThis->aCSR[14] >> 8) & 0xff);
4167
4168 pHlp->pfnPrintf(pHlp,
4169 "CSR15=%#06x: DXR=%d DTX=%d LOOP=%d DXMTFCS=%d FCOLL=%d DRTY=%d INTL=%d PORTSEL=%d LTR=%d\n"
4170 " MENDECL=%d DAPC=%d DLNKTST=%d DRCVPV=%d DRCVBC=%d PROM=%d\n",
4171 pThis->aCSR[15],
4172 !!(pThis->aCSR[15] & RT_BIT( 0)), !!(pThis->aCSR[15] & RT_BIT( 1)), !!(pThis->aCSR[15] & RT_BIT( 2)), !!(pThis->aCSR[15] & RT_BIT( 3)),
4173 !!(pThis->aCSR[15] & RT_BIT( 4)), !!(pThis->aCSR[15] & RT_BIT( 5)), !!(pThis->aCSR[15] & RT_BIT( 6)), (pThis->aCSR[15] >> 7) & 3,
4174 !!(pThis->aCSR[15] & RT_BIT( 9)), !!(pThis->aCSR[15] & RT_BIT(10)), !!(pThis->aCSR[15] & RT_BIT(11)),
4175 !!(pThis->aCSR[15] & RT_BIT(12)), !!(pThis->aCSR[15] & RT_BIT(13)), !!(pThis->aCSR[15] & RT_BIT(14)), !!(pThis->aCSR[15] & RT_BIT(15)));
4176
4177 pHlp->pfnPrintf(pHlp,
4178 "CSR46=%#06x: POLL=%#06x (Poll Time Counter)\n",
4179 pThis->aCSR[46], pThis->aCSR[46] & 0xffff);
4180
4181 pHlp->pfnPrintf(pHlp,
4182 "CSR47=%#06x: POLLINT=%#06x (Poll Time Interval)\n",
4183 pThis->aCSR[47], pThis->aCSR[47] & 0xffff);
4184
4185 pHlp->pfnPrintf(pHlp,
4186 "CSR58=%#06x: SWSTYLE=%d %s SSIZE32=%d CSRPCNET=%d APERRENT=%d\n",
4187 pThis->aCSR[58],
4188 pThis->aCSR[58] & 0x7f,
4189 (pThis->aCSR[58] & 0x7f) == 0 ? "C-LANCE / PCnet-ISA"
4190 : (pThis->aCSR[58] & 0x7f) == 1 ? "ILACC"
4191 : (pThis->aCSR[58] & 0x7f) == 2 ? "PCNet-PCI II"
4192 : (pThis->aCSR[58] & 0x7f) == 3 ? "PCNet-PCI II controller"
4193 : "!!reserved!!",
4194 !!(pThis->aCSR[58] & RT_BIT(8)), !!(pThis->aCSR[58] & RT_BIT(9)), !!(pThis->aCSR[58] & RT_BIT(10)));
4195
4196 pHlp->pfnPrintf(pHlp,
4197 "CSR112=%04RX32: MFC=%04x (Missed receive Frame Count)\n",
4198 pThis->aCSR[112], pThis->aCSR[112] & 0xffff);
4199
4200 pHlp->pfnPrintf(pHlp,
4201 "CSR122=%04RX32: RCVALGN=%04x (Receive Frame Align)\n",
4202 pThis->aCSR[122], !!(pThis->aCSR[122] & RT_BIT(0)));
4203
4204 pHlp->pfnPrintf(pHlp,
4205 "CSR124=%04RX32: RPA=%04x (Runt Packet Accept)\n",
4206 pThis->aCSR[122], !!(pThis->aCSR[122] & RT_BIT(3)));
4207
4208
4209 /*
4210 * Dump the receive ring.
4211 */
4212 pHlp->pfnPrintf(pHlp,
4213 "RCVRL=%04x RCVRC=%04x GCRDRA=%RX32 \n"
4214 "CRDA=%08RX32 CRBA=%08RX32 CRBC=%03x CRST=%04x\n"
4215 "NRDA=%08RX32 NRBA=%08RX32 NRBC=%03x NRST=%04x\n"
4216 "NNRDA=%08RX32\n"
4217 ,
4218 CSR_RCVRL(pThis), CSR_RCVRC(pThis), pThis->GCRDRA,
4219 CSR_CRDA(pThis), CSR_CRBA(pThis), CSR_CRBC(pThis), CSR_CRST(pThis),
4220 CSR_NRDA(pThis), CSR_NRBA(pThis), CSR_NRBC(pThis), CSR_NRST(pThis),
4221 CSR_NNRD(pThis));
4222 if (fRcvRing)
4223 {
4224 const unsigned cb = 1 << pThis->iLog2DescSize;
4225 RTGCPHYS32 GCPhys = pThis->GCRDRA;
4226 unsigned i = CSR_RCVRL(pThis);
4227 while (i-- > 0)
4228 {
4229 RMD rmd;
4230 pcnetRmdLoad(pThis, &rmd, PHYSADDR(pThis, GCPhys), false);
4231 pHlp->pfnPrintf(pHlp,
4232 "%04x %RX32:%c%c RBADR=%08RX32 BCNT=%03x MCNT=%03x "
4233 "OWN=%d ERR=%d FRAM=%d OFLO=%d CRC=%d BUFF=%d STP=%d ENP=%d BPE=%d "
4234 "PAM=%d LAFM=%d BAM=%d RCC=%02x RPC=%02x ONES=%#x ZEROS=%d\n",
4235 i, GCPhys, i + 1 == CSR_RCVRC(pThis) ? '*' : ' ', GCPhys == CSR_CRDA(pThis) ? '*' : ' ',
4236 rmd.rmd0.rbadr, 4096 - rmd.rmd1.bcnt, rmd.rmd2.mcnt,
4237 rmd.rmd1.own, rmd.rmd1.err, rmd.rmd1.fram, rmd.rmd1.oflo, rmd.rmd1.crc, rmd.rmd1.buff,
4238 rmd.rmd1.stp, rmd.rmd1.enp, rmd.rmd1.bpe,
4239 rmd.rmd1.pam, rmd.rmd1.lafm, rmd.rmd1.bam, rmd.rmd2.rcc, rmd.rmd2.rpc,
4240 rmd.rmd1.ones, rmd.rmd2.zeros);
4241
4242 GCPhys += cb;
4243 }
4244 }
4245
4246 /*
4247 * Dump the transmit ring.
4248 */
4249 pHlp->pfnPrintf(pHlp,
4250 "XMTRL=%04x XMTRC=%04x GCTDRA=%08RX32 BADX=%08RX32\n"
4251 "PXDA=%08RX32 PXBC=%03x PXST=%04x\n"
4252 "CXDA=%08RX32 CXBA=%08RX32 CXBC=%03x CXST=%04x\n"
4253 "NXDA=%08RX32 NXBA=%08RX32 NXBC=%03x NXST=%04x\n"
4254 "NNXDA=%08RX32\n"
4255 ,
4256 CSR_XMTRL(pThis), CSR_XMTRC(pThis),
4257 pThis->GCTDRA, CSR_BADX(pThis),
4258 CSR_PXDA(pThis), CSR_PXBC(pThis), CSR_PXST(pThis),
4259 CSR_CXDA(pThis), CSR_CXBA(pThis), CSR_CXBC(pThis), CSR_CXST(pThis),
4260 CSR_NXDA(pThis), CSR_NXBA(pThis), CSR_NXBC(pThis), CSR_NXST(pThis),
4261 CSR_NNXD(pThis));
4262 if (fXmtRing)
4263 {
4264 const unsigned cb = 1 << pThis->iLog2DescSize;
4265 RTGCPHYS32 GCPhys = pThis->GCTDRA;
4266 unsigned i = CSR_XMTRL(pThis);
4267 while (i-- > 0)
4268 {
4269 TMD tmd;
4270 pcnetTmdLoad(pThis, &tmd, PHYSADDR(pThis, GCPhys), false);
4271 pHlp->pfnPrintf(pHlp,
4272 "%04x %RX32:%c%c TBADR=%08RX32 BCNT=%03x OWN=%d "
4273 "ERR=%d NOFCS=%d LTINT=%d ONE=%d DEF=%d STP=%d ENP=%d BPE=%d "
4274 "BUFF=%d UFLO=%d EXDEF=%d LCOL=%d LCAR=%d RTRY=%d TDR=%03x TRC=%#x ONES=%#x\n"
4275 ,
4276 i, GCPhys, i + 1 == CSR_XMTRC(pThis) ? '*' : ' ', GCPhys == CSR_CXDA(pThis) ? '*' : ' ',
4277 tmd.tmd0.tbadr, 4096 - tmd.tmd1.bcnt,
4278 tmd.tmd2.tdr,
4279 tmd.tmd2.trc,
4280 tmd.tmd1.own,
4281 tmd.tmd1.err,
4282 tmd.tmd1.nofcs,
4283 tmd.tmd1.ltint,
4284 tmd.tmd1.one,
4285 tmd.tmd1.def,
4286 tmd.tmd1.stp,
4287 tmd.tmd1.enp,
4288 tmd.tmd1.bpe,
4289 tmd.tmd2.buff,
4290 tmd.tmd2.uflo,
4291 tmd.tmd2.exdef,
4292 tmd.tmd2.lcol,
4293 tmd.tmd2.lcar,
4294 tmd.tmd2.rtry,
4295 tmd.tmd2.tdr,
4296 tmd.tmd2.trc,
4297 tmd.tmd1.ones);
4298
4299 GCPhys += cb;
4300 }
4301 }
4302
4303 PDMCritSectLeave(&pThis->CritSect);
4304}
4305
4306
4307/**
4308 * Takes down the link temporarily if it's current status is up.
4309 *
4310 * This is used during restore and when replumbing the network link.
4311 *
4312 * The temporary link outage is supposed to indicate to the OS that all network
4313 * connections have been lost and that it for instance is appropriate to
4314 * renegotiate any DHCP lease.
4315 *
4316 * @param pThis The PCNet instance data.
4317 */
4318static void pcnetTempLinkDown(PCNetState *pThis)
4319{
4320 if (pThis->fLinkUp)
4321 {
4322 pThis->fLinkTempDown = true;
4323 pThis->cLinkDownReported = 0;
4324 pThis->aCSR[0] |= RT_BIT(15) | RT_BIT(13); /* ERR | CERR (this is probably wrong) */
4325 pThis->Led.Asserted.s.fError = pThis->Led.Actual.s.fError = 1;
4326 int rc = TMTimerSetMillies(pThis->pTimerRestore, 5000);
4327 AssertRC(rc);
4328 }
4329}
4330
4331
4332/**
4333 * Saves the configuration.
4334 *
4335 * @param pThis The PCNet instance data.
4336 * @param pSSM The saved state handle.
4337 */
4338static void pcnetSaveConfig(PCNetState *pThis, PSSMHANDLE pSSM)
4339{
4340 SSMR3PutMem(pSSM, &pThis->MacConfigured, sizeof(pThis->MacConfigured));
4341 SSMR3PutBool(pSSM, pThis->fAm79C973); /* >= If version 0.8 */
4342 SSMR3PutU32(pSSM, pThis->u32LinkSpeed);
4343}
4344
4345
4346/**
4347 * Live Save, pass 0.
4348 *
4349 * @returns VBox status code.
4350 * @param pDevIns The device instance.
4351 * @param pSSM The saved state handle.
4352 * @param uPass The pass number.
4353 */
4354static DECLCALLBACK(int) pcnetLiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
4355{
4356 PCNetState *pThis = PDMINS_2_DATA(pDevIns, PCNetState *);
4357 pcnetSaveConfig(pThis, pSSM);
4358 return VINF_SSM_DONT_CALL_AGAIN;
4359}
4360
4361
4362/**
4363 * Serializes the receive thread, it may be working inside the critsect.
4364 *
4365 * @returns VBox status code.
4366 * @param pDevIns The device instance.
4367 * @param pSSM The saved state handle.
4368 */
4369static DECLCALLBACK(int) pcnetSavePrep(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
4370{
4371 PCNetState *pThis = PDMINS_2_DATA(pDevIns, PCNetState *);
4372
4373 int rc = PDMCritSectEnter(&pThis->CritSect, VERR_SEM_BUSY);
4374 AssertRC(rc);
4375 PDMCritSectLeave(&pThis->CritSect);
4376
4377 return VINF_SUCCESS;
4378}
4379
4380
4381/**
4382 * Saves a state of the PC-Net II device.
4383 *
4384 * @returns VBox status code.
4385 * @param pDevIns The device instance.
4386 * @param pSSM The saved state handle.
4387 */
4388static DECLCALLBACK(int) pcnetSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
4389{
4390 PCNetState *pThis = PDMINS_2_DATA(pDevIns, PCNetState *);
4391
4392 SSMR3PutBool(pSSM, pThis->fLinkUp);
4393 SSMR3PutU32(pSSM, pThis->u32RAP);
4394 SSMR3PutS32(pSSM, pThis->iISR);
4395 SSMR3PutU32(pSSM, pThis->u32Lnkst);
4396 SSMR3PutBool(pSSM, pThis->fPrivIfEnabled); /* >= If version 0.9 */
4397 SSMR3PutBool(pSSM, pThis->fSignalRxMiss); /* >= If version 0.10 */
4398 SSMR3PutGCPhys32(pSSM, pThis->GCRDRA);
4399 SSMR3PutGCPhys32(pSSM, pThis->GCTDRA);
4400 SSMR3PutMem(pSSM, pThis->aPROM, sizeof(pThis->aPROM));
4401 SSMR3PutMem(pSSM, pThis->aCSR, sizeof(pThis->aCSR));
4402 SSMR3PutMem(pSSM, pThis->aBCR, sizeof(pThis->aBCR));
4403 SSMR3PutMem(pSSM, pThis->aMII, sizeof(pThis->aMII));
4404 SSMR3PutU16(pSSM, pThis->u16CSR0LastSeenByGuest);
4405 SSMR3PutU64(pSSM, pThis->u64LastPoll);
4406 pcnetSaveConfig(pThis, pSSM);
4407
4408 int rc = VINF_SUCCESS;
4409#ifndef PCNET_NO_POLLING
4410 rc = TMR3TimerSave(pThis->CTX_SUFF(pTimerPoll), pSSM);
4411 if (RT_FAILURE(rc))
4412 return rc;
4413#endif
4414 if (pThis->fAm79C973)
4415 rc = TMR3TimerSave(pThis->CTX_SUFF(pTimerSoftInt), pSSM);
4416 return rc;
4417}
4418
4419
4420/**
4421 * Serializes the receive thread, it may be working inside the critsect.
4422 *
4423 * @returns VBox status code.
4424 * @param pDevIns The device instance.
4425 * @param pSSM The saved state handle.
4426 */
4427static DECLCALLBACK(int) pcnetLoadPrep(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
4428{
4429 PCNetState *pThis = PDMINS_2_DATA(pDevIns, PCNetState *);
4430
4431 int rc = PDMCritSectEnter(&pThis->CritSect, VERR_SEM_BUSY);
4432 AssertRC(rc);
4433 PDMCritSectLeave(&pThis->CritSect);
4434
4435 return VINF_SUCCESS;
4436}
4437
4438
4439/**
4440 * Loads a saved PC-Net II device state.
4441 *
4442 * @returns VBox status code.
4443 * @param pDevIns The device instance.
4444 * @param pSSM The handle to the saved state.
4445 * @param uVersion The data unit version number.
4446 * @param uPass The data pass.
4447 */
4448static DECLCALLBACK(int) pcnetLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
4449{
4450 PCNetState *pThis = PDMINS_2_DATA(pDevIns, PCNetState *);
4451
4452 if ( SSM_VERSION_MAJOR_CHANGED(uVersion, PCNET_SAVEDSTATE_VERSION)
4453 || SSM_VERSION_MINOR(uVersion) < 7)
4454 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
4455
4456 if (uPass == SSM_PASS_FINAL)
4457 {
4458 /* restore data */
4459 SSMR3GetBool(pSSM, &pThis->fLinkUp);
4460 SSMR3GetU32(pSSM, &pThis->u32RAP);
4461 SSMR3GetS32(pSSM, &pThis->iISR);
4462 SSMR3GetU32(pSSM, &pThis->u32Lnkst);
4463 if ( SSM_VERSION_MAJOR(uVersion) > 0
4464 || SSM_VERSION_MINOR(uVersion) >= 9)
4465 {
4466 SSMR3GetBool(pSSM, &pThis->fPrivIfEnabled);
4467 if (pThis->fPrivIfEnabled)
4468 LogRel(("PCNet#%d: Enabling private interface\n", PCNET_INST_NR));
4469 }
4470 if ( SSM_VERSION_MAJOR(uVersion) > 0
4471 || SSM_VERSION_MINOR(uVersion) >= 10)
4472 {
4473 SSMR3GetBool(pSSM, &pThis->fSignalRxMiss);
4474 }
4475 SSMR3GetGCPhys32(pSSM, &pThis->GCRDRA);
4476 SSMR3GetGCPhys32(pSSM, &pThis->GCTDRA);
4477 SSMR3GetMem(pSSM, &pThis->aPROM, sizeof(pThis->aPROM));
4478 SSMR3GetMem(pSSM, &pThis->aCSR, sizeof(pThis->aCSR));
4479 SSMR3GetMem(pSSM, &pThis->aBCR, sizeof(pThis->aBCR));
4480 SSMR3GetMem(pSSM, &pThis->aMII, sizeof(pThis->aMII));
4481 SSMR3GetU16(pSSM, &pThis->u16CSR0LastSeenByGuest);
4482 SSMR3GetU64(pSSM, &pThis->u64LastPoll);
4483 }
4484
4485 /* check config */
4486 RTMAC Mac;
4487 int rc = SSMR3GetMem(pSSM, &Mac, sizeof(Mac));
4488 AssertRCReturn(rc, rc);
4489 if ( memcmp(&Mac, &pThis->MacConfigured, sizeof(Mac))
4490 && (uPass == 0 || !PDMDevHlpVMTeleportedAndNotFullyResumedYet(pDevIns)) )
4491 LogRel(("PCNet#%u: The mac address differs: config=%RTmac saved=%RTmac\n", PCNET_INST_NR, &pThis->MacConfigured, &Mac));
4492
4493 bool fAm79C973;
4494 rc = SSMR3GetBool(pSSM, &fAm79C973);
4495 AssertRCReturn(rc, rc);
4496 if (pThis->fAm79C973 != fAm79C973)
4497 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("The fAm79C973 flag differs: config=%RTbool saved=%RTbool"), pThis->fAm79C973, fAm79C973);
4498
4499 uint32_t u32LinkSpeed;
4500 rc = SSMR3GetU32(pSSM, &u32LinkSpeed);
4501 AssertRCReturn(rc, rc);
4502 if ( pThis->u32LinkSpeed != u32LinkSpeed
4503 && (uPass == 0 || !PDMDevHlpVMTeleportedAndNotFullyResumedYet(pDevIns)) )
4504 LogRel(("PCNet#%u: The mac link speed differs: config=%u saved=%u\n", PCNET_INST_NR, pThis->u32LinkSpeed, u32LinkSpeed));
4505
4506 if (uPass == SSM_PASS_FINAL)
4507 {
4508 /* restore timers and stuff */
4509#ifndef PCNET_NO_POLLING
4510 TMR3TimerLoad(pThis->CTX_SUFF(pTimerPoll), pSSM);
4511#endif
4512 if (pThis->fAm79C973)
4513 {
4514 if ( SSM_VERSION_MAJOR(uVersion) > 0
4515 || SSM_VERSION_MINOR(uVersion) >= 8)
4516 TMR3TimerLoad(pThis->CTX_SUFF(pTimerSoftInt), pSSM);
4517 }
4518
4519 pThis->iLog2DescSize = BCR_SWSTYLE(pThis)
4520 ? 4
4521 : 3;
4522 pThis->GCUpperPhys = BCR_SSIZE32(pThis)
4523 ? 0
4524 : (0xff00 & (uint32_t)pThis->aCSR[2]) << 16;
4525
4526 /* update promiscuous mode. */
4527 if (pThis->pDrvR3)
4528 pThis->pDrvR3->pfnSetPromiscuousMode(pThis->pDrvR3, CSR_PROM(pThis));
4529
4530#ifdef PCNET_NO_POLLING
4531 /* Enable physical monitoring again (!) */
4532 pcnetUpdateRingHandlers(pThis);
4533#endif
4534 /* Indicate link down to the guest OS that all network connections have
4535 been lost, unless we've been teleported here. */
4536 if (!PDMDevHlpVMTeleportedAndNotFullyResumedYet(pDevIns))
4537 pcnetTempLinkDown(pThis);
4538 }
4539
4540 return VINF_SUCCESS;
4541}
4542
4543
4544/**
4545 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
4546 */
4547static DECLCALLBACK(void *) pcnetQueryInterface(struct PDMIBASE *pInterface, const char *pszIID)
4548{
4549 PCNetState *pThis = RT_FROM_MEMBER(pInterface, PCNetState, IBase);
4550 Assert(&pThis->IBase == pInterface);
4551 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase);
4552 PDMIBASE_RETURN_INTERFACE(pszIID, PDMINETWORKDOWN, &pThis->INetworkDown);
4553 PDMIBASE_RETURN_INTERFACE(pszIID, PDMINETWORKCONFIG, &pThis->INetworkConfig);
4554 PDMIBASE_RETURN_INTERFACE(pszIID, PDMILEDPORTS, &pThis->ILeds);
4555 return NULL;
4556}
4557
4558
4559
4560/**
4561 * Check if the device/driver can receive data now.
4562 * This must be called before the pfnRecieve() method is called.
4563 *
4564 * @returns VBox status code.
4565 * @param pInterface Pointer to the interface structure containing the called function pointer.
4566 */
4567static int pcnetCanReceive(PCNetState *pThis)
4568{
4569 int rc = PDMCritSectEnter(&pThis->CritSect, VERR_SEM_BUSY);
4570 AssertReleaseRC(rc);
4571
4572 rc = VERR_NET_NO_BUFFER_SPACE;
4573
4574 if (RT_LIKELY(!CSR_DRX(pThis) && !CSR_STOP(pThis) && !CSR_SPND(pThis)))
4575 {
4576 if (HOST_IS_OWNER(CSR_CRST(pThis)) && pThis->GCRDRA)
4577 pcnetRdtePoll(pThis);
4578
4579 if (RT_UNLIKELY(HOST_IS_OWNER(CSR_CRST(pThis))))
4580 {
4581 /** @todo Notify the guest _now_. Will potentially increase the interrupt load */
4582 if (pThis->fSignalRxMiss)
4583 pThis->aCSR[0] |= 0x1000; /* Set MISS flag */
4584 }
4585 else
4586 rc = VINF_SUCCESS;
4587 }
4588
4589 PDMCritSectLeave(&pThis->CritSect);
4590 return rc;
4591}
4592
4593
4594/**
4595 * @interface_method_impl{PDMINETWORKDOWN,pfnWaitReceiveAvail}
4596 */
4597static DECLCALLBACK(int) pcnetNetworkDown_WaitReceiveAvail(PPDMINETWORKDOWN pInterface, RTMSINTERVAL cMillies)
4598{
4599 PCNetState *pThis = RT_FROM_MEMBER(pInterface, PCNetState, INetworkDown);
4600
4601 int rc = pcnetCanReceive(pThis);
4602 if (RT_SUCCESS(rc))
4603 return VINF_SUCCESS;
4604 if (RT_UNLIKELY(cMillies == 0))
4605 return VERR_NET_NO_BUFFER_SPACE;
4606
4607 rc = VERR_INTERRUPTED;
4608 ASMAtomicXchgBool(&pThis->fMaybeOutOfSpace, true);
4609 STAM_PROFILE_START(&pThis->StatRxOverflow, a);
4610 VMSTATE enmVMState;
4611 while (RT_LIKELY( (enmVMState = PDMDevHlpVMState(pThis->CTX_SUFF(pDevIns))) == VMSTATE_RUNNING
4612 || enmVMState == VMSTATE_RUNNING_LS))
4613 {
4614 int rc2 = pcnetCanReceive(pThis);
4615 if (RT_SUCCESS(rc2))
4616 {
4617 rc = VINF_SUCCESS;
4618 break;
4619 }
4620 LogFlow(("pcnetNetworkDown_WaitReceiveAvail: waiting cMillies=%u...\n", cMillies));
4621 /* Start the poll timer once which will remain active as long fMaybeOutOfSpace
4622 * is true -- even if (transmit) polling is disabled (CSR_DPOLL). */
4623 rc2 = PDMCritSectEnter(&pThis->CritSect, VERR_SEM_BUSY);
4624 AssertReleaseRC(rc2);
4625 pcnetPollTimerStart(pThis);
4626 PDMCritSectLeave(&pThis->CritSect);
4627 RTSemEventWait(pThis->hEventOutOfRxSpace, cMillies);
4628 }
4629 STAM_PROFILE_STOP(&pThis->StatRxOverflow, a);
4630 ASMAtomicXchgBool(&pThis->fMaybeOutOfSpace, false);
4631
4632 return rc;
4633}
4634
4635
4636/**
4637 * @interface_method_impl{PDMINETWORKDOWN,pfnReceive}
4638 */
4639static DECLCALLBACK(int) pcnetNetworkDown_Receive(PPDMINETWORKDOWN pInterface, const void *pvBuf, size_t cb)
4640{
4641 PCNetState *pThis = RT_FROM_MEMBER(pInterface, PCNetState, INetworkDown);
4642 int rc;
4643
4644 STAM_PROFILE_ADV_START(&pThis->StatReceive, a);
4645 rc = PDMCritSectEnter(&pThis->CritSect, VERR_SEM_BUSY);
4646 AssertReleaseRC(rc);
4647
4648 /*
4649 * Check for the max ethernet frame size, taking the IEEE 802.1Q (VLAN) tag into
4650 * account. Note that we are *not* expecting the CRC Checksum.
4651 * Ethernet frames consists of a 14-byte header [+ 4-byte vlan tag] + a 1500-byte body.
4652 */
4653 if (RT_LIKELY( cb <= 1514
4654 || ( cb <= 1518
4655 && ((PCRTNETETHERHDR)pvBuf)->EtherType == RT_H2BE_U16_C(RTNET_ETHERTYPE_VLAN))))
4656 {
4657 if (cb > 70) /* unqualified guess */
4658 pThis->Led.Asserted.s.fReading = pThis->Led.Actual.s.fReading = 1;
4659 pcnetReceiveNoSync(pThis, (const uint8_t *)pvBuf, cb);
4660 pThis->Led.Actual.s.fReading = 0;
4661 }
4662#ifdef LOG_ENABLED
4663 else
4664 {
4665 static bool s_fFirstBigFrameLoss = true;
4666 unsigned cbMaxFrame = ((PCRTNETETHERHDR)pvBuf)->EtherType == RT_H2BE_U16_C(RTNET_ETHERTYPE_VLAN)
4667 ? 1518 : 1514;
4668 if (s_fFirstBigFrameLoss)
4669 {
4670 s_fFirstBigFrameLoss = false;
4671 Log(("PCNet#%d: Received giant frame %zu, max %u. (Further giants will be reported at level5.)\n",
4672 PCNET_INST_NR, cb, cbMaxFrame));
4673 }
4674 else
4675 Log5(("PCNet#%d: Received giant frame %zu bytes, max %u.\n",
4676 PCNET_INST_NR, cb, cbMaxFrame));
4677 }
4678#endif /* LOG_ENABLED */
4679
4680 PDMCritSectLeave(&pThis->CritSect);
4681 STAM_PROFILE_ADV_STOP(&pThis->StatReceive, a);
4682
4683 return VINF_SUCCESS;
4684}
4685
4686
4687/**
4688 * @interface_method_impl{PDMINETWORKDOWN,pfnXmitPending}
4689 */
4690static DECLCALLBACK(void) pcnetNetworkDown_XmitPending(PPDMINETWORKDOWN pInterface)
4691{
4692 PCNetState *pThis = RT_FROM_MEMBER(pInterface, PCNetState, INetworkDown);
4693 pcnetXmitPending(pThis, true /*fOnWorkerThread*/);
4694}
4695
4696
4697
4698/**
4699 * Gets the current Media Access Control (MAC) address.
4700 *
4701 * @returns VBox status code.
4702 * @param pInterface Pointer to the interface structure containing the called function pointer.
4703 * @param pMac Where to store the MAC address.
4704 * @thread EMT
4705 */
4706static DECLCALLBACK(int) pcnetGetMac(PPDMINETWORKCONFIG pInterface, PRTMAC pMac)
4707{
4708 PCNetState *pThis = RT_FROM_MEMBER(pInterface, PCNetState, INetworkConfig);
4709 memcpy(pMac, pThis->aPROM, sizeof(*pMac));
4710 return VINF_SUCCESS;
4711}
4712
4713
4714/**
4715 * Gets the new link state.
4716 *
4717 * @returns The current link state.
4718 * @param pInterface Pointer to the interface structure containing the called function pointer.
4719 * @thread EMT
4720 */
4721static DECLCALLBACK(PDMNETWORKLINKSTATE) pcnetGetLinkState(PPDMINETWORKCONFIG pInterface)
4722{
4723 PCNetState *pThis = RT_FROM_MEMBER(pInterface, PCNetState, INetworkConfig);
4724 if (pThis->fLinkUp && !pThis->fLinkTempDown)
4725 return PDMNETWORKLINKSTATE_UP;
4726 if (!pThis->fLinkUp)
4727 return PDMNETWORKLINKSTATE_DOWN;
4728 if (pThis->fLinkTempDown)
4729 return PDMNETWORKLINKSTATE_DOWN_RESUME;
4730 AssertMsgFailed(("Invalid link state!\n"));
4731 return PDMNETWORKLINKSTATE_INVALID;
4732}
4733
4734
4735/**
4736 * Sets the new link state.
4737 *
4738 * @returns VBox status code.
4739 * @param pInterface Pointer to the interface structure containing the called function pointer.
4740 * @param enmState The new link state
4741 * @thread EMT
4742 */
4743static DECLCALLBACK(int) pcnetSetLinkState(PPDMINETWORKCONFIG pInterface, PDMNETWORKLINKSTATE enmState)
4744{
4745 PCNetState *pThis = RT_FROM_MEMBER(pInterface, PCNetState, INetworkConfig);
4746 bool fLinkUp;
4747 if ( enmState != PDMNETWORKLINKSTATE_DOWN
4748 && enmState != PDMNETWORKLINKSTATE_UP)
4749 {
4750 AssertMsgFailed(("Invalid parameter enmState=%d\n", enmState));
4751 return VERR_INVALID_PARAMETER;
4752 }
4753
4754 /* has the state changed? */
4755 fLinkUp = enmState == PDMNETWORKLINKSTATE_UP;
4756 if (pThis->fLinkUp != fLinkUp)
4757 {
4758 pThis->fLinkUp = fLinkUp;
4759 if (fLinkUp)
4760 {
4761 /* connect with a delay of 5 seconds */
4762 pThis->fLinkTempDown = true;
4763 pThis->cLinkDownReported = 0;
4764 pThis->aCSR[0] |= RT_BIT(15) | RT_BIT(13); /* ERR | CERR (this is probably wrong) */
4765 pThis->Led.Asserted.s.fError = pThis->Led.Actual.s.fError = 1;
4766 int rc = TMTimerSetMillies(pThis->pTimerRestore, 5000);
4767 AssertRC(rc);
4768 }
4769 else
4770 {
4771 /* disconnect */
4772 pThis->cLinkDownReported = 0;
4773 pThis->aCSR[0] |= RT_BIT(15) | RT_BIT(13); /* ERR | CERR (this is probably wrong) */
4774 pThis->Led.Asserted.s.fError = pThis->Led.Actual.s.fError = 1;
4775 }
4776 Assert(!PDMCritSectIsOwner(&pThis->CritSect));
4777 if (pThis->pDrvR3)
4778 pThis->pDrvR3->pfnNotifyLinkChanged(pThis->pDrvR3, enmState);
4779 }
4780 return VINF_SUCCESS;
4781}
4782
4783
4784/**
4785 * Gets the pointer to the status LED of a unit.
4786 *
4787 * @returns VBox status code.
4788 * @param pInterface Pointer to the interface structure containing the called function pointer.
4789 * @param iLUN The unit which status LED we desire.
4790 * @param ppLed Where to store the LED pointer.
4791 */
4792static DECLCALLBACK(int) pcnetQueryStatusLed(PPDMILEDPORTS pInterface, unsigned iLUN, PPDMLED *ppLed)
4793{
4794 PCNetState *pThis = (PCNetState *)( (uintptr_t)pInterface - RT_OFFSETOF(PCNetState, ILeds) );
4795 if (iLUN == 0)
4796 {
4797 *ppLed = &pThis->Led;
4798 return VINF_SUCCESS;
4799 }
4800 return VERR_PDM_LUN_NOT_FOUND;
4801}
4802
4803
4804/**
4805 * @copydoc FNPDMDEVPOWEROFF
4806 */
4807static DECLCALLBACK(void) pcnetPowerOff(PPDMDEVINS pDevIns)
4808{
4809 /* Poke thread waiting for buffer space. */
4810 pcnetWakeupReceive(pDevIns);
4811}
4812
4813#ifdef VBOX_DYNAMIC_NET_ATTACH
4814
4815/**
4816 * Detach notification.
4817 *
4818 * One port on the network card has been disconnected from the network.
4819 *
4820 * @param pDevIns The device instance.
4821 * @param iLUN The logical unit which is being detached.
4822 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
4823 */
4824static DECLCALLBACK(void) pcnetDetach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
4825{
4826 PCNetState *pThis = PDMINS_2_DATA(pDevIns, PCNetState *);
4827 Log(("#%d pcnetDetach:\n", PCNET_INST_NR));
4828
4829 AssertLogRelReturnVoid(iLUN == 0);
4830
4831 PDMCritSectEnter(&pThis->CritSect, VERR_SEM_BUSY);
4832
4833 /** @todo: r=pritesh still need to check if i missed
4834 * to clean something in this function
4835 */
4836
4837 /*
4838 * Zero some important members.
4839 */
4840 pThis->pDrvBase = NULL;
4841 pThis->pDrvR3 = NULL;
4842 pThis->pDrvR0 = NIL_RTR0PTR;
4843 pThis->pDrvRC = NIL_RTRCPTR;
4844
4845 PDMCritSectLeave(&pThis->CritSect);
4846}
4847
4848
4849/**
4850 * Attach the Network attachment.
4851 *
4852 * One port on the network card has been connected to a network.
4853 *
4854 * @returns VBox status code.
4855 * @param pDevIns The device instance.
4856 * @param iLUN The logical unit which is being attached.
4857 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
4858 *
4859 * @remarks This code path is not used during construction.
4860 */
4861static DECLCALLBACK(int) pcnetAttach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
4862{
4863 PCNetState *pThis = PDMINS_2_DATA(pDevIns, PCNetState *);
4864 LogFlow(("#%d pcnetAttach:\n", PCNET_INST_NR));
4865
4866 AssertLogRelReturn(iLUN == 0, VERR_PDM_NO_SUCH_LUN);
4867
4868 PDMCritSectEnter(&pThis->CritSect, VERR_SEM_BUSY);
4869
4870 /*
4871 * Attach the driver.
4872 */
4873 int rc = PDMDevHlpDriverAttach(pDevIns, 0, &pThis->IBase, &pThis->pDrvBase, "Network Port");
4874 if (RT_SUCCESS(rc))
4875 {
4876 if (rc == VINF_NAT_DNS)
4877 {
4878#ifdef RT_OS_LINUX
4879 PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "NoDNSforNAT",
4880 N_("A Domain Name Server (DNS) for NAT networking could not be determined. Please check your /etc/resolv.conf for <tt>nameserver</tt> entries. Either add one manually (<i>man resolv.conf</i>) or ensure that your host is correctly connected to an ISP. If you ignore this warning the guest will not be able to perform nameserver lookups and it will probably observe delays if trying so"));
4881#else
4882 PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "NoDNSforNAT",
4883 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"));
4884#endif
4885 }
4886 pThis->pDrvR3 = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMINETWORKUP);
4887 AssertMsgStmt(pThis->pDrvR3, ("Failed to obtain the PDMINETWORKUP interface!\n"),
4888 rc = VERR_PDM_MISSING_INTERFACE_BELOW);
4889 pThis->pDrvR0 = PDMIBASER0_QUERY_INTERFACE(PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMIBASER0), PDMINETWORKUP);
4890 pThis->pDrvRC = PDMIBASERC_QUERY_INTERFACE(PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMIBASERC), PDMINETWORKUP);
4891 }
4892 else if ( rc == VERR_PDM_NO_ATTACHED_DRIVER
4893 || rc == VERR_PDM_CFG_MISSING_DRIVER_NAME)
4894 {
4895 /* This should never happen because this function is not called
4896 * if there is no driver to attach! */
4897 Log(("#%d No attached driver!\n", PCNET_INST_NR));
4898 }
4899
4900 /*
4901 * Temporary set the link down if it was up so that the guest
4902 * will know that we have change the configuration of the
4903 * network card
4904 */
4905 if (RT_SUCCESS(rc))
4906 pcnetTempLinkDown(pThis);
4907
4908 PDMCritSectLeave(&pThis->CritSect);
4909 return rc;
4910
4911}
4912
4913#endif /* VBOX_DYNAMIC_NET_ATTACH */
4914
4915/**
4916 * @copydoc FNPDMDEVSUSPEND
4917 */
4918static DECLCALLBACK(void) pcnetSuspend(PPDMDEVINS pDevIns)
4919{
4920 /* Poke thread waiting for buffer space. */
4921 pcnetWakeupReceive(pDevIns);
4922}
4923
4924
4925/**
4926 * @copydoc FNPDMDEVRESET
4927 */
4928static DECLCALLBACK(void) pcnetReset(PPDMDEVINS pDevIns)
4929{
4930 PCNetState *pThis = PDMINS_2_DATA(pDevIns, PCNetState *);
4931 if (pThis->fLinkTempDown)
4932 {
4933 pThis->cLinkDownReported = 0x10000;
4934 TMTimerStop(pThis->pTimerRestore);
4935 pcnetTimerRestore(pDevIns, pThis->pTimerRestore, pThis);
4936 }
4937 if (pThis->pSharedMMIOR3)
4938 pcnetInitSharedMemory(pThis);
4939
4940 /** @todo How to flush the queues? */
4941 pcnetHardReset(pThis);
4942}
4943
4944
4945/**
4946 * @copydoc FNPDMDEVRELOCATE
4947 */
4948static DECLCALLBACK(void) pcnetRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
4949{
4950 PCNetState *pThis = PDMINS_2_DATA(pDevIns, PCNetState *);
4951 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
4952 pThis->pXmitQueueRC = PDMQueueRCPtr(pThis->pXmitQueueR3);
4953 pThis->pCanRxQueueRC = PDMQueueRCPtr(pThis->pCanRxQueueR3);
4954 if (pThis->pSharedMMIOR3)
4955 pThis->pSharedMMIORC += offDelta;
4956#ifdef PCNET_NO_POLLING
4957 pThis->pfnEMInterpretInstructionRC += offDelta;
4958#else
4959 pThis->pTimerPollRC = TMTimerRCPtr(pThis->pTimerPollR3);
4960#endif
4961 if (pThis->fAm79C973)
4962 pThis->pTimerSoftIntRC = TMTimerRCPtr(pThis->pTimerSoftIntR3);
4963}
4964
4965
4966/**
4967 * Destruct a device instance.
4968 *
4969 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
4970 * resources can be freed correctly.
4971 *
4972 * @returns VBox status.
4973 * @param pDevIns The device instance data.
4974 */
4975static DECLCALLBACK(int) pcnetDestruct(PPDMDEVINS pDevIns)
4976{
4977 PCNetState *pThis = PDMINS_2_DATA(pDevIns, PCNetState *);
4978 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
4979
4980 if (PDMCritSectIsInitialized(&pThis->CritSect))
4981 {
4982 RTSemEventSignal(pThis->hEventOutOfRxSpace);
4983 RTSemEventDestroy(pThis->hEventOutOfRxSpace);
4984 pThis->hEventOutOfRxSpace = NIL_RTSEMEVENT;
4985 PDMR3CritSectDelete(&pThis->CritSect);
4986 }
4987 return VINF_SUCCESS;
4988}
4989
4990
4991/**
4992 * @interface_method_impl{PDMDEVREG,pfnConstruct}
4993 */
4994static DECLCALLBACK(int) pcnetConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
4995{
4996 PCNetState *pThis = PDMINS_2_DATA(pDevIns, PCNetState *);
4997 PPDMIBASE pBase;
4998 char szTmp[128];
4999 int rc;
5000
5001 /* up to eight instances are supported */
5002 Assert((iInstance >= 0) && (iInstance < 8));
5003
5004 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
5005 Assert(RT_ELEMENTS(pThis->aBCR) == BCR_MAX_RAP);
5006 Assert(RT_ELEMENTS(pThis->aMII) == MII_MAX_REG);
5007 Assert(sizeof(pThis->abLoopBuf) == RT_ALIGN_Z(sizeof(pThis->abLoopBuf), 16));
5008
5009 /*
5010 * Init what's required to make the destructor safe.
5011 */
5012 pThis->hEventOutOfRxSpace = NIL_RTSEMEVENT;
5013
5014 /*
5015 * Validate configuration.
5016 */
5017 if (!CFGMR3AreValuesValid(pCfg, "MAC\0" "CableConnected\0" "Am79C973\0" "LineSpeed\0" "GCEnabled\0" "R0Enabled\0" "PrivIfEnabled\0"))
5018 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
5019 N_("Invalid configuration for pcnet device"));
5020
5021 /*
5022 * Read the configuration.
5023 */
5024 rc = CFGMR3QueryBytes(pCfg, "MAC", &pThis->MacConfigured, sizeof(pThis->MacConfigured));
5025 if (RT_FAILURE(rc))
5026 return PDMDEV_SET_ERROR(pDevIns, rc,
5027 N_("Configuration error: Failed to get the \"MAC\" value"));
5028 rc = CFGMR3QueryBoolDef(pCfg, "CableConnected", &pThis->fLinkUp, true);
5029 if (RT_FAILURE(rc))
5030 return PDMDEV_SET_ERROR(pDevIns, rc,
5031 N_("Configuration error: Failed to get the \"CableConnected\" value"));
5032
5033 rc = CFGMR3QueryBoolDef(pCfg, "Am79C973", &pThis->fAm79C973, false);
5034 if (RT_FAILURE(rc))
5035 return PDMDEV_SET_ERROR(pDevIns, rc,
5036 N_("Configuration error: Failed to get the \"Am79C973\" value"));
5037
5038 rc = CFGMR3QueryU32Def(pCfg, "LineSpeed", &pThis->u32LinkSpeed, 1000000); /* 1GBit/s (in kbps units)*/
5039 if (RT_FAILURE(rc))
5040 return PDMDEV_SET_ERROR(pDevIns, rc,
5041 N_("Configuration error: Failed to get the \"LineSpeed\" value"));
5042
5043#ifdef PCNET_GC_ENABLED
5044 rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &pThis->fGCEnabled, true);
5045 if (RT_FAILURE(rc))
5046 return PDMDEV_SET_ERROR(pDevIns, rc,
5047 N_("Configuration error: Failed to get the \"GCEnabled\" value"));
5048
5049 rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &pThis->fR0Enabled, true);
5050 if (RT_FAILURE(rc))
5051 return PDMDEV_SET_ERROR(pDevIns, rc,
5052 N_("Configuration error: Failed to get the \"R0Enabled\" value"));
5053
5054#else /* !PCNET_GC_ENABLED */
5055 pThis->fGCEnabled = false;
5056 pThis->fR0Enabled = false;
5057#endif /* !PCNET_GC_ENABLED */
5058
5059
5060 /*
5061 * Initialize data (most of it anyway).
5062 */
5063 pThis->pDevInsR3 = pDevIns;
5064 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
5065 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
5066 pThis->Led.u32Magic = PDMLED_MAGIC;
5067 /* IBase */
5068 pThis->IBase.pfnQueryInterface = pcnetQueryInterface;
5069 /* INeworkPort */
5070 pThis->INetworkDown.pfnWaitReceiveAvail = pcnetNetworkDown_WaitReceiveAvail;
5071 pThis->INetworkDown.pfnReceive = pcnetNetworkDown_Receive;
5072 pThis->INetworkDown.pfnXmitPending = pcnetNetworkDown_XmitPending;
5073 /* INetworkConfig */
5074 pThis->INetworkConfig.pfnGetMac = pcnetGetMac;
5075 pThis->INetworkConfig.pfnGetLinkState = pcnetGetLinkState;
5076 pThis->INetworkConfig.pfnSetLinkState = pcnetSetLinkState;
5077 /* ILeds */
5078 pThis->ILeds.pfnQueryStatusLed = pcnetQueryStatusLed;
5079
5080 /* PCI Device */
5081 PCIDevSetVendorId(&pThis->PciDev, 0x1022);
5082 PCIDevSetDeviceId(&pThis->PciDev, 0x2000);
5083 pThis->PciDev.config[0x04] = 0x07; /* command */
5084 pThis->PciDev.config[0x05] = 0x00;
5085 pThis->PciDev.config[0x06] = 0x80; /* status */
5086 pThis->PciDev.config[0x07] = 0x02;
5087 pThis->PciDev.config[0x08] = pThis->fAm79C973 ? 0x40 : 0x10; /* revision */
5088 pThis->PciDev.config[0x09] = 0x00;
5089 pThis->PciDev.config[0x0a] = 0x00; /* ethernet network controller */
5090 pThis->PciDev.config[0x0b] = 0x02;
5091 pThis->PciDev.config[0x0e] = 0x00; /* header_type */
5092
5093 pThis->PciDev.config[0x10] = 0x01; /* IO Base */
5094 pThis->PciDev.config[0x11] = 0x00;
5095 pThis->PciDev.config[0x12] = 0x00;
5096 pThis->PciDev.config[0x13] = 0x00;
5097 pThis->PciDev.config[0x14] = 0x00; /* MMIO Base */
5098 pThis->PciDev.config[0x15] = 0x00;
5099 pThis->PciDev.config[0x16] = 0x00;
5100 pThis->PciDev.config[0x17] = 0x00;
5101
5102 /* subsystem and subvendor IDs */
5103 pThis->PciDev.config[0x2c] = 0x22; /* subsystem vendor id */
5104 pThis->PciDev.config[0x2d] = 0x10;
5105 pThis->PciDev.config[0x2e] = 0x00; /* subsystem id */
5106 pThis->PciDev.config[0x2f] = 0x20;
5107 pThis->PciDev.config[0x3d] = 1; /* interrupt pin 0 */
5108 pThis->PciDev.config[0x3e] = 0x06;
5109 pThis->PciDev.config[0x3f] = 0xff;
5110
5111 /*
5112 * Register the PCI device, its I/O regions, the timer and the saved state item.
5113 */
5114 rc = PDMDevHlpPCIRegister(pDevIns, &pThis->PciDev);
5115 if (RT_FAILURE(rc))
5116 return rc;
5117 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0, PCNET_IOPORT_SIZE,
5118 PCI_ADDRESS_SPACE_IO, pcnetIOPortMap);
5119 if (RT_FAILURE(rc))
5120 return rc;
5121 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 1, PCNET_PNPMMIO_SIZE,
5122 PCI_ADDRESS_SPACE_MEM, pcnetMMIOMap);
5123 if (RT_FAILURE(rc))
5124 return rc;
5125
5126 bool fPrivIfEnabled;
5127 rc = CFGMR3QueryBool(pCfg, "PrivIfEnabled", &fPrivIfEnabled);
5128 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
5129 fPrivIfEnabled = true;
5130 else if (RT_FAILURE(rc))
5131 return PDMDEV_SET_ERROR(pDevIns, rc,
5132 N_("Configuration error: Failed to get the \"PrivIfEnabled\" value"));
5133
5134 if (fPrivIfEnabled)
5135 {
5136 /*
5137 * Initialize shared memory between host and guest for descriptors and RX buffers. Most guests
5138 * should not care if there is an additional PCI ressource but just in case we made this configurable.
5139 */
5140 rc = PDMDevHlpMMIO2Register(pDevIns, 2, PCNET_GUEST_SHARED_MEMORY_SIZE, 0, (void **)&pThis->pSharedMMIOR3, "PCNetShMem");
5141 if (RT_FAILURE(rc))
5142 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
5143 N_("Failed to allocate %u bytes of memory for the PCNet device"), PCNET_GUEST_SHARED_MEMORY_SIZE);
5144 rc = PDMDevHlpMMHyperMapMMIO2(pDevIns, 2, 0, 8192, "PCNetShMem", &pThis->pSharedMMIORC);
5145 if (RT_FAILURE(rc))
5146 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
5147 N_("Failed to map 8192 bytes of memory for the PCNet device into the hyper memory"));
5148 pThis->pSharedMMIOR0 = (uintptr_t)pThis->pSharedMMIOR3; /** @todo #1865: Map MMIO2 into ring-0. */
5149
5150 pcnetInitSharedMemory(pThis);
5151 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 2, PCNET_GUEST_SHARED_MEMORY_SIZE,
5152 PCI_ADDRESS_SPACE_MEM, pcnetMMIOSharedMap);
5153 if (RT_FAILURE(rc))
5154 return rc;
5155 }
5156
5157 /*
5158 * Initialize critical section.
5159 * This must be done before register the critsect with the timer code, and also before
5160 * attaching drivers or anything else that may call us back.
5161 */
5162 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->CritSect, RT_SRC_POS, "PCNet#%d", iInstance);
5163 if (RT_FAILURE(rc))
5164 return rc;
5165
5166 rc = RTSemEventCreate(&pThis->hEventOutOfRxSpace);
5167 AssertRC(rc);
5168
5169#ifdef PCNET_NO_POLLING
5170 /*
5171 * Resolve the R0 and RC handlers.
5172 */
5173 rc = PDMR3LdrGetSymbolR0Lazy(PDMDevHlpGetVM(pDevIns), NULL, "EMInterpretInstruction", &pThis->pfnEMInterpretInstructionR0);
5174 if (RT_SUCCESS(rc))
5175 rc = PDMR3LdrGetSymbolRCLazy(PDMDevHlpGetVM(pDevIns), NULL, "EMInterpretInstruction", (RTGCPTR *)&pThis->pfnEMInterpretInstructionRC);
5176 AssertLogRelMsgRCReturn(rc, ("PDMR3LdrGetSymbolRCLazy(EMInterpretInstruction) -> %Rrc\n", rc), rc);
5177#else
5178 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, pcnetTimer, pThis,
5179 TMTIMER_FLAGS_NO_CRIT_SECT, "PCNet Poll Timer", &pThis->pTimerPollR3);
5180 if (RT_FAILURE(rc))
5181 return rc;
5182 pThis->pTimerPollR0 = TMTimerR0Ptr(pThis->pTimerPollR3);
5183 pThis->pTimerPollRC = TMTimerRCPtr(pThis->pTimerPollR3);
5184 TMR3TimerSetCritSect(pThis->pTimerPollR3, &pThis->CritSect);
5185#endif
5186 if (pThis->fAm79C973)
5187 {
5188 /* Software Interrupt timer */
5189 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, pcnetTimerSoftInt, pThis, /** @todo r=bird: the locking here looks bogus now with SMP... */
5190 TMTIMER_FLAGS_DEFAULT_CRIT_SECT, "PCNet SoftInt Timer", &pThis->pTimerSoftIntR3);
5191 if (RT_FAILURE(rc))
5192 return rc;
5193 pThis->pTimerSoftIntR0 = TMTimerR0Ptr(pThis->pTimerSoftIntR3);
5194 pThis->pTimerSoftIntRC = TMTimerRCPtr(pThis->pTimerSoftIntR3);
5195 }
5196 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, pcnetTimerRestore, pThis,
5197 TMTIMER_FLAGS_NO_CRIT_SECT, "PCNet Restore Timer", &pThis->pTimerRestore);
5198 if (RT_FAILURE(rc))
5199 return rc;
5200
5201 rc = PDMDevHlpSSMRegisterEx(pDevIns, PCNET_SAVEDSTATE_VERSION, sizeof(*pThis), NULL,
5202 NULL, pcnetLiveExec, NULL,
5203 pcnetSavePrep, pcnetSaveExec, NULL,
5204 pcnetLoadPrep, pcnetLoadExec, NULL);
5205 if (RT_FAILURE(rc))
5206 return rc;
5207
5208 /*
5209 * Create the transmit queue.
5210 */
5211 rc = PDMDevHlpQueueCreate(pDevIns, sizeof(PDMQUEUEITEMCORE), 1, 0,
5212 pcnetXmitQueueConsumer, true, "PCNet-Xmit", &pThis->pXmitQueueR3);
5213 if (RT_FAILURE(rc))
5214 return rc;
5215 pThis->pXmitQueueR0 = PDMQueueR0Ptr(pThis->pXmitQueueR3);
5216 pThis->pXmitQueueRC = PDMQueueRCPtr(pThis->pXmitQueueR3);
5217
5218 /*
5219 * Create the RX notifer signaller.
5220 */
5221 rc = PDMDevHlpQueueCreate(pDevIns, sizeof(PDMQUEUEITEMCORE), 1, 0,
5222 pcnetCanRxQueueConsumer, true, "PCNet-Rcv", &pThis->pCanRxQueueR3);
5223 if (RT_FAILURE(rc))
5224 return rc;
5225 pThis->pCanRxQueueR0 = PDMQueueR0Ptr(pThis->pCanRxQueueR3);
5226 pThis->pCanRxQueueRC = PDMQueueRCPtr(pThis->pCanRxQueueR3);
5227
5228 /*
5229 * Register the info item.
5230 */
5231 RTStrPrintf(szTmp, sizeof(szTmp), "pcnet%d", pDevIns->iInstance);
5232 PDMDevHlpDBGFInfoRegister(pDevIns, szTmp, "PCNET info.", pcnetInfo);
5233
5234 /*
5235 * Attach status driver (optional).
5236 */
5237 rc = PDMDevHlpDriverAttach(pDevIns, PDM_STATUS_LUN, &pThis->IBase, &pBase, "Status Port");
5238 if (RT_SUCCESS(rc))
5239 pThis->pLedsConnector = PDMIBASE_QUERY_INTERFACE(pBase, PDMILEDCONNECTORS);
5240 else if ( rc != VERR_PDM_NO_ATTACHED_DRIVER
5241 && rc != VERR_PDM_CFG_MISSING_DRIVER_NAME)
5242 {
5243 AssertMsgFailed(("Failed to attach to status driver. rc=%Rrc\n", rc));
5244 return rc;
5245 }
5246
5247 /*
5248 * Attach driver.
5249 */
5250 rc = PDMDevHlpDriverAttach(pDevIns, 0, &pThis->IBase, &pThis->pDrvBase, "Network Port");
5251 if (RT_SUCCESS(rc))
5252 {
5253 if (rc == VINF_NAT_DNS)
5254 {
5255#ifdef RT_OS_LINUX
5256 PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "NoDNSforNAT",
5257 N_("A Domain Name Server (DNS) for NAT networking could not be determined. Please check your /etc/resolv.conf for <tt>nameserver</tt> entries. Either add one manually (<i>man resolv.conf</i>) or ensure that your host is correctly connected to an ISP. If you ignore this warning the guest will not be able to perform nameserver lookups and it will probably observe delays if trying so"));
5258#else
5259 PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "NoDNSforNAT",
5260 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"));
5261#endif
5262 }
5263 pThis->pDrvR3 = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMINETWORKUP);
5264 AssertMsgReturn(pThis->pDrvR3, ("Failed to obtain the PDMINETWORKUP interface!\n"),
5265 VERR_PDM_MISSING_INTERFACE_BELOW);
5266 pThis->pDrvR0 = PDMIBASER0_QUERY_INTERFACE(PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMIBASER0), PDMINETWORKUP);
5267 pThis->pDrvRC = PDMIBASERC_QUERY_INTERFACE(PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMIBASERC), PDMINETWORKUP);
5268 }
5269 else if ( rc == VERR_PDM_NO_ATTACHED_DRIVER
5270 || rc == VERR_PDM_CFG_MISSING_DRIVER_NAME)
5271 {
5272 /* No error! */
5273 Log(("No attached driver!\n"));
5274 }
5275 else
5276 return rc;
5277
5278 /*
5279 * Reset the device state. (Do after attaching.)
5280 */
5281 pcnetHardReset(pThis);
5282
5283#ifdef VBOX_WITH_STATISTICS
5284 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatMMIOReadGC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling MMIO reads in GC", "/Devices/PCNet%d/MMIO/ReadGC", iInstance);
5285 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatMMIOReadHC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling MMIO reads in HC", "/Devices/PCNet%d/MMIO/ReadHC", iInstance);
5286 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatMMIOWriteGC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling MMIO writes in GC", "/Devices/PCNet%d/MMIO/WriteGC", iInstance);
5287 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatMMIOWriteHC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling MMIO writes in HC", "/Devices/PCNet%d/MMIO/WriteHC", iInstance);
5288 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatAPROMRead, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling APROM reads", "/Devices/PCNet%d/IO/APROMRead", iInstance);
5289 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatAPROMWrite, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling APROM writes", "/Devices/PCNet%d/IO/APROMWrite", iInstance);
5290 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatIOReadGC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling IO reads in GC", "/Devices/PCNet%d/IO/ReadGC", iInstance);
5291 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatIOReadHC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling IO reads in HC", "/Devices/PCNet%d/IO/ReadHC", iInstance);
5292 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatIOWriteGC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling IO writes in GC", "/Devices/PCNet%d/IO/WriteGC", iInstance);
5293 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatIOWriteHC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling IO writes in HC", "/Devices/PCNet%d/IO/WriteHC", iInstance);
5294 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatTimer, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling Timer", "/Devices/PCNet%d/Timer", iInstance);
5295 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatReceive, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling receive", "/Devices/PCNet%d/Receive", iInstance);
5296 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatRxOverflow, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_OCCURENCE, "Profiling RX overflows", "/Devices/PCNet%d/RxOverflow", iInstance);
5297 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatRxOverflowWakeup, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_OCCURENCE, "Nr of RX overflow wakeups", "/Devices/PCNet%d/RxOverflowWakeup", iInstance);
5298#endif
5299 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatReceiveBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Amount of data received", "/Devices/PCNet%d/ReceiveBytes", iInstance);
5300#ifdef VBOX_WITH_STATISTICS
5301 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatTransmitCase1, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Single descriptor transmit", "/Devices/PCNet%d/Transmit/Case1", iInstance);
5302 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatTransmitCase2, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Multi descriptor transmit", "/Devices/PCNet%d/Transmit/Case2", iInstance);
5303 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatTransmit, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling transmits in HC", "/Devices/PCNet%d/Transmit/Total", iInstance);
5304#endif
5305 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatTransmitBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Amount of data transmitted", "/Devices/PCNet%d/TransmitBytes", iInstance);
5306#ifdef VBOX_WITH_STATISTICS
5307 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatTransmitSend, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling PCNet send transmit in HC","/Devices/PCNet%d/Transmit/Send", iInstance);
5308 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatTdtePollGC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling PCNet TdtePoll in GC", "/Devices/PCNet%d/TdtePollGC", iInstance);
5309 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatTdtePollHC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling PCNet TdtePoll in HC", "/Devices/PCNet%d/TdtePollHC", iInstance);
5310 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatRdtePollGC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling PCNet RdtePoll in GC", "/Devices/PCNet%d/RdtePollGC", iInstance);
5311 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatRdtePollHC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling PCNet RdtePoll in HC", "/Devices/PCNet%d/RdtePollHC", iInstance);
5312
5313 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatTmdStoreGC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling PCNet TmdStore in GC", "/Devices/PCNet%d/TmdStoreGC", iInstance);
5314 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatTmdStoreHC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling PCNet TmdStore in HC", "/Devices/PCNet%d/TmdStoreHC", iInstance);
5315
5316 unsigned i;
5317 for (i = 0; i < RT_ELEMENTS(pThis->aStatXmitFlush) - 1; i++)
5318 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->aStatXmitFlush[i], STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES, "", "/Devices/PCNet%d/XmitFlushIrq/%d", iInstance, i + 1);
5319 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->aStatXmitFlush[i], STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES, "", "/Devices/PCNet%d/XmitFlushIrq/%d+", iInstance, i + 1);
5320
5321 for (i = 0; i < RT_ELEMENTS(pThis->aStatXmitChainCounts) - 1; i++)
5322 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->aStatXmitChainCounts[i], STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES, "", "/Devices/PCNet%d/XmitChainCounts/%d", iInstance, i + 1);
5323 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->aStatXmitChainCounts[i], STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES, "", "/Devices/PCNet%d/XmitChainCounts/%d+", iInstance, i + 1);
5324
5325 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatXmitSkipCurrent, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "", "/Devices/PCNet%d/Xmit/Skipped", iInstance, i + 1);
5326
5327 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatInterrupt, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling interrupt checks", "/Devices/PCNet%d/UpdateIRQ", iInstance);
5328 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatPollTimer, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling poll timer", "/Devices/PCNet%d/PollTimer", iInstance);
5329 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatMIIReads, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of MII reads", "/Devices/PCNet%d/MIIReads", iInstance);
5330# ifdef PCNET_NO_POLLING
5331 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatRCVRingWrite, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of receive ring writes", "/Devices/PCNet%d/Ring/RCVWrites", iInstance);
5332 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatTXRingWrite, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of transmit ring writes", "/Devices/PCNet%d/Ring/TXWrites", iInstance);
5333 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatRingWriteHC, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of monitored ring page writes", "/Devices/PCNet%d/Ring/HC/Writes", iInstance);
5334 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatRingWriteR0, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of monitored ring page writes", "/Devices/PCNet%d/Ring/R0/Writes", iInstance);
5335 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatRingWriteGC, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of monitored ring page writes", "/Devices/PCNet%d/Ring/GC/Writes", iInstance);
5336 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatRingWriteFailedHC, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of failed ring page writes", "/Devices/PCNet%d/Ring/HC/Failed", iInstance);
5337 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatRingWriteFailedR0, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of failed ring page writes", "/Devices/PCNet%d/Ring/R0/Failed", iInstance);
5338 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatRingWriteFailedGC, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of failed ring page writes", "/Devices/PCNet%d/Ring/GC/Failed", iInstance);
5339 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatRingWriteOutsideHC, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of monitored writes outside ring","/Devices/PCNet%d/Ring/HC/Outside", iInstance);
5340 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatRingWriteOutsideR0, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of monitored writes outside ring","/Devices/PCNet%d/Ring/R0/Outside", iInstance);
5341 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatRingWriteOutsideGC, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of monitored writes outside ring","/Devices/PCNet%d/Ring/GC/Outside", iInstance);
5342# endif /* PCNET_NO_POLLING */
5343#endif
5344
5345 return VINF_SUCCESS;
5346}
5347
5348
5349/**
5350 * The device registration structure.
5351 */
5352const PDMDEVREG g_DevicePCNet =
5353{
5354 /* u32Version */
5355 PDM_DEVREG_VERSION,
5356 /* szName */
5357 "pcnet",
5358 /* szRCMod */
5359#ifdef PCNET_GC_ENABLED
5360 "VBoxDDGC.gc",
5361 "VBoxDDR0.r0",
5362#else
5363 "",
5364 "",
5365#endif
5366 /* pszDescription */
5367 "AMD PC-Net II Ethernet controller.\n",
5368 /* fFlags */
5369#ifdef PCNET_GC_ENABLED
5370 PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
5371#else
5372 PDM_DEVREG_FLAGS_DEFAULT_BITS,
5373#endif
5374 /* fClass */
5375 PDM_DEVREG_CLASS_NETWORK,
5376 /* cMaxInstances */
5377 8,
5378 /* cbInstance */
5379 sizeof(PCNetState),
5380 /* pfnConstruct */
5381 pcnetConstruct,
5382 /* pfnDestruct */
5383 pcnetDestruct,
5384 /* pfnRelocate */
5385 pcnetRelocate,
5386 /* pfnIOCtl */
5387 NULL,
5388 /* pfnPowerOn */
5389 NULL,
5390 /* pfnReset */
5391 pcnetReset,
5392 /* pfnSuspend */
5393 pcnetSuspend,
5394 /* pfnResume */
5395 NULL,
5396#ifdef VBOX_DYNAMIC_NET_ATTACH
5397 /* pfnAttach */
5398 pcnetAttach,
5399 /* pfnDetach */
5400 pcnetDetach,
5401#else /* !VBOX_DYNAMIC_NET_ATTACH */
5402 /* pfnAttach */
5403 NULL,
5404 /* pfnDetach */
5405 NULL,
5406#endif /* !VBOX_DYNAMIC_NET_ATTACH */
5407 /* pfnQueryInterface. */
5408 NULL,
5409 /* pfnInitComplete. */
5410 NULL,
5411 /* pfnPowerOff. */
5412 pcnetPowerOff,
5413 /* pfnSoftReset */
5414 NULL,
5415 /* u32VersionEnd */
5416 PDM_DEVREG_VERSION
5417};
5418
5419#endif /* IN_RING3 */
5420#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
5421
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