VirtualBox

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

Last change on this file since 32048 was 30722, checked in by vboxsync, 14 years ago

Removed some instances of obsolete PCISetIrqNoWait calls.

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