VirtualBox

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

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

PCNet: Don't flood the release log with errors

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