VirtualBox

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

Last change on this file since 1507 was 1377, checked in by vboxsync, 18 years ago

hard reset pcnet on reboot (at least to switch off BM)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 166.0 KB
Line 
1/** @file
2 *
3 * VBox network devices:
4 * AMD PC-Net II (Am79C970A + Am79C973) Ethernet Controller
5 */
6
7/*
8 * Copyright (C) 2006 InnoTek Systemberatung GmbH
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License as published by the Free Software Foundation,
14 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
15 * distribution. VirtualBox OSE is distributed in the hope that it will
16 * be useful, but WITHOUT ANY WARRANTY of any kind.
17 *
18 * If you received this file as part of a commercial VirtualBox
19 * distribution, then only the terms of your commercial VirtualBox
20 * license agreement apply instead of the previous paragraph.
21 *
22 * --------------------------------------------------------------------
23 *
24 * This code is based on:
25 *
26 * AMD PC-Net II (Am79C970A) emulation
27 *
28 * Copyright (c) 2004 Antony T Curtis
29 *
30 * Permission is hereby granted, free of charge, to any person obtaining a copy
31 * of this software and associated documentation files (the "Software"), to deal
32 * in the Software without restriction, including without limitation the rights
33 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
34 * copies of the Software, and to permit persons to whom the Software is
35 * furnished to do so, subject to the following conditions:
36 *
37 * The above copyright notice and this permission notice shall be included in
38 * all copies or substantial portions of the Software.
39 *
40 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
41 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
42 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
43 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
44 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
45 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
46 * THE SOFTWARE.
47 */
48
49/* This software was written to be compatible with the specification:
50 * AMD Am79C970A PCnet-PCI II Ethernet Controller Data-Sheet
51 * AMD Publication# 19436 Rev:E Amendment/0 Issue Date: June 2000
52 */
53
54/*******************************************************************************
55* Header Files *
56*******************************************************************************/
57#define LOG_GROUP LOG_GROUP_DEV_PCNET
58#include <VBox/err.h>
59#include <VBox/log.h>
60#include <VBox/mm.h>
61#include <VBox/pdm.h>
62#include <VBox/pgm.h>
63#include <VBox/stam.h>
64#include <VBox/vm.h> /* for VM_IS_EMT */
65#include <iprt/asm.h>
66#include <iprt/assert.h>
67#include <iprt/critsect.h>
68#include <iprt/string.h>
69#include <iprt/time.h>
70#ifdef IN_RING3
71#include <iprt/mem.h>
72#include <iprt/semaphore.h>
73#endif
74
75#include "Builtins.h"
76#include "vl_vbox.h"
77
78/* Enable this to catch writes to the ring descriptors instead of using excessive polling */
79/* #define PCNET_NO_POLLING */
80
81/* Enable to handle frequent io reads in the guest context */
82#define PCNET_GC_ENABLED
83
84#ifdef __GNUC__
85#define PACKED __attribute__ ((packed))
86#else
87#define PACKED
88#endif
89
90#if 0
91#define LOG_REGISTER(a) LogRel(a)
92#else
93#define LOG_REGISTER(a)
94#endif
95#if 0
96#define LOG_PACKET(name, buf, count) LogPkt(name, buf, count)
97#define LOG_PACKETS
98#else
99#define LOG_PACKET(name, buf, count)
100#undef LOG_PACKETS
101#endif
102
103#if defined(LOG_ENABLED)
104#define PCNET_DEBUG_IO
105#define PCNET_DEBUG_BCR
106#define PCNET_DEBUG_CSR
107#define PCNET_DEBUG_RMD
108#define PCNET_DEBUG_TMD
109#define PCNET_DEBUG_MATCH
110#define PCNET_DEBUG_MII
111#endif
112
113#define PCNET_IOPORT_SIZE 0x20
114#define PCNET_PNPMMIO_SIZE 0x20
115
116#define PCNET_SAVEDSTATE_VERSION 5
117
118#define BCR_MAX_RAP 50
119#define MII_MAX_REG 32
120#define CSR_MAX_REG 128
121
122/* Maximum number of times we report a link down to the guest (failure to send frame) */
123#define PCNET_MAX_LINKDOWN_REPORTED 3
124
125/* Frame cache */
126typedef struct PCNETFRAME
127{
128 /** The current frame size. Starts at -1. Only the top frame can be expanded. */
129 int32_t cb;
130#if HC_ARCH_BITS == 64
131 uint32_t Alignment;
132#endif
133 /** The virtual address of the frame (copied or direct pointer) */
134 RTR3PTR pvBuf;
135} PCNETFRAME;
136/* Pointer to PCNETFRAME */
137typedef PCNETFRAME *PPCNETFRAME;
138
139typedef struct PCNetState_st PCNetState;
140
141struct PCNetState_st
142{
143 PCIDEVICE PciDev;
144#ifndef PCNET_NO_POLLING
145 /** Poll timer (address for host context) */
146 PTMTIMERHC pTimerPollHC;
147 /** Poll timer (address for guest context) */
148 PTMTIMERGC pTimerPollGC;
149#endif
150 /** Register Address Pointer */
151 uint32_t u32RAP;
152 /** Internal interrupt service */
153 int32_t iISR;
154 /** ??? */
155 uint32_t u32Lnkst;
156 /** Address of the RX descriptor table (ring). Loaded at init. */
157 RTGCPHYS GCRDRA;
158 /** Address of the TX descriptor table (ring). Loaded at init. */
159 RTGCPHYS GCTDRA;
160 uint8_t aPROM[16];
161 uint16_t aCSR[CSR_MAX_REG];
162 uint16_t aBCR[BCR_MAX_RAP];
163 uint16_t aMII[MII_MAX_REG];
164 uint16_t u16CSR0LastSeenByGuest; /** @todo SSM!! */
165 uint16_t Alignment0[HC_ARCH_BITS == 32 ? 2 : 4];
166 /** Last time we polled the queues */
167 uint64_t u64LastPoll;
168
169 /** Array of frames. */
170 PCNETFRAME SendFrame;
171 /** The xmit buffer. */
172 uint8_t abSendBuf[4096];
173 /** The recv buffer. */
174 uint8_t abRecvBuf[4096];
175
176 /** Pending send packet counter. */
177 uint32_t cPendingSends;
178
179 /** Size of a RX/TX descriptor (8 or 16 bytes according to SWSTYLE */
180 int iLog2DescSize;
181 /** Bits 16..23 in 16-bit mode */
182 RTGCPHYS GCUpperPhys;
183
184 /** Transmit signaller */
185 GCPTRTYPE(PPDMQUEUE) pXmitQueueGC;
186 HCPTRTYPE(PPDMQUEUE) pXmitQueueHC;
187
188 /** Receive signaller */
189 HCPTRTYPE(PPDMQUEUE) pCanRxQueueHC;
190 GCPTRTYPE(PPDMQUEUE) pCanRxQueueGC;
191 /** Pointer to the device instance. */
192 GCPTRTYPE(PPDMDEVINS) pDevInsGC;
193 /** Pointer to the device instance. */
194 HCPTRTYPE(PPDMDEVINS) pDevInsHC;
195 /** Restore timer.
196 * This is used to disconnect and reconnect the link after a restore. */
197 PTMTIMERHC pTimerRestore;
198 /** Pointer to the connector of the attached network driver. */
199 HCPTRTYPE(PPDMINETWORKCONNECTOR) pDrv;
200 /** Pointer to the attached network driver. */
201 HCPTRTYPE(PPDMIBASE) pDrvBase;
202 /** The base interface. */
203 PDMIBASE IBase;
204 /** The network port interface. */
205 PDMINETWORKPORT INetworkPort;
206 /** The network config port interface. */
207 PDMINETWORKCONFIG INetworkConfig;
208 /** Base address of the MMIO region. */
209 RTGCPHYS MMIOBase;
210 /** Base port of the I/O space region. */
211 RTIOPORT IOPortBase;
212 /** If set the link is currently up. */
213 bool fLinkUp;
214 /** If set the link is temporarily down because of a saved state load. */
215 bool fLinkTempDown;
216
217 /** Number of times we've reported the link down. */
218 RTUINT cLinkDownReported;
219#if HC_ARCH_BITS == 64 || GC_ARCH_BITS == 64
220 RTUINT Alignment;
221#endif
222 /** The configured MAC address. */
223 PDMMAC MacConfigured;
224
225 /** The LED. */
226 PDMLED Led;
227 /** The LED ports. */
228 PDMILEDPORTS ILeds;
229 /** Partner of ILeds. */
230 HCPTRTYPE(PPDMILEDCONNECTORS) pLedsConnector;
231
232 /** Async send thread */
233 RTSEMEVENT hSendEventSem;
234 RTTHREAD hSendThread;
235
236 /** Access critical section. */
237 PDMCRITSECT CritSect;
238
239#ifdef PCNET_NO_POLLING
240 RTGCPHYS TDRAPhysOld;
241 uint32_t cbTDRAOld;
242
243 RTGCPHYS RDRAPhysOld;
244 uint32_t cbRDRAOld;
245
246 DECLGCCALLBACKMEMBER(int, pfnEMInterpretInstructionGC, (PVM pVM, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize));
247 DECLR0CALLBACKMEMBER(int, pfnEMInterpretInstructionR0, (PVM pVM, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize));
248#endif
249
250 bool fGCEnabled;
251 bool fR0Enabled;
252 bool fAm79C973;
253 bool afAlignment[5];
254
255#ifdef VBOX_WITH_STATISTICS
256 STAMPROFILEADV StatMMIOReadGC;
257 STAMPROFILEADV StatMMIOReadHC;
258 STAMPROFILEADV StatMMIOWriteGC;
259 STAMPROFILEADV StatMMIOWriteHC;
260 STAMPROFILEADV StatAPROMRead;
261 STAMPROFILEADV StatAPROMWrite;
262 STAMPROFILEADV StatIOReadGC;
263 STAMPROFILEADV StatIOReadHC;
264 STAMPROFILEADV StatIOWriteGC;
265 STAMPROFILEADV StatIOWriteHC;
266 STAMPROFILEADV StatTimer;
267 STAMPROFILEADV StatReceive;
268 STAMPROFILEADV StatTransmit;
269 STAMPROFILEADV StatTransmitSend;
270 STAMPROFILEADV StatTdtePollGC;
271 STAMPROFILEADV StatTdtePollHC;
272 STAMPROFILEADV StatTmdStoreGC;
273 STAMPROFILEADV StatTmdStoreHC;
274 STAMPROFILEADV StatRdtePollGC;
275 STAMPROFILEADV StatRdtePollHC;
276 STAMCOUNTER aStatXmitFlush[16];
277 STAMCOUNTER aStatXmitChainCounts[16];
278 STAMCOUNTER StatXmitSkipCurrent;
279 STAMPROFILEADV StatInterrupt;
280 STAMPROFILEADV StatPollTimer;
281 STAMCOUNTER StatMIIReads;
282# ifdef PCNET_NO_POLLING
283 STAMCOUNTER StatRCVRingWrite;
284 STAMCOUNTER StatTXRingWrite;
285 STAMCOUNTER StatRingWriteHC;
286 STAMCOUNTER StatRingWriteR0;
287 STAMCOUNTER StatRingWriteGC;
288
289 STAMCOUNTER StatRingWriteFailedHC;
290 STAMCOUNTER StatRingWriteFailedR0;
291 STAMCOUNTER StatRingWriteFailedGC;
292
293 STAMCOUNTER StatRingWriteOutsideRangeHC;
294 STAMCOUNTER StatRingWriteOutsideRangeR0;
295 STAMCOUNTER StatRingWriteOutsideRangeGC;
296# endif
297#endif /* VBOX_WITH_STATISTICS */
298};
299
300#define PCNETSTATE_2_DEVINS(pPCNet) ( (pPCNet)->CTXSUFF(pDevIns) )
301#define PCIDEV_2_PCNETSTATE(pPciDev) ( (PCNetState *)(pPciDev) )
302
303/* BUS CONFIGURATION REGISTERS */
304#define BCR_MSRDA 0
305#define BCR_MSWRA 1
306#define BCR_MC 2
307#define BCR_RESERVED3 3
308#define BCR_LNKST 4
309#define BCR_LED1 5
310#define BCR_LED2 6
311#define BCR_LED3 7
312#define BCR_RESERVED8 8
313#define BCR_FDC 9
314/* 10 - 15 = reserved */
315#define BCR_IOBASEL 16 /* Reserved */
316#define BCR_IOBASEU 16 /* Reserved */
317#define BCR_BSBC 18
318#define BCR_EECAS 19
319#define BCR_SWS 20
320#define BCR_INTCON 21 /* Reserved */
321#define BCR_PLAT 22
322#define BCR_PCISID 23
323#define BCR_PCISVID 24
324#define BCR_SRAMSIZ 25
325#define BCR_SRAMB 26
326#define BCR_SRAMIC 27
327#define BCR_EBADDRL 28
328#define BCR_EBADDRU 29
329#define BCR_EBD 30
330#define BCR_STVAL 31
331#define BCR_MIICAS 32
332#define BCR_MIIADDR 33
333#define BCR_MIIMDR 34
334#define BCR_PCIVID 35
335#define BCR_PMC_A 36
336#define BCR_DATA0 37
337#define BCR_DATA1 38
338#define BCR_DATA2 39
339#define BCR_DATA3 40
340#define BCR_DATA4 41
341#define BCR_DATA5 42
342#define BCR_DATA6 43
343#define BCR_DATA7 44
344#define BCR_PMR1 45
345#define BCR_PMR2 46
346#define BCR_PMR3 47
347
348#define BCR_DWIO(S) !!((S)->aBCR[BCR_BSBC] & 0x0080)
349#define BCR_SSIZE32(S) !!((S)->aBCR[BCR_SWS ] & 0x0100)
350#define BCR_SWSTYLE(S) ((S)->aBCR[BCR_SWS ] & 0x00FF)
351
352#define CSR_INIT(S) !!((S)->aCSR[0] & 0x0001) /**< Init assertion */
353#define CSR_STRT(S) !!((S)->aCSR[0] & 0x0002) /**< Start assertion */
354#define CSR_STOP(S) !!((S)->aCSR[0] & 0x0004) /**< Stop assertion */
355#define CSR_TDMD(S) !!((S)->aCSR[0] & 0x0008) /**< Transmit demand. (perform xmit poll now
356 (readable, settable, not clearable) */
357#define CSR_TXON(S) !!((S)->aCSR[0] & 0x0010) /**< Transmit on (readonly) */
358#define CSR_RXON(S) !!((S)->aCSR[0] & 0x0020) /**< Receive On */
359#define CSR_INEA(S) !!((S)->aCSR[0] & 0x0040) /**< Interrupt Enable */
360#define CSR_LAPPEN(S) !!((S)->aCSR[3] & 0x0020) /**< Look Ahead Packet Processing Enable */
361#define CSR_DXSUFLO(S) !!((S)->aCSR[3] & 0x0040) /**< Disable Transmit Stop on
362 Underflow error */
363#define CSR_ASTRP_RCV(S) !!((S)->aCSR[4] & 0x0400) /**< Auto Strip Receive */
364#define CSR_DPOLL(S) !!((S)->aCSR[4] & 0x1000) /**< Disable Transmit Polling */
365#define CSR_SPND(S) !!((S)->aCSR[5] & 0x0001) /**< Suspend */
366#define CSR_LTINTEN(S) !!((S)->aCSR[5] & 0x4000) /**< Last Transmit Interrupt Enable */
367#define CSR_TOKINTD(S) !!((S)->aCSR[5] & 0x8000) /**< Transmit OK Interrupt Disable */
368#define CSR_DRX(S) !!((S)->aCSR[15] & 0x0001) /**< Disable Receiver */
369#define CSR_DTX(S) !!((S)->aCSR[15] & 0x0002) /**< Disable Transmit */
370#define CSR_LOOP(S) !!((S)->aCSR[15] & 0x0004) /**< Loopback Enable */
371#define CSR_DRCVPA(S) !!((S)->aCSR[15] & 0x2000) /**< Disable Receive Physical Address */
372#define CSR_DRCVBC(S) !!((S)->aCSR[15] & 0x4000) /**< Disable Receive Broadcast */
373#define CSR_PROM(S) !!((S)->aCSR[15] & 0x8000) /**< Promiscuous Mode */
374
375#if !defined(__X86__) && !defined(__AMD64__)
376#error fix macros (and more in this file) for big-endian machines
377#endif
378
379#define CSR_IADR(S) (*(uint32_t*)((S)->aCSR + 1)) /**< Initialization Block Address */
380#define CSR_CRBA(S) (*(uint32_t*)((S)->aCSR + 18)) /**< Current Receive Buffer Address */
381#define CSR_CXBA(S) (*(uint32_t*)((S)->aCSR + 20)) /**< Current Transmit Buffer Address */
382#define CSR_NRBA(S) (*(uint32_t*)((S)->aCSR + 22)) /**< Next Receive Buffer Address */
383#define CSR_BADR(S) (*(uint32_t*)((S)->aCSR + 24)) /**< Base Address of Receive Ring */
384#define CSR_NRDA(S) (*(uint32_t*)((S)->aCSR + 26)) /**< Next Receive Descriptor Address */
385#define CSR_CRDA(S) (*(uint32_t*)((S)->aCSR + 28)) /**< Current Receive Descriptor Address */
386#define CSR_BADX(S) (*(uint32_t*)((S)->aCSR + 30)) /**< Base Address of Transmit Descriptor */
387#define CSR_NXDA(S) (*(uint32_t*)((S)->aCSR + 32)) /**< Next Transmit Descriptor Address */
388#define CSR_CXDA(S) (*(uint32_t*)((S)->aCSR + 34)) /**< Current Transmit Descriptor Address */
389#define CSR_NNRD(S) (*(uint32_t*)((S)->aCSR + 36)) /**< Next Next Receive Descriptor Address */
390#define CSR_NNXD(S) (*(uint32_t*)((S)->aCSR + 38)) /**< Next Next Transmit Descriptor Address */
391#define CSR_CRBC(S) ((S)->aCSR[40]) /**< Current Receive Byte Count */
392#define CSR_CRST(S) ((S)->aCSR[41]) /**< Current Receive Status */
393#define CSR_CXBC(S) ((S)->aCSR[42]) /**< Current Transmit Byte Count */
394#define CSR_CXST(S) ((S)->aCSR[43]) /**< Current transmit status */
395#define CSR_NRBC(S) ((S)->aCSR[44]) /**< Next Receive Byte Count */
396#define CSR_NRST(S) ((S)->aCSR[45]) /**< Next Receive Status */
397#define CSR_POLL(S) ((S)->aCSR[46]) /**< Transmit Poll Time Counter */
398#define CSR_PINT(S) ((S)->aCSR[47]) /**< Transmit Polling Interval */
399#define CSR_PXDA(S) (*(uint32_t*)((S)->aCSR + 60)) /**< Previous Transmit Descriptor Address*/
400#define CSR_PXBC(S) ((S)->aCSR[62]) /**< Previous Transmit Byte Count */
401#define CSR_PXST(S) ((S)->aCSR[63]) /**< Previous Transmit Status */
402#define CSR_NXBA(S) (*(uint32_t*)((S)->aCSR + 64)) /**< Next Transmit Buffer Address */
403#define CSR_NXBC(S) ((S)->aCSR[66]) /**< Next Transmit Byte Count */
404#define CSR_NXST(S) ((S)->aCSR[67]) /**< Next Transmit Status */
405#define CSR_RCVRC(S) ((S)->aCSR[72]) /**< Receive Descriptor Ring Counter */
406#define CSR_XMTRC(S) ((S)->aCSR[74]) /**< Transmit Descriptor Ring Counter */
407#define CSR_RCVRL(S) ((S)->aCSR[76]) /**< Receive Descriptor Ring Length */
408#define CSR_XMTRL(S) ((S)->aCSR[78]) /**< Transmit Descriptor Ring Length */
409#define CSR_MISSC(S) ((S)->aCSR[112]) /**< Missed Frame Count */
410
411#define PHYSADDR(S,A) ((A) | (S)->GCUpperPhys)
412
413/* Version for the PCnet/FAST III 79C973 card */
414#define CSR_VERSION_LOW_79C973 0x5003 /* the lower two bits must be 11b for AMD */
415#define CSR_VERSION_LOW_79C970A 0x1003 /* the lower two bits must be 11b for AMD */
416#define CSR_VERSION_HIGH 0x0262
417
418/** @todo All structs: big endian? */
419
420#pragma pack(1) /* bird: MSC paranoia */
421/** frank: From the gcc manual: ``This attribute, attached to `struct' or `union' type
422 * definition, specifies that each member (other than zero-width bitfields) of
423 * the structure or union is placed to minimize the memory required. ...
424 * Specifying this attribute for `struct' and `union' types is equivalent to
425 * specifying the `packed attribute' on each the structure or union members.''
426 * @todo r=bird: #pragma pack(1) / __attribute__((packed)) isn't necessary here
427 * because of the way the alignment rules work.
428 */
429struct PACKED INITBLK16
430{
431 uint16_t mode; /**< copied into csr15 */
432 uint16_t padr1; /**< MAC 0..15 */
433 uint16_t padr2; /**< MAC 16..32 */
434 uint16_t padr3; /**< MAC 33..47 */
435 uint16_t ladrf1; /**< logical address filter 0..15 */
436 uint16_t ladrf2; /**< logical address filter 16..31 */
437 uint16_t ladrf3; /**< logical address filter 32..47 */
438 uint16_t ladrf4; /**< logical address filter 48..63 */
439 uint32_t rdra:24; /**< address of receive descriptor ring */
440 uint32_t res1:5; /**< reserved */
441 uint32_t rlen:3; /**< number of receive descriptor ring entries */
442 uint32_t tdra:24; /**< address of transmit descriptor ring */
443 uint32_t res2:5; /**< reserved */
444 uint32_t tlen:3; /**< number of transmit descriptor ring entries */
445};
446AssertCompileSize(INITBLK16, 24);
447
448/** bird: I've changed the type for the bitfields. They should only be 16-bit all together.
449 * frank: I've changed the bitfiled types to uint32_t to prevent compiler warnings. */
450struct PACKED INITBLK32
451{
452 uint16_t mode; /**< copied into csr15 */
453 uint16_t res1:4; /**< reserved */
454 uint16_t rlen:4; /**< number of receive descriptor ring entries */
455 uint16_t res2:4; /**< reserved */
456 uint16_t tlen:4; /**< number of transmit descriptor ring entries */
457 uint16_t padr1; /**< MAC 0..15 */
458 uint16_t padr2; /**< MAC 16..31 */
459 uint16_t padr3; /**< MAC 32..47 */
460 uint16_t res3; /**< reserved */
461 uint16_t ladrf1; /**< logical address filter 0..15 */
462 uint16_t ladrf2; /**< logical address filter 16..31 */
463 uint16_t ladrf3; /**< logibal address filter 32..47 */
464 uint16_t ladrf4; /**< logical address filter 48..63 */
465 uint32_t rdra; /**< address of receive descriptor ring */
466 uint32_t tdra; /**< address of transmit descriptor ring */
467};
468AssertCompileSize(INITBLK32, 28);
469
470/** Transmit Message Descriptor */
471typedef struct TMD
472{
473 struct
474 {
475 uint32_t tbadr; /**< transmit buffer address */
476 } tmd0;
477 struct PACKED
478 {
479 uint32_t bcnt:12; /**< buffer byte count (two's complement) */
480 uint32_t ones:4; /**< must be 1111b */
481 uint32_t res:7; /**< reserved */
482 uint32_t bpe:1; /**< bus parity error */
483 uint32_t enp:1; /**< end of packet */
484 uint32_t stp:1; /**< start of packet */
485 uint32_t def:1; /**< deferred */
486 uint32_t one:1; /**< exactly one retry was needed to transmit a frame */
487 uint32_t ltint:1; /**< suppress interrupts after successful transmission */
488 uint32_t nofcs:1; /**< when set, the state of DXMTFCS is ignored and
489 transmitter FCS generation is activated. */
490 uint32_t err:1; /**< error occured */
491 uint32_t own:1; /**< 0=owned by guest driver, 1=owned by controller */
492 } tmd1;
493 struct PACKED
494 {
495 uint32_t trc:4; /**< transmit retry count */
496 uint32_t res:12; /**< reserved */
497 uint32_t tdr:10; /**< ??? */
498 uint32_t rtry:1; /**< retry error */
499 uint32_t lcar:1; /**< loss of carrier */
500 uint32_t lcol:1; /**< late collision */
501 uint32_t exdef:1; /**< excessive deferral */
502 uint32_t uflo:1; /**< underflow error */
503 uint32_t buff:1; /**< out of buffers (ENP not found) */
504 } tmd2;
505 struct
506 {
507 uint32_t res; /**< reserved for user defined space */
508 } tmd3;
509} TMD;
510AssertCompileSize(TMD, 16);
511
512/** Receive Message Descriptor */
513typedef struct RMD
514{
515 struct
516 {
517 uint32_t rbadr; /**< receive buffer address */
518 } rmd0;
519 struct PACKED
520 {
521 uint32_t bcnt:12; /**< buffer byte count (two's complement) */
522 uint32_t ones:4; /**< must be 1111b */
523 uint32_t res:4; /**< reserved */
524 uint32_t bam:1; /**< broadcast address match */
525 uint32_t lafm:1; /**< logical filter address match */
526 uint32_t pam:1; /**< physcial address match */
527 uint32_t bpe:1; /**< bus parity error */
528 uint32_t enp:1; /**< end of packet */
529 uint32_t stp:1; /**< start of packet */
530 uint32_t buff:1; /**< buffer error */
531 uint32_t crc:1; /**< crc error on incoming frame */
532 uint32_t oflo:1; /**< overflow error (lost all or part of incoming frame) */
533 uint32_t fram:1; /**< frame error */
534 uint32_t err:1; /**< error occured */
535 uint32_t own:1; /**< 0=owned by guest driver, 1=owned by controller */
536 } rmd1;
537 struct PACKED
538 {
539 uint32_t mcnt:12; /**< message byte count */
540 uint32_t zeros:4; /**< 0000b */
541 uint32_t rpc:8; /**< receive frame tag */
542 uint32_t rcc:8; /**< receive frame tag + reserved */
543 } rmd2;
544 struct
545 {
546 uint32_t res; /**< reserved for user defined space */
547 } rmd3;
548} RMD;
549AssertCompileSize(RMD, 16);
550#pragma pack()
551
552
553#ifndef VBOX_DEVICE_STRUCT_TESTCASE
554/*******************************************************************************
555* Internal Functions *
556*******************************************************************************/
557#define PRINT_TMD(T) Log2(( \
558 "TMD0 : TBADR=0x%08x\n" \
559 "TMD1 : OWN=%d, ERR=%d, FCS=%d, LTI=%d, " \
560 "ONE=%d, DEF=%d, STP=%d, ENP=%d,\n" \
561 " BPE=%d, BCNT=%d\n" \
562 "TMD2 : BUF=%d, UFL=%d, EXD=%d, LCO=%d, " \
563 "LCA=%d, RTR=%d,\n" \
564 " TDR=%d, TRC=%d\n", \
565 (T)->tmd0.tbadr, \
566 (T)->tmd1.own, (T)->tmd1.err, (T)->tmd1.nofcs, \
567 (T)->tmd1.ltint, (T)->tmd1.one, (T)->tmd1.def, \
568 (T)->tmd1.stp, (T)->tmd1.enp, (T)->tmd1.bpe, \
569 4096-(T)->tmd1.bcnt, \
570 (T)->tmd2.buff, (T)->tmd2.uflo, (T)->tmd2.exdef,\
571 (T)->tmd2.lcol, (T)->tmd2.lcar, (T)->tmd2.rtry, \
572 (T)->tmd2.tdr, (T)->tmd2.trc))
573
574#define PRINT_RMD(R) Log2(( \
575 "RMD0 : RBADR=0x%08x\n" \
576 "RMD1 : OWN=%d, ERR=%d, FRAM=%d, OFLO=%d, " \
577 "CRC=%d, BUFF=%d, STP=%d, ENP=%d,\n " \
578 "BPE=%d, PAM=%d, LAFM=%d, BAM=%d, ONES=%d, BCNT=%d\n" \
579 "RMD2 : RCC=%d, RPC=%d, MCNT=%d, ZEROS=%d\n", \
580 (R)->rmd0.rbadr, \
581 (R)->rmd1.own, (R)->rmd1.err, (R)->rmd1.fram, \
582 (R)->rmd1.oflo, (R)->rmd1.crc, (R)->rmd1.buff, \
583 (R)->rmd1.stp, (R)->rmd1.enp, (R)->rmd1.bpe, \
584 (R)->rmd1.pam, (R)->rmd1.lafm, (R)->rmd1.bam, \
585 (R)->rmd1.ones, 4096-(R)->rmd1.bcnt, \
586 (R)->rmd2.rcc, (R)->rmd2.rpc, (R)->rmd2.mcnt, \
587 (R)->rmd2.zeros))
588
589/**
590 * Load transmit message descriptor
591 * Make sure we read the own flag first.
592 */
593DECLINLINE(void) pcnetTmdLoad(PCNetState *pData, TMD *tmd, RTGCPHYS addr)
594{
595 PPDMDEVINS pDevIns = PCNETSTATE_2_DEVINS(pData);
596 uint8_t ownbyte;
597
598 if (!BCR_SWSTYLE(pData))
599 {
600 uint16_t xda[4];
601
602 PDMDevHlpPhysRead(pDevIns, addr+3, &ownbyte, 1);
603 PDMDevHlpPhysRead(pDevIns, addr, (void*)&xda[0], sizeof(xda));
604 ((uint32_t *)tmd)[0] = (uint32_t)xda[0] | ((uint32_t)(xda[1] & 0x00ff) << 16);
605 ((uint32_t *)tmd)[1] = (uint32_t)xda[2] | ((uint32_t)(xda[1] & 0xff00) << 16);
606 ((uint32_t *)tmd)[2] = (uint32_t)xda[3] << 16;
607 ((uint32_t *)tmd)[3] = 0;
608 }
609 else if (BCR_SWSTYLE(pData) != 3)
610 {
611 PDMDevHlpPhysRead(pDevIns, addr+7, &ownbyte, 1);
612 PDMDevHlpPhysRead(pDevIns, addr, (void*)tmd, 16);
613 }
614 else
615 {
616 uint32_t xda[4];
617 PDMDevHlpPhysRead(pDevIns, addr+7, &ownbyte, 1);
618 PDMDevHlpPhysRead(pDevIns, addr, (void*)&xda[0], sizeof(xda));
619 ((uint32_t *)tmd)[0] = xda[2];
620 ((uint32_t *)tmd)[1] = xda[1];
621 ((uint32_t *)tmd)[2] = xda[0];
622 ((uint32_t *)tmd)[3] = xda[3];
623 }
624 /* Double check the own bit; guest drivers might be buggy and lock prefixes in the recompiler are ignored by other threads. */
625#ifdef DEBUG
626 if (tmd->tmd1.own == 1 && !(ownbyte & 0x80))
627 Log(("pcnetTmdLoad: own bit flipped while reading!!\n"));
628#endif
629 if (!(ownbyte & 0x80))
630 tmd->tmd1.own = 0;
631}
632
633/**
634 * Store transmit message descriptor and hand it over to the host (the VM guest).
635 * Make sure that all data are transmitted before we clear the own flag.
636 */
637DECLINLINE(void) pcnetTmdStorePassHost(PCNetState *pData, TMD *tmd, RTGCPHYS addr)
638{
639 STAM_PROFILE_ADV_START(&pData->CTXSUFF(StatTmdStore), a);
640 PPDMDEVINS pDevIns = PCNETSTATE_2_DEVINS(pData);
641 if (!BCR_SWSTYLE(pData))
642 {
643 uint16_t xda[4];
644 xda[0] = ((uint32_t *)tmd)[0] & 0xffff;
645 xda[1] = ((((uint32_t *)tmd)[0] >> 16) & 0xff) | ((((uint32_t *)tmd)[1]>>16) & 0xff00);
646 xda[2] = ((uint32_t *)tmd)[1] & 0xffff;
647 xda[3] = ((uint32_t *)tmd)[2] >> 16;
648 xda[1] |= 0x8000;
649 PDMDevHlpPhysWrite(pDevIns, addr, (void*)&xda[0], sizeof(xda));
650 xda[1] &= ~0x8000;
651 PDMDevHlpPhysWrite(pDevIns, addr+3, (uint8_t*)xda + 3, 1);
652 }
653 else if (BCR_SWSTYLE(pData) != 3)
654 {
655 ((uint32_t*)tmd)[1] |= 0x80000000;
656 PDMDevHlpPhysWrite(pDevIns, addr, (void*)tmd, 16);
657 ((uint32_t*)tmd)[1] &= ~0x80000000;
658 PDMDevHlpPhysWrite(pDevIns, addr+7, (uint8_t*)tmd + 7, 1);
659 }
660 else
661 {
662 uint32_t xda[4];
663 xda[0] = ((uint32_t *)tmd)[2];
664 xda[1] = ((uint32_t *)tmd)[1];
665 xda[2] = ((uint32_t *)tmd)[0];
666 xda[3] = ((uint32_t *)tmd)[3];
667 xda[1] |= 0x80000000;
668 PDMDevHlpPhysWrite(pDevIns, addr, (void*)&xda[0], sizeof(xda));
669 xda[1] &= ~0x80000000;
670 PDMDevHlpPhysWrite(pDevIns, addr+7, (uint8_t*)xda + 7, 1);
671 }
672 STAM_PROFILE_ADV_STOP(&pData->CTXSUFF(StatTmdStore), a);
673}
674
675/**
676 * Load receive message descriptor
677 * Make sure we read the own flag first.
678 */
679DECLINLINE(void) pcnetRmdLoad(PCNetState *pData, RMD *rmd, RTGCPHYS addr)
680{
681 PPDMDEVINS pDevIns = PCNETSTATE_2_DEVINS(pData);
682 uint8_t ownbyte;
683
684 if (!BCR_SWSTYLE(pData))
685 {
686 uint16_t rda[4];
687 PDMDevHlpPhysRead(pDevIns, addr+3, &ownbyte, 1);
688 PDMDevHlpPhysRead(pDevIns, addr, (void*)&rda[0], sizeof(rda));
689 ((uint32_t *)rmd)[0] = (uint32_t)rda[0] | ((rda[1] & 0x00ff) << 16);
690 ((uint32_t *)rmd)[1] = (uint32_t)rda[2] | ((rda[1] & 0xff00) << 16);
691 ((uint32_t *)rmd)[2] = (uint32_t)rda[3];
692 ((uint32_t *)rmd)[3] = 0;
693 }
694 else if (BCR_SWSTYLE(pData) != 3)
695 {
696 PDMDevHlpPhysRead(pDevIns, addr+7, &ownbyte, 1);
697 PDMDevHlpPhysRead(pDevIns, addr, (void*)rmd, 16);
698 }
699 else
700 {
701 uint32_t rda[4];
702 PDMDevHlpPhysRead(pDevIns, addr+7, &ownbyte, 1);
703 PDMDevHlpPhysRead(pDevIns, addr, (void*)&rda[0], sizeof(rda));
704 ((uint32_t *)rmd)[0] = rda[2];
705 ((uint32_t *)rmd)[1] = rda[1];
706 ((uint32_t *)rmd)[2] = rda[0];
707 ((uint32_t *)rmd)[3] = rda[3];
708 }
709 /* Double check the own bit; guest drivers might be buggy and lock prefixes in the recompiler are ignored by other threads. */
710#ifdef DEBUG
711 if (rmd->rmd1.own == 1 && !(ownbyte & 0x80))
712 Log(("pcnetTmdLoad: own bit flipped while reading!!\n"));
713#endif
714 if (!(ownbyte & 0x80))
715 rmd->rmd1.own = 0;
716}
717
718/**
719 * Store receive message descriptor and hand it over to the host (the VM guest).
720 * Make sure that all data are transmitted before we clear the own flag.
721 */
722DECLINLINE(void) pcnetRmdStorePassHost(PCNetState *pData, RMD *rmd, RTGCPHYS addr)
723{
724 PPDMDEVINS pDevIns = PCNETSTATE_2_DEVINS(pData);
725 if (!BCR_SWSTYLE(pData))
726 {
727 uint16_t rda[4];
728 rda[0] = ((uint32_t *)rmd)[0] & 0xffff;
729 rda[1] = ((((uint32_t *)rmd)[0]>>16) & 0xff) | ((((uint32_t *)rmd)[1]>>16) & 0xff00);
730 rda[2] = ((uint32_t *)rmd)[1] & 0xffff;
731 rda[3] = ((uint32_t *)rmd)[2] & 0xffff;
732 rda[1] |= 0x8000;
733 PDMDevHlpPhysWrite(pDevIns, addr, (void*)&rda[0], sizeof(rda));
734 rda[1] &= ~0x8000;
735 PDMDevHlpPhysWrite(pDevIns, addr+3, (uint8_t*)rda + 3, 1);
736 }
737 else if (BCR_SWSTYLE(pData) != 3)
738 {
739 ((uint32_t*)rmd)[1] |= 0x80000000;
740 PDMDevHlpPhysWrite(pDevIns, addr, (void*)rmd, 16);
741 ((uint32_t*)rmd)[1] &= ~0x80000000;
742 PDMDevHlpPhysWrite(pDevIns, addr+7, (uint8_t*)rmd + 7, 1);
743 }
744 else
745 {
746 uint32_t rda[4];
747 rda[0] = ((uint32_t *)rmd)[2];
748 rda[1] = ((uint32_t *)rmd)[1];
749 rda[2] = ((uint32_t *)rmd)[0];
750 rda[3] = ((uint32_t *)rmd)[3];
751 rda[1] |= 0x80000000;
752 PDMDevHlpPhysWrite(pDevIns, addr, (void*)&rda[0], sizeof(rda));
753 rda[1] &= ~0x80000000;
754 PDMDevHlpPhysWrite(pDevIns, addr+7, (uint8_t*)rda + 7, 1);
755 }
756}
757
758/** Checks if it's a bad (as in invalid) RMD.*/
759#define IS_RMD_BAD(rmd) ((rmd).rmd1.ones != 15 || (rmd).rmd2.zeros != 0)
760
761/** The network card is the owner of the RDTE/TDTE, actually it is this driver */
762#define CARD_IS_OWNER(desc) (((desc) & 0x8000))
763
764/** The host is the owner of the RDTE/TDTE -- actually the VM guest. */
765#define HOST_IS_OWNER(desc) (!((desc) & 0x8000))
766
767#ifndef ETHER_IS_MULTICAST /* Net/Open BSD macro it seems */
768#define ETHER_IS_MULTICAST(a) ((*(uint8_t *)(a)) & 1)
769#endif
770
771#define ETHER_ADDR_LEN ETH_ALEN
772#define ETH_ALEN 6
773#pragma pack(1)
774struct ether_header
775{
776 uint8_t ether_dhost[ETH_ALEN]; /**< destination ethernet address */
777 uint8_t ether_shost[ETH_ALEN]; /**< source ethernet address */
778 uint16_t ether_type; /**< packet type ID field */
779};
780#pragma pack()
781
782#ifdef LOG_PACKETS
783static void LogPkt(const char *name, const void *const src, int count)
784{
785 int i, j;
786 const uint8_t * const p = (const uint8_t * const)src;
787 LogRel(("%s: ", name));
788 i = 14; // length of MAC header
789 i += 4*(p[i] & 15); // length of IP header
790 i += 4*(p[i+12] >> 4); // length of TCP header
791 for (j=i; j<70 && j<count; j++)
792 LogRel((" %02x", p[j]));
793 LogRel((" ("));
794 for (j=i; j<70 && j<count; j++)
795 LogRel(("%c", p[j] >= 32 && p[j] < 127 ? p[j] : '.'));
796 LogRel((")\n"));
797}
798#endif
799
800#define PRINT_PKTHDR(BUF) do { \
801 struct ether_header *hdr = (struct ether_header *)(BUF); \
802 Log(("packet dhost=%02x:%02x:%02x:%02x:%02x:%02x, " \
803 "shost=%02x:%02x:%02x:%02x:%02x:%02x, " \
804 "type=0x%04x (bcast=%d)\n", \
805 hdr->ether_dhost[0],hdr->ether_dhost[1],hdr->ether_dhost[2], \
806 hdr->ether_dhost[3],hdr->ether_dhost[4],hdr->ether_dhost[5], \
807 hdr->ether_shost[0],hdr->ether_shost[1],hdr->ether_shost[2], \
808 hdr->ether_shost[3],hdr->ether_shost[4],hdr->ether_shost[5], \
809 htons(hdr->ether_type), \
810 !!ETHER_IS_MULTICAST(hdr->ether_dhost))); \
811} while (0)
812
813
814#ifdef IN_RING3
815
816#define MULTICAST_FILTER_LEN 8
817
818DECLINLINE(uint32_t) lnc_mchash(const uint8_t *ether_addr)
819{
820#define LNC_POLYNOMIAL 0xEDB88320UL
821 uint32_t crc = 0xFFFFFFFF;
822 int idx, bit;
823 uint8_t data;
824
825 for (idx = 0; idx < ETHER_ADDR_LEN; idx++)
826 {
827 for (data = *ether_addr++, bit = 0; bit < MULTICAST_FILTER_LEN; bit++)
828 {
829 crc = (crc >> 1) ^ (((crc ^ data) & 1) ? LNC_POLYNOMIAL : 0);
830 data >>= 1;
831 }
832 }
833 return crc;
834#undef LNC_POLYNOMIAL
835}
836
837#define CRC(crc, ch) (crc = (crc >> 8) ^ crctab[(crc ^ (ch)) & 0xff])
838
839/* generated using the AUTODIN II polynomial
840 * x^32 + x^26 + x^23 + x^22 + x^16 +
841 * x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x^1 + 1
842 */
843static const uint32_t crctab[256] =
844{
845 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
846 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
847 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
848 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
849 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
850 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
851 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
852 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
853 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
854 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
855 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
856 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
857 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
858 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
859 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
860 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
861 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
862 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
863 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
864 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
865 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
866 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
867 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
868 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
869 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
870 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
871 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
872 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
873 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
874 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
875 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
876 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
877 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
878 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
879 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
880 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
881 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
882 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
883 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
884 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
885 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
886 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
887 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
888 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
889 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
890 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
891 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
892 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
893 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
894 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
895 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
896 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
897 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
898 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
899 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
900 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
901 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
902 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
903 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
904 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
905 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
906 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
907 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
908 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
909};
910
911DECLINLINE(int) padr_match(PCNetState *pData, const uint8_t *buf, int size)
912{
913 struct ether_header *hdr = (struct ether_header *)buf;
914 int result;
915#if (defined(__X86__) || defined(__AMD64__)) && !defined(PCNET_DEBUG_MATCH)
916 result = !CSR_DRCVPA(pData) && !memcmp(hdr->ether_dhost, pData->aCSR + 12, 6);
917#else
918 uint8_t padr[6];
919 padr[0] = pData->aCSR[12] & 0xff;
920 padr[1] = pData->aCSR[12] >> 8;
921 padr[2] = pData->aCSR[13] & 0xff;
922 padr[3] = pData->aCSR[13] >> 8;
923 padr[4] = pData->aCSR[14] & 0xff;
924 padr[5] = pData->aCSR[14] >> 8;
925 result = !CSR_DRCVPA(pData) && !memcmp(hdr->ether_dhost, padr, 6);
926#endif
927
928#ifdef PCNET_DEBUG_MATCH
929 Log(("#%d packet dhost=%02x:%02x:%02x:%02x:%02x:%02x, "
930 "padr=%02x:%02x:%02x:%02x:%02x:%02x\n",
931 PCNETSTATE_2_DEVINS(pData)->iInstance,
932 hdr->ether_dhost[0],hdr->ether_dhost[1],hdr->ether_dhost[2],
933 hdr->ether_dhost[3],hdr->ether_dhost[4],hdr->ether_dhost[5],
934 padr[0],padr[1],padr[2],padr[3],padr[4],padr[5]));
935 Log(("padr_match result=%d\n", result));
936#endif
937 return result;
938}
939
940DECLINLINE(int) padr_bcast(PCNetState *pData, const uint8_t *buf, int size)
941{
942 static uint8_t aBCAST[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
943 struct ether_header *hdr = (struct ether_header *)buf;
944 int result = !CSR_DRCVBC(pData) && !memcmp(hdr->ether_dhost, aBCAST, 6);
945#ifdef PCNET_DEBUG_MATCH
946 Log(("#%d padr_bcast result=%d\n", PCNETSTATE_2_DEVINS(pData)->iInstance, result));
947#endif
948 return result;
949}
950
951static int ladr_match(PCNetState *pData, const uint8_t *buf, int size)
952{
953 struct ether_header *hdr = (struct ether_header *)buf;
954 if (RT_UNLIKELY(hdr->ether_dhost[0] & 0x01) && ((uint64_t *)&pData->aCSR[8])[0] != 0LL)
955 {
956 int index;
957#if defined(__X86__) || defined(__AMD64__)
958 index = lnc_mchash(hdr->ether_dhost) >> 26;
959 return ((uint8_t*)(pData->aCSR + 8))[index >> 3] & (1 << (index & 7));
960#else
961 uint8_t ladr[8];
962 ladr[0] = pData->aCSR[8] & 0xff;
963 ladr[1] = pData->aCSR[8] >> 8;
964 ladr[2] = pData->aCSR[9] & 0xff;
965 ladr[3] = pData->aCSR[9] >> 8;
966 ladr[4] = pData->aCSR[10] & 0xff;
967 ladr[5] = pData->aCSR[10] >> 8;
968 ladr[6] = pData->aCSR[11] & 0xff;
969 ladr[7] = pData->aCSR[11] >> 8;
970 index = lnc_mchash(hdr->ether_dhost) >> 26;
971 return (ladr[index >> 3] & (1 << (index & 7)));
972#endif
973 }
974 return 0;
975}
976
977#endif /* IN_RING3 */
978
979/**
980 * Get the receive descriptor ring address with a given index.
981 */
982DECLINLINE(RTGCPHYS) pcnetRdraAddr(PCNetState *pData, int idx)
983{
984 return pData->GCRDRA + ((CSR_RCVRL(pData) - idx) << pData->iLog2DescSize);
985}
986
987/**
988 * Get the transmit descriptor ring address with a given index.
989 */
990DECLINLINE(RTGCPHYS) pcnetTdraAddr(PCNetState *pData, int idx)
991{
992 return pData->GCTDRA + ((CSR_XMTRL(pData) - idx) << pData->iLog2DescSize);
993}
994
995__BEGIN_DECLS
996PDMBOTHCBDECL(int) pcnetIOPortRead(PPDMDEVINS pDevIns, void *pvUser,
997 RTIOPORT Port, uint32_t *pu32, unsigned cb);
998PDMBOTHCBDECL(int) pcnetIOPortWrite(PPDMDEVINS pDevIns, void *pvUser,
999 RTIOPORT Port, uint32_t u32, unsigned cb);
1000PDMBOTHCBDECL(int) pcnetIOPortAPromWrite(PPDMDEVINS pDevIns, void *pvUser,
1001 RTIOPORT Port, uint32_t u32, unsigned cb);
1002PDMBOTHCBDECL(int) pcnetIOPortAPromRead(PPDMDEVINS pDevIns, void *pvUser,
1003 RTIOPORT Port, uint32_t *pu32, unsigned cb);
1004PDMBOTHCBDECL(int) pcnetMMIORead(PPDMDEVINS pDevIns, void *pvUser,
1005 RTGCPHYS GCPhysAddr, void *pv, unsigned cb);
1006PDMBOTHCBDECL(int) pcnetMMIOWrite(PPDMDEVINS pDevIns, void *pvUser,
1007 RTGCPHYS GCPhysAddr, void *pv, unsigned cb);
1008#ifndef IN_RING3
1009DECLEXPORT(int) pcnetHandleRingWrite(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame,
1010 RTGCPTR pvFault, RTGCPHYS GCPhysFault, void *pvUser);
1011#endif
1012__END_DECLS
1013
1014#undef htonl
1015#define htonl(x) ASMByteSwapU32(x)
1016#undef htons
1017#define htons(x) ( (((x) & 0xff00) >> 8) | (((x) & 0x00ff) << 8) )
1018
1019static void pcnetPollRxTx(PCNetState *pData);
1020static void pcnetPollTimer(PCNetState *pData);
1021static void pcnetUpdateIrq(PCNetState *pData);
1022static uint32_t pcnetBCRReadU16(PCNetState *pData, uint32_t u32RAP);
1023static int pcnetBCRWriteU16(PCNetState *pData, uint32_t u32RAP, uint32_t val);
1024
1025
1026#ifdef PCNET_NO_POLLING
1027# ifndef IN_RING3
1028
1029/**
1030 * #PF Virtual Handler callback for Guest write access to the ring descriptor page(pData)
1031 *
1032 * @return VBox status code (appropriate for trap handling and GC return).
1033 * @param pVM VM Handle.
1034 * @param uErrorCode CPU Error code.
1035 * @param pRegFrame Trap register frame.
1036 * @param pvFault The fault address (cr2).
1037 * @param GCPhysFault The GC physical address corresponding to pvFault.
1038 * @param pvUser User argument.
1039 */
1040DECLEXPORT(int) pcnetHandleRingWrite(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame,
1041 RTGCPTR pvFault, RTGCPHYS GCPhysFault, void *pvUser)
1042{
1043 PCNetState *pData = (PCNetState *)pvUser;
1044
1045 Log(("#%d pcnetHandleRingWriteGC: write to %08x\n", PCNETSTATE_2_DEVINS(pData)->iInstance, GCPhysFault));
1046
1047 uint32_t cb;
1048 int rc = CTXALLSUFF(pData->pfnEMInterpretInstruction)(pVM, pRegFrame, pvFault, &cb);
1049 if (VBOX_SUCCESS(rc) && cb)
1050 {
1051 if ( (GCPhysFault >= pData->GCTDRA && GCPhysFault + cb < pcnetTdraAddr(pData, 0))
1052#ifdef PCNET_MONITOR_RECEIVE_RING
1053 || (GCPhysFault >= pData->GCRDRA && GCPhysFault + cb < pcnetRdraAddr(pData, 0))
1054#endif
1055 )
1056 {
1057 uint32_t offsetTDRA = (GCPhysFault - pData->GCTDRA);
1058
1059 int rc = PDMCritSectEnter(&pData->CritSect, VERR_SEM_BUSY);
1060 if (VBOX_SUCCESS(rc))
1061 {
1062 STAM_COUNTER_INC(&CTXALLSUFF(pData->StatRingWrite)); ;
1063
1064 /* Check if we can do something now */
1065 pcnetPollRxTx(pData);
1066 pcnetUpdateIrq(pData);
1067
1068 PDMCritSectLeave(&pData->CritSect);
1069 return VINF_SUCCESS;
1070 }
1071 }
1072 else
1073 {
1074 STAM_COUNTER_INC(&CTXALLSUFF(pData->StatRingWriteOutsideRange)); ;
1075 return VINF_SUCCESS; /* outside of the ring range */
1076 }
1077 }
1078 STAM_COUNTER_INC(&CTXALLSUFF(pData->StatRingWriteFailed)); ;
1079 return VINF_IOM_HC_MMIO_WRITE; /* handle in ring3 */
1080}
1081
1082# else /* IN_RING3 */
1083
1084/**
1085 * #PF Handler callback for physical access handler ranges (MMIO among others) in HC.
1086 *
1087 * The handler can not raise any faults, it's mainly for monitoring write access
1088 * to certain pages.
1089 *
1090 * @returns VINF_SUCCESS if the handler have carried out the operation.
1091 * @returns VINF_PGM_HANDLER_DO_DEFAULT if the caller should carry out the access operation.
1092 * @param pVM VM Handle.
1093 * @param GCPhys The physical address the guest is writing to.
1094 * @param pvPhys The HC mapping of that address.
1095 * @param pvBuf What the guest is reading/writing.
1096 * @param cbBuf How much it's reading/writing.
1097 * @param enmAccessType The access type.
1098 * @param pvUser User argument.
1099 */
1100static DECLCALLBACK(int) pcnetHandleRingWrite(PVM pVM, RTGCPHYS GCPhys, void *pvPhys, void *pvBuf,
1101 size_t cbBuf, PGMACCESSTYPE enmAccessType, void *pvUser)
1102{
1103 PPDMDEVINS pDevIns = (PPDMDEVINS)pvUser;
1104 PCNetState *pData = PDMINS2DATA(pDevIns, PCNetState *);
1105
1106 Log(("#%d pcnetHandleRingWrite: write to %08x\n", PCNETSTATE_2_DEVINS(pData)->iInstance, GCPhys));
1107#ifdef VBOX_WITH_STATISTICS
1108 STAM_COUNTER_INC(&CTXSUFF(pData->StatRingWrite));
1109 if (GCPhys >= pData->GCRDRA && GCPhys < pcnetRdraAddr(pData, 0))
1110 STAM_COUNTER_INC(&pData->StatRCVRingWrite);
1111 else if (GCPhys >= pData->GCTDRA && GCPhys < pcnetTdraAddr(pData, 0))
1112 STAM_COUNTER_INC(&pData->StatTXRingWrite);
1113#endif
1114 /* Perform the actual write */
1115 memcpy((char *)pvPhys, pvBuf, cbBuf);
1116
1117 /* Writes done by our code don't require polling of course */
1118 if (PDMCritSectIsOwner(&pData->CritSect) == false)
1119 {
1120 if ( (GCPhys >= pData->GCTDRA && GCPhys + cbBuf < pcnetTdraAddr(pData, 0))
1121#ifdef PCNET_MONITOR_RECEIVE_RING
1122 || (GCPhys >= pData->GCRDRA && GCPhys + cbBuf < pcnetRdraAddr(pData, 0))
1123#endif
1124 )
1125 {
1126 int rc = PDMCritSectEnter(&pData->CritSect, VERR_SEM_BUSY);
1127 AssertReleaseRC(rc);
1128 /* Check if we can do something now */
1129 pcnetPollRxTx(pData);
1130 pcnetUpdateIrq(pData);
1131 PDMCritSectLeave(&pData->CritSect);
1132 }
1133 }
1134 return VINF_SUCCESS;
1135}
1136# endif /* !IN_RING3 */
1137#endif /* PCNET_NO_POLLING */
1138
1139static void pcnetSoftReset(PCNetState *pData)
1140{
1141 Log(("#%d pcnetSoftReset:\n", PCNETSTATE_2_DEVINS(pData)->iInstance));
1142
1143 pData->u32Lnkst = 0x40;
1144 pData->GCRDRA = 0;
1145 pData->GCTDRA = 0;
1146 pData->u32RAP = 0;
1147
1148 pData->aBCR[BCR_BSBC] &= ~0x0080;
1149
1150 pData->aCSR[0] = 0x0004;
1151 pData->aCSR[3] = 0x0000;
1152 pData->aCSR[4] = 0x0115;
1153 pData->aCSR[5] = 0x0000;
1154 pData->aCSR[6] = 0x0000;
1155 pData->aCSR[8] = 0;
1156 pData->aCSR[9] = 0;
1157 pData->aCSR[10] = 0;
1158 pData->aCSR[11] = 0;
1159 pData->aCSR[12] = le16_to_cpu(((uint16_t *)&pData->aPROM[0])[0]);
1160 pData->aCSR[13] = le16_to_cpu(((uint16_t *)&pData->aPROM[0])[1]);
1161 pData->aCSR[14] = le16_to_cpu(((uint16_t *)&pData->aPROM[0])[2]);
1162 pData->aCSR[15] &= 0x21c4;
1163 CSR_RCVRC(pData) = 1;
1164 CSR_XMTRC(pData) = 1;
1165 CSR_RCVRL(pData) = 1;
1166 CSR_XMTRL(pData) = 1;
1167 pData->aCSR[80] = 0x1410;
1168 pData->aCSR[88] = pData->fAm79C973 ? CSR_VERSION_LOW_79C973 : CSR_VERSION_LOW_79C970A;
1169 pData->aCSR[89] = CSR_VERSION_HIGH;
1170 pData->aCSR[94] = 0x0000;
1171 pData->aCSR[100] = 0x0200;
1172 pData->aCSR[103] = 0x0105;
1173 pData->aCSR[103] = 0x0105;
1174 CSR_MISSC(pData) = 0;
1175 pData->aCSR[114] = 0x0000;
1176 pData->aCSR[122] = 0x0000;
1177 pData->aCSR[124] = 0x0000;
1178}
1179
1180/**
1181 * Check if we have to send an interrupt to the guest. An interrupt can occur on
1182 * - csr0 (written quite often)
1183 * - csr4 (only written by pcnetSoftReset(), pcnetStop() or by the guest driver)
1184 * - csr5 (only written by pcnetSoftReset(), pcnetStop or by the driver guest)
1185 */
1186static void pcnetUpdateIrq(PCNetState *pData)
1187{
1188 register int iISR = 0;
1189 register uint16_t csr0 = pData->aCSR[0];
1190
1191 csr0 &= ~0x0080; /* clear INTR */
1192
1193 STAM_PROFILE_ADV_START(&pData->StatInterrupt, a);
1194
1195 /* Linux guests set csr4=0x0915
1196 * W2k guests set csr3=0x4940 (disable BABL, MERR, IDON, DXSUFLO */
1197
1198#if 1
1199 if ( ( (csr0 & ~pData->aCSR[3]) & 0x5f00)
1200 || (((pData->aCSR[4]>>1) & ~pData->aCSR[4]) & 0x0115)
1201 || (((pData->aCSR[5]>>1) & pData->aCSR[5]) & 0x0048))
1202#else
1203 if ( ( !(pData->aCSR[3] & 0x4000) && !!(csr0 & 0x4000)) /* BABL */
1204 ||( !(pData->aCSR[3] & 0x1000) && !!(csr0 & 0x1000)) /* MISS */
1205 ||( !(pData->aCSR[3] & 0x0100) && !!(csr0 & 0x0100)) /* IDON */
1206 ||( !(pData->aCSR[3] & 0x0200) && !!(csr0 & 0x0200)) /* TINT */
1207 ||( !(pData->aCSR[3] & 0x0400) && !!(csr0 & 0x0400)) /* RINT */
1208 ||( !(pData->aCSR[3] & 0x0800) && !!(csr0 & 0x0800)) /* MERR */
1209 ||( !(pData->aCSR[4] & 0x0001) && !!(pData->aCSR[4] & 0x0002)) /* JAB */
1210 ||( !(pData->aCSR[4] & 0x0004) && !!(pData->aCSR[4] & 0x0008)) /* TXSTRT */
1211 ||( !(pData->aCSR[4] & 0x0010) && !!(pData->aCSR[4] & 0x0020)) /* RCVO */
1212 ||( !(pData->aCSR[4] & 0x0100) && !!(pData->aCSR[4] & 0x0200)) /* MFCO */
1213 ||(!!(pData->aCSR[5] & 0x0040) && !!(pData->aCSR[5] & 0x0080)) /* EXDINT */
1214 ||(!!(pData->aCSR[5] & 0x0008) && !!(pData->aCSR[5] & 0x0010)) /* MPINT */)
1215#endif
1216 {
1217 iISR = !!(csr0 & 0x0040); /* CSR_INEA */
1218 csr0 |= 0x0080; /* set INTR */
1219 }
1220
1221#ifdef VBOX
1222 if (pData->aCSR[4] & 0x0080) /* UINTCMD */
1223 {
1224 pData->aCSR[4] &= ~0x0080; /* clear UINTCMD */
1225 pData->aCSR[4] |= 0x0040; /* set UINT */
1226 Log(("#%d user int\n", PCNETSTATE_2_DEVINS(pData)->iInstance));
1227 }
1228 if (pData->aCSR[4] & csr0 & 0x0040 /* CSR_INEA */)
1229 {
1230 csr0 |= 0x0080; /* set INTR */
1231 iISR = 1;
1232 }
1233#else /* !VBOX */
1234 if (!!(pData->aCSR[4] & 0x0080) && CSR_INEA(pData)) /* UINTCMD */
1235 {
1236 pData->aCSR[4] &= ~0x0080;
1237 pData->aCSR[4] |= 0x0040; /* set UINT */
1238 csr0 |= 0x0080; /* set INTR */
1239 iISR = 1;
1240 Log(("#%d user int\n", PCNETSTATE_2_DEVINS(pData)->iInstance));
1241 }
1242#endif /* !VBOX */
1243
1244#if 1
1245 if (((pData->aCSR[5]>>1) & pData->aCSR[5]) & 0x0500)
1246#else
1247 if ( (!!(pData->aCSR[5] & 0x0400) && !!(pData->aCSR[5] & 0x0800)) /* SINT */
1248 ||(!!(pData->aCSR[5] & 0x0100) && !!(pData->aCSR[5] & 0x0200)) /* SLPINT */)
1249#endif
1250 {
1251 iISR = 1;
1252 csr0 |= 0x0080; /* INTR */
1253 }
1254
1255 pData->aCSR[0] = csr0;
1256
1257 Log2(("#%d set irq iISR=%d\n", PCNETSTATE_2_DEVINS(pData)->iInstance, iISR));
1258
1259 /* normal path is to _not_ change the IRQ status */
1260 if (RT_UNLIKELY(iISR != pData->iISR))
1261 {
1262 Log(("#%d INTA=%d\n", PCNETSTATE_2_DEVINS(pData)->iInstance, iISR));
1263 PDMDevHlpPCISetIrqNoWait(PCNETSTATE_2_DEVINS(pData), 0, iISR);
1264 pData->iISR = iISR;
1265 }
1266 STAM_PROFILE_ADV_STOP(&pData->StatInterrupt, a);
1267}
1268
1269#ifdef IN_RING3
1270#ifdef PCNET_NO_POLLING
1271static void pcnetUpdateRingHandlers(PCNetState *pData)
1272{
1273 PPDMDEVINS pDevIns = PCNETSTATE_2_DEVINS(pData);
1274 int rc;
1275
1276 Log(("pcnetUpdateRingHandlers TD %VGp size %x -> %VGp size %x\n", pData->TDRAPhysOld, pData->cbTDRAOld, pData->GCTDRA, pcnetTdraAddr(pData, 0)));
1277 Log(("pcnetUpdateRingHandlers RX %VGp size %x -> %VGp size %x\n", pData->RDRAPhysOld, pData->cbRDRAOld, pData->GCRDRA, pcnetRdraAddr(pData, 0)));
1278
1279 /** @todo unregister order not correct! */
1280
1281#ifdef PCNET_MONITOR_RECEIVE_RING
1282 if (pData->GCRDRA != pData->RDRAPhysOld || CSR_RCVRL(pData) != pData->cbRDRAOld)
1283 {
1284 if (pData->RDRAPhysOld != 0)
1285 PGMHandlerPhysicalDeregister(PDMDevHlpGetVM(pDevIns),
1286 pData->RDRAPhysOld & ~PAGE_OFFSET_MASK);
1287
1288 rc = PGMR3HandlerPhysicalRegister(PDMDevHlpGetVM(pDevIns),
1289 PGMPHYSHANDLERTYPE_PHYSICAL_WRITE,
1290 pData->GCRDRA & ~PAGE_OFFSET_MASK,
1291 RT_ALIGN(pcnetRdraAddr(pData, 0), PAGE_SIZE) - 1,
1292 pcnetHandleRingWrite, pDevIns,
1293 g_DevicePCNet.szR0Mod, "pcnetHandleRingWrite",
1294 pData->pDevInsHC->pvInstanceDataHC,
1295 g_DevicePCNet.szGCMod, "pcnetHandleRingWrite",
1296 pData->pDevInsHC->pvInstanceDataGC,
1297 "PCNet receive ring write access handler");
1298 AssertRC(rc);
1299
1300 pData->RDRAPhysOld = pData->GCRDRA;
1301 pData->cbRDRAOld = pcnetRdraAddr(pData, 0);
1302 }
1303#endif /* PCNET_MONITOR_RECEIVE_RING */
1304
1305#ifdef PCNET_MONITOR_RECEIVE_RING
1306 /* 3 possibilities:
1307 * 1) TDRA on different physical page as RDRA
1308 * 2) TDRA completely on same physical page as RDRA
1309 * 3) TDRA & RDRA overlap partly with different physical pages
1310 */
1311 RTGCPHYS RDRAPageStart = pData->GCRDRA & ~PAGE_OFFSET_MASK;
1312 RTGCPHYS RDRAPageEnd = (pcnetRdraAddr(pData, 0) - 1) & ~PAGE_OFFSET_MASK;
1313 RTGCPHYS TDRAPageStart = pData->GCTDRA & ~PAGE_OFFSET_MASK;
1314 RTGCPHYS TDRAPageEnd = (pcnetTdraAddr(pData, 0) - 1) & ~PAGE_OFFSET_MASK;
1315
1316 if ( RDRAPageStart > TDRAPageEnd
1317 || TDRAPageStart > RDRAPageEnd)
1318 {
1319#endif /* PCNET_MONITOR_RECEIVE_RING */
1320 /* 1) */
1321 if (pData->GCTDRA != pData->TDRAPhysOld || CSR_XMTRL(pData) != pData->cbTDRAOld)
1322 {
1323 if (pData->TDRAPhysOld != 0)
1324 PGMHandlerPhysicalDeregister(PDMDevHlpGetVM(pDevIns),
1325 pData->TDRAPhysOld & ~PAGE_OFFSET_MASK);
1326
1327 rc = PGMR3HandlerPhysicalRegister(PDMDevHlpGetVM(pDevIns),
1328 PGMPHYSHANDLERTYPE_PHYSICAL_WRITE,
1329 pData->GCTDRA & ~PAGE_OFFSET_MASK,
1330 RT_ALIGN(pcnetTdraAddr(pData, 0), PAGE_SIZE) - 1,
1331 pcnetHandleRingWrite, pDevIns,
1332 g_DevicePCNet.szR0Mod, "pcnetHandleRingWrite",
1333 pData->pDevInsHC->pvInstanceDataHC,
1334 g_DevicePCNet.szGCMod, "pcnetHandleRingWrite",
1335 pData->pDevInsHC->pvInstanceDataGC,
1336 "PCNet transmit ring write access handler");
1337 AssertRC(rc);
1338
1339 pData->TDRAPhysOld = pData->GCTDRA;
1340 pData->cbTDRAOld = pcnetTdraAddr(pData, 0);
1341 }
1342#ifdef PCNET_MONITOR_RECEIVE_RING
1343 }
1344 else
1345 if ( RDRAPageStart != TDRAPageStart
1346 && ( TDRAPageStart == RDRAPageEnd
1347 || TDRAPageEnd == RDRAPageStart
1348 )
1349 )
1350 {
1351 /* 3) */
1352 AssertFailed();
1353 }
1354 /* else 2) */
1355#endif
1356}
1357#endif /* PCNET_NO_POLLING */
1358
1359static void pcnetInit(PCNetState *pData)
1360{
1361 PPDMDEVINS pDevIns = PCNETSTATE_2_DEVINS(pData);
1362 Log(("#%d pcnetInit: init_addr=0x%08x\n", PCNETSTATE_2_DEVINS(pData)->iInstance,
1363 PHYSADDR(pData, CSR_IADR(pData))));
1364
1365 /** @todo Documentation says that RCVRL and XMTRL are stored as two's complement!
1366 * Software is allowed to write these registers directly. */
1367#define PCNET_INIT() do { \
1368 PDMDevHlpPhysRead(pDevIns, PHYSADDR(pData, CSR_IADR(pData)), \
1369 (uint8_t *)&initblk, sizeof(initblk)); \
1370 pData->aCSR[15] = le16_to_cpu(initblk.mode); \
1371 CSR_RCVRL(pData) = (initblk.rlen < 9) ? (1 << initblk.rlen) : 512; \
1372 CSR_XMTRL(pData) = (initblk.tlen < 9) ? (1 << initblk.tlen) : 512; \
1373 pData->aCSR[ 6] = (initblk.tlen << 12) | (initblk.rlen << 8); \
1374 pData->aCSR[ 8] = le16_to_cpu(initblk.ladrf1); \
1375 pData->aCSR[ 9] = le16_to_cpu(initblk.ladrf2); \
1376 pData->aCSR[10] = le16_to_cpu(initblk.ladrf3); \
1377 pData->aCSR[11] = le16_to_cpu(initblk.ladrf4); \
1378 pData->aCSR[12] = le16_to_cpu(initblk.padr1); \
1379 pData->aCSR[13] = le16_to_cpu(initblk.padr2); \
1380 pData->aCSR[14] = le16_to_cpu(initblk.padr3); \
1381 pData->GCRDRA = PHYSADDR(pData, initblk.rdra); \
1382 pData->GCTDRA = PHYSADDR(pData, initblk.tdra); \
1383} while (0)
1384
1385 if (BCR_SSIZE32(pData))
1386 {
1387 struct INITBLK32 initblk;
1388 pData->GCUpperPhys = 0;
1389 PCNET_INIT();
1390 Log(("#%d initblk.rlen=0x%02x, initblk.tlen=0x%02x\n",
1391 PCNETSTATE_2_DEVINS(pData)->iInstance, initblk.rlen, initblk.tlen));
1392 }
1393 else
1394 {
1395 struct INITBLK16 initblk;
1396 pData->GCUpperPhys = (0xff00 & (uint32_t)pData->aCSR[2]) << 16;
1397 PCNET_INIT();
1398 Log(("#%d initblk.rlen=0x%02x, initblk.tlen=0x%02x\n",
1399 PCNETSTATE_2_DEVINS(pData)->iInstance, initblk.rlen, initblk.tlen));
1400 }
1401
1402#undef PCNET_INIT
1403
1404 if (pData->pDrv)
1405 pData->pDrv->pfnSetPromiscuousMode(pData->pDrv, CSR_PROM(pData));
1406
1407 CSR_RCVRC(pData) = CSR_RCVRL(pData);
1408 CSR_XMTRC(pData) = CSR_XMTRL(pData);
1409
1410#ifdef PCNET_NO_POLLING
1411 pcnetUpdateRingHandlers(pData);
1412#endif
1413
1414 /* Reset cached RX and TX states */
1415 CSR_CRST(pData) = CSR_CRBC(pData) = CSR_NRST(pData) = CSR_NRBC(pData) = 0;
1416 CSR_CXST(pData) = CSR_CXBC(pData) = CSR_NXST(pData) = CSR_NXBC(pData) = 0;
1417
1418 LogRel(("PCNet#%d: Init: ss32=%d GCRDRA=0x%08x[%d] GCTDRA=0x%08x[%d]\n",
1419 PCNETSTATE_2_DEVINS(pData)->iInstance, BCR_SSIZE32(pData),
1420 pData->GCRDRA, CSR_RCVRL(pData), pData->GCTDRA, CSR_XMTRL(pData)));
1421
1422 pData->aCSR[0] |= 0x0101; /* Initialization done */
1423 pData->aCSR[0] &= ~0x0004; /* clear STOP bit */
1424}
1425#endif /* IN_RING3 */
1426
1427/**
1428 * Start RX/TX operation.
1429 */
1430static void pcnetStart(PCNetState *pData)
1431{
1432 Log(("%#d pcnetStart:\n", PCNETSTATE_2_DEVINS(pData)->iInstance));
1433 if (!CSR_DTX(pData))
1434 pData->aCSR[0] |= 0x0010; /* set TXON */
1435 if (!CSR_DRX(pData))
1436 pData->aCSR[0] |= 0x0020; /* set RXON */
1437 pData->aCSR[0] &= ~0x0004; /* clear STOP bit */
1438 pData->aCSR[0] |= 0x0002; /* STRT */
1439}
1440
1441/**
1442 * Stop RX/TX operation.
1443 */
1444static void pcnetStop(PCNetState *pData)
1445{
1446 Log(("#%d pcnetStop:\n", PCNETSTATE_2_DEVINS(pData)->iInstance));
1447 pData->aCSR[0] &= ~0x7feb;
1448 pData->aCSR[0] |= 0x0014;
1449 pData->aCSR[4] &= ~0x02c2;
1450 pData->aCSR[5] &= ~0x0011;
1451 pcnetPollTimer(pData);
1452}
1453
1454#ifdef IN_RING3
1455static DECLCALLBACK(bool) pcnetCanRxQueueConsumer(PPDMDEVINS pDevIns, PPDMQUEUEITEMCORE pItem)
1456{
1457 PCNetState *pData = PDMINS2DATA(pDevIns, PCNetState *);
1458 pData->pDrv->pfnNotifyCanReceive(pData->pDrv);
1459 return true;
1460}
1461#endif
1462
1463/**
1464 * Poll Receive Descriptor Table Entry and cache the results in the appropriate registers.
1465 * Note: Once a descriptor belongs to the network card (this driver), it cannot be changed
1466 * by the host (the guest driver) anymore. Well, it could but the results are undefined by
1467 * definition.
1468 * @param fSkipCurrent if true, don't scan the current RDTE.
1469 */
1470static void pcnetRdtePoll(PCNetState *pData, bool fSkipCurrent=false)
1471{
1472 STAM_PROFILE_ADV_START(&pData->CTXSUFF(StatRdtePoll), a);
1473 /* assume lack of a next receive descriptor */
1474 CSR_NRST(pData) = 0;
1475
1476 if (RT_LIKELY(pData->GCRDRA))
1477 {
1478 /*
1479 * The current receive message descriptor.
1480 */
1481 RMD rmd;
1482 int i = CSR_RCVRC(pData);
1483 RTGCPHYS addr;
1484
1485 if (i < 1)
1486 i = CSR_RCVRL(pData);
1487
1488 if (!fSkipCurrent)
1489 {
1490 addr = pcnetRdraAddr(pData, i);
1491 pcnetRmdLoad(pData, &rmd, PHYSADDR(pData, addr));
1492 CSR_CRDA(pData) = CSR_CRBA(pData) = 0;
1493 CSR_CRBC(pData) = CSR_CRST(pData) = 0;
1494 if (!rmd.rmd1.own)
1495 {
1496 STAM_PROFILE_ADV_STOP(&pData->CTXSUFF(StatRdtePoll), a);
1497 return;
1498 }
1499 if (RT_LIKELY(!IS_RMD_BAD(rmd)))
1500 {
1501 CSR_CRDA(pData) = addr; /* Receive Descriptor Address */
1502 CSR_CRBA(pData) = rmd.rmd0.rbadr; /* Receive Buffer Address */
1503 CSR_CRBC(pData) = rmd.rmd1.bcnt; /* Receive Byte Count */
1504 CSR_CRST(pData) = ((uint32_t *)&rmd)[1] >> 16; /* Receive Status */
1505#ifdef IN_RING3
1506 pData->pDrv->pfnNotifyCanReceive(pData->pDrv);
1507#else
1508 PPDMQUEUEITEMCORE pItem = PDMQueueAlloc(CTXSUFF(pData->pCanRxQueue));
1509 if (pItem)
1510 PDMQueueInsert(CTXSUFF(pData->pCanRxQueue), pItem);
1511#endif
1512 }
1513 else
1514 {
1515 STAM_PROFILE_ADV_STOP(&pData->CTXSUFF(StatRdtePoll), a);
1516 /* This is not problematic since we don't own the descriptor */
1517 LogRel(("PCNet#%d: BAD RMD ENTRIES AT 0x%08x (i=%d)\n",
1518 PCNETSTATE_2_DEVINS(pData)->iInstance, addr, i));
1519 return;
1520 }
1521 }
1522
1523 /*
1524 * The next descriptor.
1525 */
1526 if (--i < 1)
1527 i = CSR_RCVRL(pData);
1528 addr = pcnetRdraAddr(pData, i);
1529 pcnetRmdLoad(pData, &rmd, PHYSADDR(pData, addr));
1530 CSR_NRDA(pData) = CSR_NRBA(pData) = 0;
1531 CSR_NRBC(pData) = 0;
1532 if (!rmd.rmd1.own)
1533 {
1534 STAM_PROFILE_ADV_STOP(&pData->CTXSUFF(StatRdtePoll), a);
1535 return;
1536 }
1537 if (RT_LIKELY(!IS_RMD_BAD(rmd)))
1538 {
1539 CSR_NRDA(pData) = addr; /* Receive Descriptor Address */
1540 CSR_NRBA(pData) = rmd.rmd0.rbadr; /* Receive Buffer Address */
1541 CSR_NRBC(pData) = rmd.rmd1.bcnt; /* Receive Byte Count */
1542 CSR_NRST(pData) = ((uint32_t *)&rmd)[1] >> 16; /* Receive Status */
1543 }
1544 else
1545 {
1546 STAM_PROFILE_ADV_STOP(&pData->CTXSUFF(StatRdtePoll), a);
1547 /* This is not problematic since we don't own the descriptor */
1548 LogRel(("PCNet#%d: BAD RMD ENTRIES + AT 0x%08x (i=%d)\n",
1549 PCNETSTATE_2_DEVINS(pData)->iInstance, addr, i));
1550 return;
1551 }
1552
1553 /**
1554 * @todo NNRD
1555 */
1556 }
1557 else
1558 {
1559 CSR_CRDA(pData) = CSR_CRBA(pData) = CSR_NRDA(pData) = CSR_NRBA(pData) = 0;
1560 CSR_CRBC(pData) = CSR_NRBC(pData) = CSR_CRST(pData) = 0;
1561 }
1562 STAM_PROFILE_ADV_STOP(&pData->CTXSUFF(StatRdtePoll), a);
1563}
1564
1565/**
1566 * Poll Transmit Descriptor Table Entry
1567 * @return true if transmit descriptors available
1568 */
1569static int pcnetTdtePoll(PCNetState *pData, TMD *tmd)
1570{
1571 STAM_PROFILE_ADV_START(&pData->CTXSUFF(StatTdtePoll), a);
1572 if (RT_LIKELY(pData->GCTDRA))
1573 {
1574 RTGCPHYS cxda = pcnetTdraAddr(pData, CSR_XMTRC(pData));
1575
1576 pcnetTmdLoad(pData, tmd, PHYSADDR(pData, cxda));
1577
1578 if (!tmd->tmd1.own)
1579 {
1580 STAM_PROFILE_ADV_STOP(&pData->CTXSUFF(StatTdtePoll), a);
1581 return 0;
1582 }
1583
1584 if (RT_UNLIKELY(tmd->tmd1.ones != 15))
1585 {
1586 STAM_PROFILE_ADV_STOP(&pData->CTXSUFF(StatTdtePoll), a);
1587 LogRel(("PCNet#%d: BAD TMD XDA=0x%08x\n",
1588 PCNETSTATE_2_DEVINS(pData)->iInstance, PHYSADDR(pData, cxda)));
1589 return 0;
1590 }
1591
1592 /* previous xmit descriptor */
1593 CSR_PXDA(pData) = CSR_CXDA(pData);
1594 CSR_PXBC(pData) = CSR_CXBC(pData);
1595 CSR_PXST(pData) = CSR_CXST(pData);
1596
1597 /* set current trasmit decriptor. */
1598 CSR_CXDA(pData) = cxda;
1599 CSR_CXBC(pData) = tmd->tmd1.bcnt;
1600 CSR_CXST(pData) = ((uint32_t *)tmd)[1] >> 16;
1601 STAM_PROFILE_ADV_STOP(&pData->CTXSUFF(StatTdtePoll), a);
1602 return CARD_IS_OWNER(CSR_CXST(pData));
1603 }
1604 else
1605 {
1606 /** @todo consistency with previous receive descriptor */
1607 CSR_CXDA(pData) = 0;
1608 CSR_CXBC(pData) = CSR_CXST(pData) = 0;
1609 STAM_PROFILE_ADV_STOP(&pData->CTXSUFF(StatTdtePoll), a);
1610 return 0;
1611 }
1612}
1613
1614
1615#ifdef IN_RING3
1616
1617/**
1618 * Check if there is at least one free receive buffer available.
1619 */
1620static int pcnetCanReceiveNoSync(PCNetState *pData)
1621{
1622 if (RT_UNLIKELY(CSR_DRX(pData) || CSR_STOP(pData) || CSR_SPND(pData)))
1623 return 0;
1624
1625 if (HOST_IS_OWNER(CSR_CRST(pData)) && pData->GCRDRA)
1626 pcnetRdtePoll(pData);
1627
1628 if (HOST_IS_OWNER(CSR_CRST(pData)))
1629 {
1630 /** @todo Notify the guest _now_. Will potentially increase the interrupt load */
1631 pData->aCSR[0] |= 0x1000; /* Set MISS flag */
1632 return 0;
1633 }
1634
1635 /* byte count stored in two's complement 12 bits wide */
1636 Log(("#%d pcnetCanReceiveNoSync %d bytes\n", PCNETSTATE_2_DEVINS(pData)->iInstance,
1637 4096 - CSR_CRBC(pData)));
1638 return 4096 - CSR_CRBC(pData);
1639}
1640
1641/**
1642 * Write data into guest receive buffers.
1643 */
1644static void pcnetReceiveNoSync(PCNetState *pData, const uint8_t *buf, int size)
1645{
1646 PPDMDEVINS pDevIns = PCNETSTATE_2_DEVINS(pData);
1647 int is_padr = 0, is_bcast = 0, is_ladr = 0;
1648
1649 if (RT_UNLIKELY(CSR_DRX(pData) || CSR_STOP(pData) || CSR_SPND(pData) || !size))
1650 return;
1651
1652 Log(("#%d pcnetReceiveNoSync: size=%d\n", PCNETSTATE_2_DEVINS(pData)->iInstance, size));
1653
1654 LOG_PACKET("rraw", buf, size);
1655
1656 /*
1657 * Perform address matching.
1658 */
1659 if ( CSR_PROM(pData)
1660 || (is_padr = padr_match(pData, buf, size))
1661 || (is_bcast = padr_bcast(pData, buf, size))
1662 || (is_ladr = ladr_match(pData, buf, size)))
1663 {
1664 if (HOST_IS_OWNER(CSR_CRST(pData)))
1665 pcnetRdtePoll(pData);
1666 if (RT_UNLIKELY(HOST_IS_OWNER(CSR_CRST(pData))))
1667 {
1668 /* Not owned by controller. This should not be possible as
1669 * we already called pcnetCanReceive(). */
1670 LogRel(("PCNet#%d: no buffer: RCVRC=%d\n",
1671 PCNETSTATE_2_DEVINS(pData)->iInstance, CSR_RCVRC(pData)));
1672 /* Dump the status of all RX descriptors */
1673 const unsigned cb = 1 << pData->iLog2DescSize;
1674 RTGCPHYS GCPhys = pData->GCRDRA;
1675 unsigned i = CSR_RCVRL(pData);
1676 while (i-- > 0)
1677 {
1678 RMD rmd;
1679 pcnetRmdLoad(pData, &rmd, PHYSADDR(pData, GCPhys));
1680 LogRel((" %08x\n", rmd.rmd1));
1681 GCPhys += cb;
1682 }
1683 pData->aCSR[0] |= 0x1000; /* Set MISS flag */
1684 CSR_MISSC(pData)++;
1685 }
1686 else
1687 {
1688 uint8_t *src = &pData->abRecvBuf[8];
1689 RTGCPHYS crda = CSR_CRDA(pData);
1690 RMD rmd;
1691 int pktcount = 0;
1692
1693 memcpy(src, buf, size);
1694 if (!CSR_ASTRP_RCV(pData))
1695 {
1696 uint32_t fcs = ~0;
1697 uint8_t *p = src;
1698
1699 while (size < 60)
1700 src[size++] = 0;
1701 while (p != &src[size])
1702 CRC(fcs, *p++);
1703 ((uint32_t *)&src[size])[0] = htonl(fcs);
1704 /* FCS at end of packet */
1705 }
1706 size += 4;
1707
1708#ifdef PCNET_DEBUG_MATCH
1709 PRINT_PKTHDR(buf);
1710#endif
1711
1712 pcnetRmdLoad(pData, &rmd, PHYSADDR(pData, crda));
1713 /*if (!CSR_LAPPEN(pData))*/
1714 rmd.rmd1.stp = 1;
1715
1716 int count = RT_MIN(4096 - (int)rmd.rmd1.bcnt, size);
1717 RTGCPHYS rbadr = PHYSADDR(pData, rmd.rmd0.rbadr);
1718 PDMDevHlpPhysWrite(pDevIns, rbadr, src, count);
1719 src += count;
1720 size -= count;
1721 rmd.rmd2.mcnt = count;
1722 pktcount++;
1723 if (size > 0)
1724 {
1725 if (HOST_IS_OWNER(CSR_NRST(pData)))
1726 {
1727 /* From the manual: ``Regardless of ownership of the second receive
1728 * descriptor, the Am79C972 controller will continue to perform receive
1729 * data DMA transfers to the first buffer. If the frame length exceeds
1730 * the length of the first buffer, and the Am79C972 controller does not
1731 * own the second buffer, ownership of the current descriptor will be
1732 * passed back to the system by writing a 0 to the OWN bit of RMD1.
1733 * Status will be written indicating buffer (BUFF = 1) and possibly
1734 * overflow (OFLO = 1) errors.
1735 * If the frame length exceeds the length of the first (current) buffer,
1736 * and the Am79C972 controller does own the second (next) buffer,
1737 * ownership will be passed back to the system by writing a 0 to the OWN
1738 * bit of RMD1 when the first buffer is full. The OWN bit is the only bit
1739 * modified in the descriptor. Receive data transfers to the second buffer
1740 * may occur before the Am79C972 controller proceeds to look ahead to the
1741 * ownership of the third buffer. Such action will depend upon the state
1742 * of the FIFO when the OWN bit has been updated in the first descriptor.
1743 * In any case, lookahead will be performed to the third buffer and the
1744 * information gathered will be stored in the chip, regardless of the state
1745 * of the ownership bit.'' */
1746 pcnetRdtePoll(pData, true);
1747 }
1748 if (CARD_IS_OWNER(CSR_NRST(pData)))
1749 {
1750 /* write back, clear the own bit */
1751 pcnetRmdStorePassHost(pData, &rmd, PHYSADDR(pData, crda));
1752 crda = CSR_NRDA(pData);
1753 pcnetRmdLoad(pData, &rmd, PHYSADDR(pData, crda));
1754 count = RT_MIN(4096 - (int)rmd.rmd1.bcnt, size);
1755 rbadr = PHYSADDR(pData, rmd.rmd0.rbadr);
1756 PDMDevHlpPhysWrite(pDevIns, rbadr, src, count);
1757 src += count;
1758 size -= count;
1759 rmd.rmd2.mcnt = count;
1760 pktcount++;
1761 }
1762 }
1763
1764 if (RT_LIKELY(size == 0))
1765 {
1766 rmd.rmd1.enp = 1;
1767 rmd.rmd1.pam = !CSR_PROM(pData) && is_padr;
1768 rmd.rmd1.lafm = !CSR_PROM(pData) && is_ladr;
1769 rmd.rmd1.bam = !CSR_PROM(pData) && is_bcast;
1770 }
1771 else
1772 {
1773 LogRel(("PCNet#%d: Overflow by %ubytes\n",
1774 PCNETSTATE_2_DEVINS(pData)->iInstance, size));
1775 rmd.rmd1.oflo = 1;
1776 rmd.rmd1.buff = 1;
1777 rmd.rmd1.err = 1;
1778 }
1779 /* write back, clear the own bit */
1780 pcnetRmdStorePassHost(pData, &rmd, PHYSADDR(pData, crda));
1781
1782 pData->aCSR[0] |= 0x0400;
1783
1784 Log(("#%d RCVRC=%d CRDA=0x%08x BLKS=%d\n", PCNETSTATE_2_DEVINS(pData)->iInstance,
1785 CSR_RCVRC(pData), PHYSADDR(pData, CSR_CRDA(pData)), pktcount));
1786#ifdef PCNET_DEBUG_RMD
1787 PRINT_RMD(&rmd);
1788#endif
1789
1790 while (pktcount--)
1791 {
1792 if (CSR_RCVRC(pData) < 2)
1793 CSR_RCVRC(pData) = CSR_RCVRL(pData);
1794 else
1795 CSR_RCVRC(pData)--;
1796 }
1797 /* guest driver is owner: force repoll of current and next RDTEs */
1798 CSR_CRST(pData) = 0;
1799 }
1800 }
1801
1802 /* see description of TXDPOLL:
1803 * ``transmit polling will take place following receive activities'' */
1804 pcnetPollRxTx(pData);
1805 pcnetUpdateIrq(pData);
1806}
1807
1808
1809/**
1810 * Checks if the link is up.
1811 * @returns true if the link is up.
1812 * @returns false if the link is down.
1813 */
1814DECLINLINE(bool) pcnetIsLinkUp(PCNetState *pData)
1815{
1816 return pData->pDrv && !pData->fLinkTempDown && pData->fLinkUp;
1817}
1818
1819
1820/**
1821 * Transmit queue consumer
1822 * This is just a very simple way of delaying sending to R3.
1823 *
1824 * @returns Success indicator.
1825 * If false the item will not be removed and the flushing will stop.
1826 * @param pDevIns The device instance.
1827 * @param pItem The item to consume. Upon return this item will be freed.
1828 */
1829static DECLCALLBACK(bool) pcnetXmitQueueConsumer(PPDMDEVINS pDevIns, PPDMQUEUEITEMCORE pItem)
1830{
1831 PCNetState *pData = PDMINS2DATA(pDevIns, PCNetState *);
1832 NOREF(pItem);
1833
1834 /* Clear counter .*/
1835 ASMAtomicAndU32(&pData->cPendingSends, 0);
1836 int rc = RTSemEventSignal(pData->hSendEventSem);
1837 AssertRC(rc);
1838 return true;
1839}
1840
1841
1842/**
1843 * Scraps the top frame.
1844 * This is done as a precaution against mess left over by on
1845 */
1846DECLINLINE(void) pcnetXmitScrapFrame(PCNetState *pData)
1847{
1848 pData->SendFrame.pvBuf = NULL;
1849 pData->SendFrame.cb = -1;
1850}
1851
1852
1853/**
1854 * If we are in RING3 don't copy the frame from GC here but only store the address. We
1855 * don't need to buffer the frames because a direct address translation was possible.
1856 */
1857DECLINLINE(void) pcnetXmitZeroCopyFrame(PCNetState *pData, RTR3PTR pv, const unsigned cbFrame)
1858{
1859 pData->SendFrame.pvBuf = pv;
1860 pData->SendFrame.cb = cbFrame;
1861}
1862
1863
1864/**
1865 * Reads the first part of a frame
1866 */
1867DECLINLINE(void) pcnetXmitRead1st(PCNetState *pData, RTGCPHYS GCPhysFrame, const unsigned cbFrame)
1868{
1869 Assert(cbFrame < sizeof(pData->abSendBuf));
1870
1871 PDMDevHlpPhysRead(pData->CTXSUFF(pDevIns), GCPhysFrame,
1872 &pData->abSendBuf[0],
1873 cbFrame);
1874 pData->SendFrame.pvBuf = pData->abSendBuf;
1875 pData->SendFrame.cb = cbFrame;
1876}
1877
1878
1879/**
1880 * Reads more into the current frame.
1881 */
1882DECLINLINE(void) pcnetXmitReadMore(PCNetState *pData, RTGCPHYS GCPhysFrame, const unsigned cbFrame)
1883{
1884 Assert(pData->SendFrame.cb + cbFrame < sizeof(pData->abSendBuf));
1885 PDMDevHlpPhysRead(pData->CTXSUFF(pDevIns), GCPhysFrame,
1886 &pData->abSendBuf[pData->SendFrame.cb],
1887 cbFrame);
1888 pData->SendFrame.cb += cbFrame;
1889}
1890
1891
1892/**
1893 * Completes the current frame.
1894 * If we've reached the maxium number of frames, they will be flushed.
1895 */
1896DECLINLINE(int) pcnetXmitCompleteFrame(PCNetState *pData)
1897{
1898 /* Don't hold the critical section while transmitting data. */
1899 /** @note also avoids deadlocks with NAT as it can call us right back. */
1900 PDMCritSectLeave(&pData->CritSect);
1901
1902 STAM_PROFILE_ADV_START(&pData->StatTransmitSend, a);
1903 pData->pDrv->pfnSend(pData->pDrv, pData->SendFrame.pvBuf, pData->SendFrame.cb);
1904 STAM_PROFILE_ADV_STOP(&pData->StatTransmitSend, a);
1905
1906 return PDMCritSectEnter(&pData->CritSect, VERR_PERMISSION_DENIED);
1907}
1908
1909
1910/**
1911 * Fails a TMD with a link down error.
1912 */
1913static void pcnetXmitFailTMDLinkDown(PCNetState *pData, TMD *pTmd)
1914{
1915 /* make carrier error - hope this is correct. */
1916 pData->cLinkDownReported++;
1917 pTmd->tmd2.lcar = pTmd->tmd1.err = 1;
1918 pData->aCSR[0] |= BIT(15) | BIT(13); /* ERR | CERR */
1919 pData->Led.Asserted.s.fError = pData->Led.Actual.s.fError = 1;
1920 Log(("#%d pcnetTransmit: Signaling send error. swstyle=%#x\n",
1921 PCNETSTATE_2_DEVINS(pData)->iInstance, pData->aBCR[BCR_SWS]));
1922}
1923
1924/**
1925 * Fails a TMD with a generic error.
1926 */
1927static void pcnetXmitFailTMDGeneric(PCNetState *pData, TMD *pTmd)
1928{
1929 /* make carrier error - hope this is correct. */
1930 pTmd->tmd2.lcar = pTmd->tmd1.err = 1;
1931 pData->aCSR[0] |= BIT(15) | BIT(13); /* ERR | CERR */
1932 pData->Led.Asserted.s.fError = pData->Led.Actual.s.fError = 1;
1933 Log(("#%d pcnetTransmit: Signaling send error. swstyle=%#x\n",
1934 PCNETSTATE_2_DEVINS(pData)->iInstance, pData->aBCR[BCR_SWS]));
1935}
1936
1937
1938/**
1939 * Transmit a loopback frame.
1940 */
1941DECLINLINE(void) pcnetXmitLoopbackFrame(PCNetState *pData)
1942{
1943 pData->Led.Asserted.s.fReading = pData->Led.Actual.s.fReading = 1;
1944 if (HOST_IS_OWNER(CSR_CRST(pData)))
1945 pcnetRdtePoll(pData);
1946
1947 Assert(pData->SendFrame.pvBuf);
1948 pcnetReceiveNoSync(pData, (const uint8_t *)pData->SendFrame.pvBuf, pData->SendFrame.cb);
1949 pcnetXmitScrapFrame(pData);
1950 pData->Led.Actual.s.fReading = 0;
1951}
1952
1953/**
1954 * Flushes queued frames.
1955 */
1956DECLINLINE(void) pcnetXmitFlushFrames(PCNetState *pData)
1957{
1958 pcnetXmitQueueConsumer(CTXSUFF(pData->pDevIns), NULL);
1959}
1960
1961#endif /* IN_RING3 */
1962
1963
1964
1965/**
1966 * Try to transmit frames
1967 */
1968static void pcnetTransmit(PCNetState *pData)
1969{
1970 if (RT_UNLIKELY(!CSR_TXON(pData)))
1971 {
1972 pData->aCSR[0] &= ~0x0008; /* Clear TDMD */
1973 return;
1974 }
1975
1976 /*
1977 * Check the current transmit descriptors.
1978 */
1979 TMD tmd;
1980 if (!pcnetTdtePoll(pData, &tmd))
1981 return;
1982
1983 /* Update TDMD, TXSTRT and TINT. */
1984 pData->aCSR[0] &= ~0x0008; /* clear TDMD */
1985
1986 /*
1987 * If we're in Ring-3 we should flush the queue now, in GC/R0 we'll queue a flush job.
1988 */
1989#ifdef IN_RING3
1990 pcnetXmitFlushFrames(pData);
1991#else
1992
1993#if 1
1994 PPDMQUEUEITEMCORE pItem = PDMQueueAlloc(CTXSUFF(pData->pXmitQueue));
1995 if (RT_UNLIKELY(pItem))
1996 PDMQueueInsert(CTXSUFF(pData->pXmitQueue), pItem);
1997#else
1998 if (ASMAtomicIncU32(&pData->cPendingSends) < 16)
1999 {
2000 PPDMQUEUEITEMCORE pItem = PDMQueueAlloc(CTXSUFF(pData->pXmitQueue));
2001 if (RT_UNLIKELY(pItem))
2002 PDMQueueInsert(CTXSUFF(pData->pXmitQueue), pItem);
2003 }
2004 else
2005 PDMQueueFlush(CTXSUFF(pData->pXmitQueue));
2006#endif
2007#endif
2008}
2009
2010#ifdef IN_RING3
2011
2012/**
2013 * Try to transmit frames
2014 */
2015static int pcnetAsyncTransmit(PCNetState *pData)
2016{
2017 unsigned cFlushIrq = 0;
2018
2019 Assert(PDMCritSectIsOwner(&pData->CritSect));
2020
2021 if (RT_UNLIKELY(!CSR_TXON(pData)))
2022 {
2023 pData->aCSR[0] &= ~0x0008; /* Clear TDMD */
2024 return VINF_SUCCESS;
2025 }
2026
2027 /*
2028 * Iterate the transmit descriptors.
2029 */
2030 STAM_PROFILE_ADV_START(&pData->StatTransmit, a);
2031 do
2032 {
2033#ifdef VBOX_WITH_STATISTICS
2034 unsigned cBuffers = 1;
2035#endif
2036 TMD tmd;
2037 if (!pcnetTdtePoll(pData, &tmd))
2038 break;
2039
2040 /* Don't continue sending packets when the link is down. */
2041 if (RT_UNLIKELY( !pcnetIsLinkUp(pData)
2042 && pData->cLinkDownReported > PCNET_MAX_LINKDOWN_REPORTED)
2043 )
2044 break;
2045
2046#ifdef PCNET_DEBUG_TMD
2047 Log2(("#%d TMDLOAD 0x%08x\n", PCNETSTATE_2_DEVINS(pData)->iInstance, PHYSADDR(pData, CSR_CXDA(pData))));
2048 PRINT_TMD(&tmd);
2049#endif
2050 pcnetXmitScrapFrame(pData);
2051
2052 /*
2053 * The typical case - a complete packet.
2054 * This can be performed with zero copy in Ring-3.
2055 */
2056 if (tmd.tmd1.stp && tmd.tmd1.enp)
2057 {
2058 const unsigned cb = 4096 - tmd.tmd1.bcnt;
2059 Log(("#%d pcnetTransmit: stp&enp: cb=%d xmtrc=%#x\n", PCNETSTATE_2_DEVINS(pData)->iInstance, cb, CSR_XMTRC(pData)));
2060
2061 if (RT_LIKELY(pcnetIsLinkUp(pData) || CSR_LOOP(pData)))
2062 {
2063 RTR3PTR pv;
2064
2065 /* From the manual: ``A zero length buffer is acceptable as
2066 * long as it is not the last buffer in a chain (STP = 0 and
2067 * ENP = 1).'' That means that the first buffer might have a
2068 * zero length if it is not the last one in the chain. */
2069 if (RT_LIKELY(cb <= 1536))
2070 {
2071 int rc = PDMDevHlpPhys2HCVirt(pData->pDevInsHC,
2072 PHYSADDR(pData, tmd.tmd0.tbadr), cb, &pv);
2073 if (RT_SUCCESS(rc))
2074 pcnetXmitZeroCopyFrame(pData, pv, cb);
2075 else
2076 {
2077 pcnetXmitRead1st(pData, PHYSADDR(pData, tmd.tmd0.tbadr), cb);
2078 }
2079 if (CSR_LOOP(pData))
2080 pcnetXmitLoopbackFrame(pData);
2081 else
2082 {
2083 int rc = pcnetXmitCompleteFrame(pData);
2084 if (VBOX_FAILURE(rc))
2085 return rc; /* can happen during termination */
2086 }
2087 }
2088 else if (cb == 4096)
2089 {
2090 /* The Windows NT4 pcnet driver sometimes marks the first
2091 * unused descriptor as owned by us. Ignore that (by
2092 * passing it back). Do not update the ring counter in this
2093 * case (otherwise that driver becomes even more confused,
2094 * which causes transmit to stall for about 10 seconds).
2095 * This is just a workaround, not a final solution. */
2096 /* r=frank: IMHO this is the correct implementation. The
2097 * manual says: ``If the OWN bit is set and the buffer
2098 * length is 0, the OWN bit will be cleared. In the C-LANCE
2099 * the buffer length of 0 is interpreted as a 4096-byte
2100 * buffer.'' */
2101 LogRel(("PCNET: pcnetAsyncTransmit: illegal 4kb frame -> ignoring\n"));
2102 pcnetTmdStorePassHost(pData, &tmd, PHYSADDR(pData, CSR_CXDA(pData)));
2103 break;
2104 }
2105 else
2106 {
2107 /* Signal error, as this violates the Ethernet specs. */
2108 /** @todo check if the correct error is generated. */
2109 LogRel(("PCNET: pcnetAsyncTransmit: illegal 4kb frame -> signalling error\n"));
2110
2111 pcnetXmitFailTMDGeneric(pData, &tmd);
2112 }
2113 }
2114 else
2115 pcnetXmitFailTMDLinkDown(pData, &tmd);
2116
2117 /* Write back the TMD and pass it to the host (clear own bit). */
2118 pcnetTmdStorePassHost(pData, &tmd, PHYSADDR(pData, CSR_CXDA(pData)));
2119
2120 /* advance the ring counter register */
2121 if (CSR_XMTRC(pData) < 2)
2122 CSR_XMTRC(pData) = CSR_XMTRL(pData);
2123 else
2124 CSR_XMTRC(pData)--;
2125 }
2126 else if (tmd.tmd1.stp)
2127 {
2128 /*
2129 * Read TMDs until end-of-packet or tdte poll fails (underflow).
2130 */
2131 const unsigned cbMaxFrame = 1536;
2132 bool fDropFrame = false;
2133 unsigned cb = 4096 - tmd.tmd1.bcnt;
2134 pcnetXmitRead1st(pData, PHYSADDR(pData, tmd.tmd0.tbadr), cb);
2135 for (;;)
2136 {
2137 /*
2138 * Advance the ring counter register and check the next tmd.
2139 */
2140#ifdef LOG_ENABLED
2141 const uint32_t iStart = CSR_XMTRC(pData);
2142#endif
2143 const uint32_t GCPhysPrevTmd = PHYSADDR(pData, CSR_CXDA(pData));
2144 if (CSR_XMTRC(pData) < 2)
2145 CSR_XMTRC(pData) = CSR_XMTRL(pData);
2146 else
2147 CSR_XMTRC(pData)--;
2148
2149 TMD dummy;
2150 if (!pcnetTdtePoll(pData, &dummy))
2151 {
2152 /*
2153 * Underflow!
2154 */
2155 tmd.tmd2.buff = tmd.tmd2.uflo = tmd.tmd1.err = 1;
2156 pData->aCSR[0] |= 0x0200; /* set TINT */
2157 if (!CSR_DXSUFLO(pData)) /* stop on xmit underflow */
2158 pData->aCSR[0] &= ~0x0010; /* clear TXON */
2159 pcnetTmdStorePassHost(pData, &tmd, GCPhysPrevTmd);
2160 AssertMsgFailed(("pcnetTransmit: Underflow!!!\n"));
2161 break;
2162 }
2163
2164 /* release & save the previous tmd, pass it to the host */
2165 pcnetTmdStorePassHost(pData, &tmd, GCPhysPrevTmd);
2166
2167 /*
2168 * The next tdm.
2169 */
2170#ifdef VBOX_WITH_STATISTICS
2171 cBuffers++;
2172#endif
2173 pcnetTmdLoad(pData, &tmd, PHYSADDR(pData, CSR_CXDA(pData)));
2174 cb = 4096 - tmd.tmd1.bcnt;
2175 if ( pData->SendFrame.cb + cb < cbMaxFrame
2176 && !fDropFrame)
2177 pcnetXmitReadMore(pData, PHYSADDR(pData, tmd.tmd0.tbadr), cb);
2178 else
2179 {
2180 AssertMsg(fDropFrame, ("pcnetTransmit: Frame is too big!!! %d bytes\n",
2181 pData->SendFrame.cb + cb));
2182 fDropFrame = true;
2183 }
2184 if (tmd.tmd1.enp)
2185 {
2186 Log(("#%d pcnetTransmit: stp: cb=%d xmtrc=%#x-%#x\n", PCNETSTATE_2_DEVINS(pData)->iInstance,
2187 pData->SendFrame.cb, iStart, CSR_XMTRC(pData)));
2188 if (pcnetIsLinkUp(pData) && !fDropFrame)
2189 {
2190 int rc = pcnetXmitCompleteFrame(pData);
2191 if (VBOX_FAILURE(rc))
2192 return rc; /* can happen during termination */
2193 }
2194 else if (CSR_LOOP(pData) && !fDropFrame)
2195 pcnetXmitLoopbackFrame(pData);
2196 else
2197 {
2198 if (!fDropFrame)
2199 pcnetXmitFailTMDLinkDown(pData, &tmd);
2200 pcnetXmitScrapFrame(pData);
2201 }
2202
2203 /* Write back the TMD, pass it to the host */
2204 pcnetTmdStorePassHost(pData, &tmd, PHYSADDR(pData, CSR_CXDA(pData)));
2205
2206 /* advance the ring counter register */
2207 if (CSR_XMTRC(pData) < 2)
2208 CSR_XMTRC(pData) = CSR_XMTRL(pData);
2209 else
2210 CSR_XMTRC(pData)--;
2211 break;
2212 }
2213 }
2214 }
2215 else
2216 {
2217 /*
2218 * We underflowed in a previous transfer, or the driver is giving us shit.
2219 * Simply stop the transmitting for now.
2220 */
2221 /** @todo according to the specs we're supposed to clear the own bit and move on to the next one. */
2222 Log(("#%d pcnetTransmit: guest is giving us shit!\n", PCNETSTATE_2_DEVINS(pData)->iInstance));
2223 break;
2224 }
2225 /* Update TDMD, TXSTRT and TINT. */
2226 pData->aCSR[0] &= ~0x0008; /* clear TDMD */
2227
2228 pData->aCSR[4] |= 0x0004; /* set TXSTRT */
2229 if ( !CSR_TOKINTD(pData) /* Transmit OK Interrupt Disable, no infl. on errors. */
2230 || (CSR_LTINTEN(pData) && tmd.tmd1.ltint)
2231 || tmd.tmd1.err)
2232 {
2233 cFlushIrq++;
2234 pData->aCSR[0] |= 0x0200; /* set TINT */
2235 }
2236
2237 /** @todo should we continue after an error (tmd.tmd1.err) or not? */
2238
2239 STAM_COUNTER_INC(&pData->aStatXmitChainCounts[RT_MIN(cBuffers,
2240 ELEMENTS(pData->aStatXmitChainCounts)) - 1]);
2241 } while (CSR_TXON(pData)); /* transfer on */
2242
2243 if (cFlushIrq)
2244 {
2245 STAM_COUNTER_INC(&pData->aStatXmitFlush[RT_MIN(cFlushIrq, ELEMENTS(pData->aStatXmitFlush)) - 1]);
2246 pcnetUpdateIrq(pData);
2247 }
2248
2249 STAM_PROFILE_ADV_STOP(&pData->StatTransmit, a);
2250
2251 return VINF_SUCCESS;
2252}
2253
2254/**
2255 * Async I/O thread for delayed sending of packets.
2256 */
2257static DECLCALLBACK(int) pcnetAsyncSend(RTTHREAD ThreadSelf, void *pvUser)
2258{
2259 PCNetState *pData = (PCNetState *)pvUser;
2260 RTSEMEVENT hEvent = pData->hSendEventSem;
2261 int rc = VINF_SUCCESS;
2262
2263 while(rc == VINF_SUCCESS)
2264 {
2265 rc = RTSemEventWait(hEvent, RT_INDEFINITE_WAIT);
2266 if (VBOX_FAILURE(rc))
2267 break;
2268
2269 rc = PDMCritSectEnter(&pData->CritSect, VERR_PERMISSION_DENIED);
2270 AssertReleaseRC(rc);
2271
2272 rc = pcnetAsyncTransmit(pData);
2273 PDMCritSectLeave(&pData->CritSect);
2274 }
2275 return VINF_SUCCESS;
2276}
2277
2278#endif /* IN_RING3 */
2279
2280/**
2281 * Poll for changes in RX and TX descriptor rings.
2282 */
2283static void pcnetPollRxTx(PCNetState *pData)
2284{
2285 if (CSR_RXON(pData))
2286 if (HOST_IS_OWNER(CSR_CRST(pData))) /* Only poll RDTEs if none available */
2287 pcnetRdtePoll(pData);
2288
2289 if (CSR_TDMD(pData) || CSR_TXON(pData) && !CSR_DPOLL(pData))
2290 pcnetTransmit(pData);
2291}
2292
2293/**
2294 * Update the poller timer
2295 * @thread EMT,
2296 */
2297static void pcnetPollTimer(PCNetState *pData)
2298{
2299 STAM_PROFILE_ADV_START(&pData->StatPollTimer, a);
2300
2301#ifdef LOG_ENABLED
2302 TMD dummy;
2303 Log2(("#%d pcnetPollTimer time=%08x TDMD=%d TXON=%d POLL=%d TDTE=%d TDRA=%x\n",
2304 PCNETSTATE_2_DEVINS(pData)->iInstance, RTTimeMilliTS(), CSR_TDMD(pData), CSR_TXON(pData),
2305 !CSR_DPOLL(pData), pcnetTdtePoll(pData, &dummy), pData->GCTDRA));
2306 Log2(("#%d pcnetPollTimer: CSR_CXDA=%x CSR_XMTRL=%d CSR_XMTRC=%d\n",
2307 PCNETSTATE_2_DEVINS(pData)->iInstance, CSR_CXDA(pData), CSR_XMTRL(pData), CSR_XMTRC(pData)));
2308#endif
2309#ifdef PCNET_DEBUG_TMD
2310 if (CSR_CXDA(pData))
2311 {
2312 TMD tmd;
2313 pcnetTmdLoad(pData, &tmd, PHYSADDR(pData, CSR_CXDA(pData)));
2314 Log2(("#%d pcnetPollTimer: TMDLOAD 0x%08x\n", PCNETSTATE_2_DEVINS(pData)->iInstance, PHYSADDR(pData, CSR_CXDA(pData))));
2315 PRINT_TMD(&tmd);
2316 }
2317#endif
2318 if (CSR_TDMD(pData))
2319 pcnetTransmit(pData);
2320
2321 pcnetUpdateIrq(pData);
2322
2323 if (RT_LIKELY(!CSR_STOP(pData) && !CSR_SPND(pData) && !CSR_DPOLL(pData)))
2324 {
2325 /* We ensure that we poll at least every 2ms (500Hz) but not more often than
2326 * 5000 times per second. This way we completely prevent the overhead from
2327 * heavy reprogramming the timer which turned out to be very CPU-intensive.
2328 * The drawback is that csr46 and csr47 are not updated properly anymore
2329 * but so far I have not seen any guest depending on these values. The 2ms
2330 * interval is the default polling interval of the PCNet card (65536/33MHz). */
2331#ifdef PCNET_NO_POLLING
2332 pcnetPollRxTx(pData);
2333#else
2334 uint64_t u64Now = TMTimerGet(pData->CTXSUFF(pTimerPoll));
2335 if (RT_UNLIKELY(u64Now - pData->u64LastPoll > 200000))
2336 {
2337 pData->u64LastPoll = u64Now;
2338 pcnetPollRxTx(pData);
2339 }
2340 if (!TMTimerIsActive(pData->CTXSUFF(pTimerPoll)))
2341 /* Poll timer interval is fixed to 500Hz. Don't stop it. */
2342 TMTimerSet(pData->CTXSUFF(pTimerPoll),
2343 TMTimerGet(pData->CTXSUFF(pTimerPoll)) + 2000000);
2344#endif
2345 }
2346 STAM_PROFILE_ADV_STOP(&pData->StatPollTimer, a);
2347}
2348
2349
2350static int pcnetCSRWriteU16(PCNetState *pData, uint32_t u32RAP, uint32_t new_value)
2351{
2352 uint16_t val = new_value;
2353 int rc = VINF_SUCCESS;
2354#ifdef PCNET_DEBUG_CSR
2355 Log(("#%d pcnetCSRWriteU16: rap=%d val=0x%04x\n", PCNETSTATE_2_DEVINS(pData)->iInstance, u32RAP, val));
2356#endif
2357 switch (u32RAP)
2358 {
2359 case 0:
2360 {
2361 uint16_t csr0 = pData->aCSR[0];
2362 /* Clear any interrupt flags.
2363 * Don't clear an interrupt flag which was not seen by the guest yet. */
2364 csr0 &= ~(val & 0x7f00 & pData->u16CSR0LastSeenByGuest);
2365 csr0 = (csr0 & ~0x0040) | (val & 0x0048);
2366 val = (val & 0x007f) | (csr0 & 0x7f00);
2367
2368 /* Iff STOP, STRT and INIT are set, clear STRT and INIT */
2369 if ((val & 7) == 7)
2370 val &= ~3;
2371
2372#ifndef IN_RING3
2373 if (!(csr0 & 0x0001/*init*/) && (val & 1))
2374 {
2375 Log(("#%d pcnetCSRWriteU16: pcnetInit requested => HC\n", PCNETSTATE_2_DEVINS(pData)->iInstance));
2376 return VINF_IOM_HC_IOPORT_WRITE;
2377 }
2378#endif
2379 LOG_REGISTER(("PCNet#%d: WRITE CSR%d, %04x => %04x (%04x)\n",
2380 PCNETSTATE_2_DEVINS(pData)->iInstance,
2381 u32RAP, new_value, csr0, pData->aCSR[0]));
2382 pData->aCSR[0] = csr0;
2383
2384 if (!CSR_STOP(pData) && (val & 4))
2385 pcnetStop(pData);
2386
2387#ifdef IN_RING3
2388 if (!CSR_INIT(pData) && (val & 1))
2389 pcnetInit(pData);
2390#endif
2391
2392 if (!CSR_STRT(pData) && (val & 2))
2393 pcnetStart(pData);
2394
2395 if (CSR_TDMD(pData))
2396 pcnetTransmit(pData);
2397
2398 return rc;
2399 }
2400 case 1: /* IADRL */
2401 case 2: /* IADRH */
2402 case 8: /* LADRF 0..15 */
2403 case 9: /* LADRF 16..31 */
2404 case 10: /* LADRF 32..47 */
2405 case 11: /* LADRF 48..63 */
2406 case 12: /* PADR 0..15 */
2407 case 13: /* PADR 16..31 */
2408 case 14: /* PADR 32..47 */
2409 case 18: /* CRBAL */
2410 case 19: /* CRBAU */
2411 case 20: /* CXBAL */
2412 case 21: /* CXBAU */
2413 case 22: /* NRBAL */
2414 case 23: /* NRBAU */
2415 case 24: /* BADRL */
2416 case 25: /* BADRU */
2417 case 26: /* NRDAL */
2418 case 27: /* NRDAU */
2419 case 28: /* CRDAL */
2420 case 29: /* CRDAU */
2421 case 30: /* BADXL */
2422 case 31: /* BADXU */
2423 case 32: /* NXDAL */
2424 case 33: /* NXDAU */
2425 case 34: /* CXDAL */
2426 case 35: /* CXDAU */
2427 case 36: /* NNRDL */
2428 case 37: /* NNRDU */
2429 case 38: /* NNXDL */
2430 case 39: /* NNXDU */
2431 case 40: /* CRBCL */
2432 case 41: /* CRBCU */
2433 case 42: /* CXBCL */
2434 case 43: /* CXBCU */
2435 case 44: /* NRBCL */
2436 case 45: /* NRBCU */
2437 case 46: /* POLL */
2438 case 47: /* POLLINT */
2439 case 72: /* RCVRC */
2440 case 74: /* XMTRC */
2441 case 76: /* RCVRL */ /** @todo call pcnetUpdateRingHandlers */
2442 /** @todo receive ring length is stored in two's complement! */
2443 case 78: /* XMTRL */ /** @todo call pcnetUpdateRingHandlers */
2444 /** @todo transmit ring length is stored in two's complement! */
2445 case 112: /* MISSC */
2446 if (CSR_STOP(pData) || CSR_SPND(pData))
2447 break;
2448 LOG_REGISTER(("PCNet#%d: WRITE CSR%d, %04x\n",
2449 PCNETSTATE_2_DEVINS(pData)->iInstance, u32RAP, val));
2450 return rc;
2451 case 3: /* Interrupt Mask and Deferral Control */
2452 LOG_REGISTER(("PCNet#%d: WRITE CSR%d, %04x\n",
2453 PCNETSTATE_2_DEVINS(pData)->iInstance, u32RAP, val));
2454 break;
2455 case 4: /* Test and Features Control */
2456 LOG_REGISTER(("PCNet#%d: WRITE CSR%d, %04x\n",
2457 PCNETSTATE_2_DEVINS(pData)->iInstance, u32RAP, val));
2458 pData->aCSR[4] &= ~(val & 0x026a);
2459 val &= ~0x026a;
2460 val |= pData->aCSR[4] & 0x026a;
2461 break;
2462 case 5: /* Extended Control and Interrupt 1 */
2463 LOG_REGISTER(("PCNet#%d: WRITE CSR%d, %04x\n",
2464 PCNETSTATE_2_DEVINS(pData)->iInstance, u32RAP, val));
2465 pData->aCSR[5] &= ~(val & 0x0a90);
2466 val &= ~0x0a90;
2467 val |= pData->aCSR[5] & 0x0a90;
2468 break;
2469 case 15: /* Mode */
2470 if ((pData->aCSR[15] & 0x8000) != (val & 0x8000) && pData->pDrv)
2471 {
2472 Log(("PCNet#%d: promiscuous mode changed to %d\n",
2473 PCNETSTATE_2_DEVINS(pData)->iInstance, !!(val & 0x8000)));
2474#ifndef IN_RING3
2475 return VINF_IOM_HC_IOPORT_WRITE;
2476#else
2477 /* check for promiscuous mode change */
2478 pData->pDrv->pfnSetPromiscuousMode(pData->pDrv, !!(val & 0x8000));
2479#endif
2480 }
2481 break;
2482 case 16: /* IADRL */
2483 return pcnetCSRWriteU16(pData, 1, val);
2484 case 17: /* IADRH */
2485 return pcnetCSRWriteU16(pData, 2, val);
2486 case 58: /* Software Style */
2487 LOG_REGISTER(("PCNet#%d: WRITE SW_STYLE, %04x\n",
2488 PCNETSTATE_2_DEVINS(pData)->iInstance, val));
2489 rc = pcnetBCRWriteU16(pData, BCR_SWS, val);
2490 break;
2491 default:
2492 return rc;
2493 }
2494 pData->aCSR[u32RAP] = val;
2495 return rc;
2496}
2497
2498static uint32_t pcnetCSRReadU16(PCNetState *pData, uint32_t u32RAP)
2499{
2500 uint32_t val;
2501 switch (u32RAP)
2502 {
2503 case 0:
2504 pcnetUpdateIrq(pData);
2505 val = pData->aCSR[0];
2506 val |= (val & 0x7800) ? 0x8000 : 0;
2507 pData->u16CSR0LastSeenByGuest = val;
2508 break;
2509 case 16:
2510 return pcnetCSRReadU16(pData, 1);
2511 case 17:
2512 return pcnetCSRReadU16(pData, 2);
2513 case 58:
2514 return pcnetBCRReadU16(pData, BCR_SWS);
2515 case 88:
2516 val = pData->aCSR[89];
2517 val <<= 16;
2518 val |= pData->aCSR[88];
2519 break;
2520 default:
2521 val = pData->aCSR[u32RAP];
2522 LOG_REGISTER(("PCNet#%d: read CSR%d => %04x\n",
2523 PCNETSTATE_2_DEVINS(pData)->iInstance, u32RAP, val));
2524 }
2525#ifdef PCNET_DEBUG_CSR
2526 Log(("#%d pcnetCSRReadU16: u32RAP=%d val=0x%04x\n", PCNETSTATE_2_DEVINS(pData)->iInstance,
2527 u32RAP, val));
2528#endif
2529 return val;
2530}
2531
2532static int pcnetBCRWriteU16(PCNetState *pData, uint32_t u32RAP, uint32_t val)
2533{
2534 int rc = VINF_SUCCESS;
2535 u32RAP &= 0x7f;
2536#ifdef PCNET_DEBUG_BCR
2537 Log2(("#%d pcnetBCRWriteU16: u32RAP=%d val=0x%04x\n", PCNETSTATE_2_DEVINS(pData)->iInstance,
2538 u32RAP, val));
2539#endif
2540 switch (u32RAP)
2541 {
2542 case BCR_SWS:
2543 if (!(CSR_STOP(pData) || CSR_SPND(pData)))
2544 return rc;
2545 val &= ~0x0300;
2546 switch (val & 0x00ff)
2547 {
2548 default:
2549 Log(("Bad SWSTYLE=0x%02x\n", val & 0xff));
2550 // fall through
2551 case 0:
2552 val |= 0x0200; /* 16 bit */
2553 pData->iLog2DescSize = 3;
2554 pData->GCUpperPhys = (0xff00 & (uint32_t)pData->aCSR[2]) << 16;
2555 break;
2556 case 1:
2557 val |= 0x0100; /* 32 bit */
2558 pData->iLog2DescSize = 4;
2559 pData->GCUpperPhys = 0;
2560 break;
2561 case 2:
2562 case 3:
2563 val |= 0x0300; /* 32 bit */
2564 pData->iLog2DescSize = 4;
2565 pData->GCUpperPhys = 0;
2566 break;
2567 }
2568 LOG_REGISTER(("PCNet#%d: WRITE SW_STYLE, %04x\n",
2569 PCNETSTATE_2_DEVINS(pData)->iInstance, val));
2570 Log(("BCR_SWS=0x%04x\n", val));
2571 pData->aCSR[58] = val;
2572 /* fall through */
2573 case BCR_LNKST:
2574 case BCR_LED1:
2575 case BCR_LED2:
2576 case BCR_LED3:
2577 case BCR_MC:
2578 case BCR_FDC:
2579 case BCR_BSBC:
2580 case BCR_EECAS:
2581 case BCR_PLAT:
2582 case BCR_MIIADDR:
2583 LOG_REGISTER(("PCNet#%d: WRITE BCR%d, %04x\n",
2584 PCNETSTATE_2_DEVINS(pData)->iInstance, u32RAP, val));
2585 pData->aBCR[u32RAP] = val;
2586 break;
2587
2588 case BCR_MIIMDR:
2589 LOG_REGISTER(("PCNet#%d: WRITE MII%d, %04x\n",
2590 PCNETSTATE_2_DEVINS(pData)->iInstance, u32RAP, val));
2591 pData->aMII[pData->aBCR[BCR_MIIADDR] & 0x1f] = val;
2592 break;
2593
2594 default:
2595 break;
2596 }
2597 return rc;
2598}
2599
2600static uint32_t pcnetMIIReadU16(PCNetState *pData, uint32_t miiaddr)
2601{
2602 uint32_t val;
2603 STAM_COUNTER_INC(&pData->StatMIIReads);
2604
2605 switch (miiaddr)
2606 {
2607 case 0:
2608 /* MII basic mode control register. */
2609 val = 0x1000; /* Enable auto negotiation. */
2610 break;
2611
2612 case 1:
2613 /* MII basic mode status register. */
2614 if (pData->fLinkUp && !pData->fLinkTempDown)
2615 val = 0x7800 /* Can do 100mbps FD/HD and 10mbps FD/HD. */
2616 | 0x0020 /* Auto-negotiation complete. */
2617 | 0x0008 /* Able to do auto-negotiation. */
2618 | 0x0004 /* Link status. */
2619 | 0x0001; /* Extended Capability, i.e. registers 4+ valid. */
2620 else
2621 {
2622 val = 0x7800 /* Can do 100mbps FD/HD and 10mbps FD/HD. */
2623 | 0x0008 /* Able to do auto-negotiation. */
2624 | 0x0001; /* Extended Capability, i.e. registers 4+ valid. */
2625 pData->cLinkDownReported++;
2626 }
2627 break;
2628
2629 case 2:
2630 /* PHY identifier 1. */
2631 val = 0; /* No name PHY. */
2632 break;
2633
2634 case 3:
2635 /* PHY identifier 2. */
2636 val = 0; /* No name PHY. */
2637 break;
2638
2639 case 4:
2640 /* Advertisement control register. */
2641 val = 0x05e0 /* Try flow control, 100mbps FD/HD and 10mbps FD/HD. */
2642 | 0x0001; /* CSMA selector. */
2643 break;
2644
2645 case 5:
2646 /* Link partner ability register. */
2647 if (pData->fLinkUp && !pData->fLinkTempDown)
2648 val = 0x8000 /* Next page bit. */
2649 | 0x4000 /* Link partner acked us. */
2650 | 0x05e0 /* Can do flow control, 100mbps FD/HD and 10mbps FD/HD. */
2651 | 0x0001; /* Use CSMA selector. */
2652 else
2653 {
2654 val = 0;
2655 pData->cLinkDownReported++;
2656 }
2657 break;
2658
2659 case 6:
2660 /* Auto negotiation expansion register. */
2661 if (pData->fLinkUp && !pData->fLinkTempDown)
2662 val = 0x0008 /* Link partner supports npage. */
2663 | 0x0004 /* Enable npage words. */
2664 | 0x0001; /* Can do N-way auto-negotiation. */
2665 else
2666 {
2667 val = 0;
2668 pData->cLinkDownReported++;
2669 }
2670 break;
2671
2672 default:
2673 val = 0;
2674 break;
2675 }
2676
2677#ifdef PCNET_DEBUG_MII
2678 Log(("#%d pcnet: mii read %d -> %#x\n", PCNETSTATE_2_DEVINS(pData)->iInstance,
2679 miiaddr, val));
2680#endif
2681 return val;
2682}
2683
2684static uint32_t pcnetBCRReadU16(PCNetState *pData, uint32_t u32RAP)
2685{
2686 uint32_t val;
2687 u32RAP &= 0x7f;
2688 switch (u32RAP)
2689 {
2690 case BCR_LNKST:
2691 case BCR_LED1:
2692 case BCR_LED2:
2693 case BCR_LED3:
2694 val = pData->aBCR[u32RAP] & ~0x8000;
2695 /* Clear LNKSTE if we're not connected or if we've just loaded a VM state. */
2696 if (!pData->pDrv || pData->fLinkTempDown || !pData->fLinkUp)
2697 {
2698 if (u32RAP == 4)
2699 pData->cLinkDownReported++;
2700 val &= ~0x40;
2701 }
2702 val |= (val & 0x017f & pData->u32Lnkst) ? 0x8000 : 0;
2703 break;
2704
2705 case BCR_MIIMDR:
2706 if (pData->fAm79C973 && (pData->aBCR[BCR_MIIADDR] >> 5 & 0x1f) == 0)
2707 {
2708 size_t miiaddr = pData->aBCR[BCR_MIIADDR] & 0x1f;
2709 val = pcnetMIIReadU16(pData, miiaddr);
2710 }
2711 else
2712 val = 0xffff;
2713 break;
2714
2715 default:
2716 val = u32RAP < BCR_MAX_RAP ? pData->aBCR[u32RAP] : 0;
2717 break;
2718 }
2719#ifdef PCNET_DEBUG_BCR
2720 Log2(("#%d pcnetBCRReadU16: u32RAP=%d val=0x%04x\n", PCNETSTATE_2_DEVINS(pData)->iInstance,
2721 u32RAP, val));
2722#endif
2723 return val;
2724}
2725
2726#ifdef IN_RING3 /* move down */
2727static void pcnetHardReset(PCNetState *pData)
2728{
2729 int i;
2730 uint16_t checksum;
2731
2732 /* Initialize the PROM */
2733 Assert(sizeof(pData->MacConfigured) == 6);
2734 memcpy(pData->aPROM, &pData->MacConfigured, sizeof(pData->MacConfigured));
2735 pData->aPROM[12] = pData->aPROM[13] = 0x00;
2736 pData->aPROM[14] = pData->aPROM[15] = 0x57;
2737
2738 for (i = 0, checksum = 0; i < 16; i++)
2739 checksum += pData->aPROM[i];
2740 *(uint16_t *)&pData->aPROM[12] = cpu_to_le16(checksum);
2741
2742 pData->aBCR[BCR_MSRDA] = 0x0005;
2743 pData->aBCR[BCR_MSWRA] = 0x0005;
2744 pData->aBCR[BCR_MC ] = 0x0002;
2745 pData->aBCR[BCR_LNKST] = 0x00c0;
2746 pData->aBCR[BCR_LED1 ] = 0x0084;
2747 pData->aBCR[BCR_LED2 ] = 0x0088;
2748 pData->aBCR[BCR_LED3 ] = 0x0090;
2749 pData->aBCR[BCR_FDC ] = 0x0000;
2750 pData->aBCR[BCR_BSBC ] = 0x9001;
2751 pData->aBCR[BCR_EECAS] = 0x0002;
2752 pData->aCSR[58 ] = /* CSR58 is an alias for BCR20 */
2753 pData->aBCR[BCR_SWS ] = 0x0200;
2754 pData->iLog2DescSize = 3;
2755 pData->aBCR[BCR_PLAT ] = 0xff06;
2756
2757 pcnetSoftReset(pData);
2758}
2759#endif /* IN_RING3 */
2760
2761static void pcnetAPROMWriteU8(PCNetState *pData, uint32_t addr, uint32_t val)
2762{
2763 addr &= 0x0f;
2764 val &= 0xff;
2765 Log(("#%d pcnetAPROMWriteU8: addr=0x%08x val=0x%02x\n", PCNETSTATE_2_DEVINS(pData)->iInstance,
2766 addr, val));
2767 /* Check APROMWE bit to enable write access */
2768 if (pcnetBCRReadU16(pData, 2) & 0x80)
2769 pData->aPROM[addr] = val;
2770}
2771
2772static uint32_t pcnetAPROMReadU8(PCNetState *pData, uint32_t addr)
2773{
2774 uint32_t val = pData->aPROM[addr &= 0x0f];
2775 Log(("#%d pcnetAPROMReadU8: addr=0x%08x val=0x%02x\n", PCNETSTATE_2_DEVINS(pData)->iInstance,
2776 addr, val));
2777 return val;
2778}
2779
2780static int pcnetIoportWriteU16(PCNetState *pData, uint32_t addr, uint32_t val)
2781{
2782 int rc = VINF_SUCCESS;
2783
2784#ifdef PCNET_DEBUG_IO
2785 Log2(("#%d pcnetIoportWriteU16: addr=0x%08x val=0x%04x\n", PCNETSTATE_2_DEVINS(pData)->iInstance,
2786 addr, val));
2787#endif
2788 if (RT_LIKELY(!BCR_DWIO(pData)))
2789 {
2790 switch (addr & 0x0f)
2791 {
2792 case 0x00: /* RDP */
2793 pcnetPollTimer(pData);
2794 rc = pcnetCSRWriteU16(pData, pData->u32RAP, val);
2795 pcnetUpdateIrq(pData);
2796 break;
2797 case 0x02: /* RAP */
2798 pData->u32RAP = val & 0x7f;
2799 break;
2800 case 0x06: /* BDP */
2801 rc = pcnetBCRWriteU16(pData, pData->u32RAP, val);
2802 break;
2803 }
2804 }
2805
2806 return rc;
2807}
2808
2809static uint32_t pcnetIoportReadU16(PCNetState *pData, uint32_t addr, int *pRC)
2810{
2811 uint32_t val = ~0U;
2812
2813 *pRC = VINF_SUCCESS;
2814
2815 if (RT_LIKELY(!BCR_DWIO(pData)))
2816 {
2817 switch (addr & 0x0f)
2818 {
2819 case 0x00: /* RDP */
2820 /** @note if we're not polling, then the guest will tell us when to poll by setting TDMD in CSR0 */
2821 /** Polling is then useless here and possibly expensive. */
2822 if (!CSR_DPOLL(pData))
2823 pcnetPollTimer(pData);
2824
2825 val = pcnetCSRReadU16(pData, pData->u32RAP);
2826 if (pData->u32RAP == 0) // pcnetUpdateIrq() already called by pcnetCSRReadU16()
2827 goto skip_update_irq;
2828 break;
2829 case 0x02: /* RAP */
2830 val = pData->u32RAP;
2831 goto skip_update_irq;
2832 case 0x04: /* RESET */
2833 pcnetSoftReset(pData);
2834 val = 0;
2835 break;
2836 case 0x06: /* BDP */
2837 val = pcnetBCRReadU16(pData, pData->u32RAP);
2838 break;
2839 }
2840 }
2841 pcnetUpdateIrq(pData);
2842
2843skip_update_irq:
2844#ifdef PCNET_DEBUG_IO
2845 Log2(("#%d pcnetIoportReadU16: addr=0x%08x val=0x%04x\n", PCNETSTATE_2_DEVINS(pData)->iInstance,
2846 addr, val & 0xffff));
2847#endif
2848 return val;
2849}
2850
2851static int pcnetIoportWriteU32(PCNetState *pData, uint32_t addr, uint32_t val)
2852{
2853 int rc = VINF_SUCCESS;
2854
2855#ifdef PCNET_DEBUG_IO
2856 Log2(("#%d pcnetIoportWriteU32: addr=0x%08x val=0x%08x\n", PCNETSTATE_2_DEVINS(pData)->iInstance,
2857 addr, val));
2858#endif
2859 if (RT_LIKELY(BCR_DWIO(pData)))
2860 {
2861 switch (addr & 0x0f)
2862 {
2863 case 0x00: /* RDP */
2864 pcnetPollTimer(pData);
2865 rc = pcnetCSRWriteU16(pData, pData->u32RAP, val & 0xffff);
2866 pcnetUpdateIrq(pData);
2867 break;
2868 case 0x04: /* RAP */
2869 pData->u32RAP = val & 0x7f;
2870 break;
2871 case 0x0c: /* BDP */
2872 rc = pcnetBCRWriteU16(pData, pData->u32RAP, val & 0xffff);
2873 break;
2874 }
2875 }
2876 else if (addr == 0)
2877 {
2878 /* switch device to dword I/O mode */
2879 pcnetBCRWriteU16(pData, BCR_BSBC, pcnetBCRReadU16(pData, BCR_BSBC) | 0x0080);
2880#ifdef PCNET_DEBUG_IO
2881 Log2(("device switched into dword i/o mode\n"));
2882#endif
2883 }
2884
2885 return rc;
2886}
2887
2888static uint32_t pcnetIoportReadU32(PCNetState *pData, uint32_t addr, int *pRC)
2889{
2890 uint32_t val = ~0U;
2891
2892 *pRC = VINF_SUCCESS;
2893
2894 if (RT_LIKELY(BCR_DWIO(pData)))
2895 {
2896 switch (addr & 0x0f)
2897 {
2898 case 0x00: /* RDP */
2899 /** @note if we're not polling, then the guest will tell us when to poll by setting TDMD in CSR0 */
2900 /** Polling is then useless here and possibly expensive. */
2901 if (!CSR_DPOLL(pData))
2902 pcnetPollTimer(pData);
2903
2904 val = pcnetCSRReadU16(pData, pData->u32RAP);
2905 if (pData->u32RAP == 0) // pcnetUpdateIrq() already called by pcnetCSRReadU16()
2906 goto skip_update_irq;
2907 break;
2908 case 0x04: /* RAP */
2909 val = pData->u32RAP;
2910 goto skip_update_irq;
2911 case 0x08: /* RESET */
2912 pcnetSoftReset(pData);
2913 val = 0;
2914 break;
2915 case 0x0c: /* BDP */
2916 val = pcnetBCRReadU16(pData, pData->u32RAP);
2917 break;
2918 }
2919 }
2920 pcnetUpdateIrq(pData);
2921
2922skip_update_irq:
2923#ifdef PCNET_DEBUG_IO
2924 Log2(("#%d pcnetIoportReadU32: addr=0x%08x val=0x%08x\n", PCNETSTATE_2_DEVINS(pData)->iInstance,
2925 addr, val));
2926#endif
2927 return val;
2928}
2929
2930static void pcnetMMIOWriteU8(PCNetState *pData, RTGCPHYS addr, uint32_t val)
2931{
2932#ifdef PCNET_DEBUG_IO
2933 Log2(("#%d pcnetMMIOWriteU8: addr=0x%08x val=0x%02x\n", PCNETSTATE_2_DEVINS(pData)->iInstance,
2934 addr, val));
2935#endif
2936 if (!(addr & 0x10))
2937 pcnetAPROMWriteU8(pData, addr, val);
2938}
2939
2940static uint32_t pcnetMMIOReadU8(PCNetState *pData, RTGCPHYS addr)
2941{
2942 uint32_t val = ~0U;
2943 if (!(addr & 0x10))
2944 val = pcnetAPROMReadU8(pData, addr);
2945#ifdef PCNET_DEBUG_IO
2946 Log2(("#%d pcnetMMIOReadU8: addr=0x%08x val=0x%02x\n", PCNETSTATE_2_DEVINS(pData)->iInstance,
2947 addr, val & 0xff));
2948#endif
2949 return val;
2950}
2951
2952static void pcnetMMIOWriteU16(PCNetState *pData, RTGCPHYS addr, uint32_t val)
2953{
2954#ifdef PCNET_DEBUG_IO
2955 Log2(("#%d pcnetMMIOWriteU16: addr=0x%08x val=0x%04x\n", PCNETSTATE_2_DEVINS(pData)->iInstance,
2956 addr, val));
2957#endif
2958 if (addr & 0x10)
2959 pcnetIoportWriteU16(pData, addr & 0x0f, val);
2960 else
2961 {
2962 pcnetAPROMWriteU8(pData, addr, val );
2963 pcnetAPROMWriteU8(pData, addr+1, val >> 8);
2964 }
2965}
2966
2967static uint32_t pcnetMMIOReadU16(PCNetState *pData, RTGCPHYS addr)
2968{
2969 uint32_t val = ~0U;
2970 int rc;
2971
2972 if (addr & 0x10)
2973 val = pcnetIoportReadU16(pData, addr & 0x0f, &rc);
2974 else
2975 {
2976 val = pcnetAPROMReadU8(pData, addr+1);
2977 val <<= 8;
2978 val |= pcnetAPROMReadU8(pData, addr);
2979 }
2980#ifdef PCNET_DEBUG_IO
2981 Log2(("#%d pcnetMMIOReadU16: addr=0x%08x val = 0x%04x\n", PCNETSTATE_2_DEVINS(pData)->iInstance,
2982 addr, val & 0xffff));
2983#endif
2984 return val;
2985}
2986
2987static void pcnetMMIOWriteU32(PCNetState *pData, RTGCPHYS addr, uint32_t val)
2988{
2989#ifdef PCNET_DEBUG_IO
2990 Log2(("#%d pcnetMMIOWriteU32: addr=0x%08x val=0x%08x\n", PCNETSTATE_2_DEVINS(pData)->iInstance,
2991 addr, val));
2992#endif
2993 if (addr & 0x10)
2994 pcnetIoportWriteU32(pData, addr & 0x0f, val);
2995 else
2996 {
2997 pcnetAPROMWriteU8(pData, addr, val );
2998 pcnetAPROMWriteU8(pData, addr+1, val >> 8);
2999 pcnetAPROMWriteU8(pData, addr+2, val >> 16);
3000 pcnetAPROMWriteU8(pData, addr+3, val >> 24);
3001 }
3002}
3003
3004static uint32_t pcnetMMIOReadU32(PCNetState *pData, RTGCPHYS addr)
3005{
3006 uint32_t val;
3007 int rc;
3008
3009 if (addr & 0x10)
3010 val = pcnetIoportReadU32(pData, addr & 0x0f, &rc);
3011 else
3012 {
3013 val = pcnetAPROMReadU8(pData, addr+3);
3014 val <<= 8;
3015 val |= pcnetAPROMReadU8(pData, addr+2);
3016 val <<= 8;
3017 val |= pcnetAPROMReadU8(pData, addr+1);
3018 val <<= 8;
3019 val |= pcnetAPROMReadU8(pData, addr );
3020 }
3021#ifdef PCNET_DEBUG_IO
3022 Log2(("#%d pcnetMMIOReadU32: addr=0x%08x val=0x%08x\n", PCNETSTATE_2_DEVINS(pData)->iInstance,
3023 addr, val));
3024#endif
3025 return val;
3026}
3027
3028
3029/**
3030 * Port I/O Handler for IN operations.
3031 *
3032 * @returns VBox status code.
3033 *
3034 * @param pDevIns The device instance.
3035 * @param pvUser User argument.
3036 * @param Port Port number used for the IN operation.
3037 * @param pu32 Where to store the result.
3038 * @param cb Number of bytes read.
3039 */
3040PDMBOTHCBDECL(int) pcnetIOPortAPromRead(PPDMDEVINS pDevIns, void *pvUser,
3041 RTIOPORT Port, uint32_t *pu32, unsigned cb)
3042{
3043 PCNetState *pData = PDMINS2DATA(pDevIns, PCNetState *);
3044 int rc;
3045 if (cb == 1)
3046 {
3047 STAM_PROFILE_ADV_START(&pData->StatAPROMRead, a);
3048 rc = PDMCritSectEnter(&pData->CritSect, VINF_IOM_HC_IOPORT_WRITE);
3049 if (rc == VINF_SUCCESS)
3050 {
3051 *pu32 = pcnetAPROMReadU8(pData, Port);
3052 PDMCritSectLeave(&pData->CritSect);
3053 }
3054 STAM_PROFILE_ADV_STOP(&pData->StatAPROMRead, a);
3055 }
3056 else
3057 rc = VERR_IOM_IOPORT_UNUSED;
3058 LogFlow(("#%d pcnetIOPortAPromRead: Port=%RTiop *pu32=%#RX32 cb=%d rc=%Vrc\n",
3059 PCNETSTATE_2_DEVINS(pData)->iInstance, Port, *pu32, cb, rc));
3060 return rc;
3061}
3062
3063
3064/**
3065 * Port I/O Handler for OUT operations.
3066 *
3067 * @returns VBox status code.
3068 *
3069 * @param pDevIns The device instance.
3070 * @param pvUser User argument.
3071 * @param Port Port number used for the IN operation.
3072 * @param u32 The value to output.
3073 * @param cb The value size in bytes.
3074 */
3075PDMBOTHCBDECL(int) pcnetIOPortAPromWrite(PPDMDEVINS pDevIns, void *pvUser,
3076 RTIOPORT Port, uint32_t u32, unsigned cb)
3077{
3078 PCNetState *pData = PDMINS2DATA(pDevIns, PCNetState *);
3079 int rc;
3080
3081 if (cb == 1)
3082 {
3083 STAM_PROFILE_ADV_START(&pData->StatAPROMWrite, a);
3084 rc = PDMCritSectEnter(&pData->CritSect, VINF_IOM_HC_IOPORT_WRITE);
3085 if (rc == VINF_SUCCESS)
3086 {
3087 pcnetAPROMWriteU8(pData, Port, u32);
3088 PDMCritSectLeave(&pData->CritSect);
3089 }
3090 STAM_PROFILE_ADV_STOP(&pData->StatAPROMWrite, a);
3091 }
3092 else
3093 {
3094 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
3095 rc = VINF_SUCCESS;
3096 }
3097 LogFlow(("#%d pcnetIOPortAPromWrite: Port=%RTiop u32=%#RX32 cb=%d rc=%Vrc\n",
3098 PCNETSTATE_2_DEVINS(pData)->iInstance, Port, u32, cb, rc));
3099 return rc;
3100}
3101
3102
3103/**
3104 * Port I/O Handler for IN operations.
3105 *
3106 * @returns VBox status code.
3107 *
3108 * @param pDevIns The device instance.
3109 * @param pvUser User argument.
3110 * @param Port Port number used for the IN operation.
3111 * @param pu32 Where to store the result.
3112 * @param cb Number of bytes read.
3113 */
3114PDMBOTHCBDECL(int) pcnetIOPortRead(PPDMDEVINS pDevIns, void *pvUser,
3115 RTIOPORT Port, uint32_t *pu32, unsigned cb)
3116{
3117 PCNetState *pData = PDMINS2DATA(pDevIns, PCNetState *);
3118 int rc = VINF_SUCCESS;
3119
3120 STAM_PROFILE_ADV_START(&pData->CTXSUFF(StatIORead), a);
3121 rc = PDMCritSectEnter(&pData->CritSect, VINF_IOM_HC_IOPORT_READ);
3122 if (rc == VINF_SUCCESS)
3123 {
3124 switch (cb)
3125 {
3126 case 2: *pu32 = pcnetIoportReadU16(pData, Port, &rc); break;
3127 case 4: *pu32 = pcnetIoportReadU32(pData, Port, &rc); break;
3128 default:
3129 rc = VERR_IOM_IOPORT_UNUSED;
3130 break;
3131 }
3132 PDMCritSectLeave(&pData->CritSect);
3133 }
3134 STAM_PROFILE_ADV_STOP(&pData->CTXSUFF(StatIORead), a);
3135 LogFlow(("#%d pcnetIOPortRead: Port=%RTiop *pu32=%#RX32 cb=%d rc=%Vrc\n",
3136 PCNETSTATE_2_DEVINS(pData)->iInstance, Port, *pu32, cb, rc));
3137 return rc;
3138}
3139
3140
3141/**
3142 * Port I/O Handler for OUT operations.
3143 *
3144 * @returns VBox status code.
3145 *
3146 * @param pDevIns The device instance.
3147 * @param pvUser User argument.
3148 * @param Port Port number used for the IN operation.
3149 * @param u32 The value to output.
3150 * @param cb The value size in bytes.
3151 */
3152PDMBOTHCBDECL(int) pcnetIOPortWrite(PPDMDEVINS pDevIns, void *pvUser,
3153 RTIOPORT Port, uint32_t u32, unsigned cb)
3154{
3155 PCNetState *pData = PDMINS2DATA(pDevIns, PCNetState *);
3156 int rc = VINF_SUCCESS;
3157
3158 STAM_PROFILE_ADV_START(&pData->CTXSUFF(StatIOWrite), a);
3159 rc = PDMCritSectEnter(&pData->CritSect, VINF_IOM_HC_IOPORT_WRITE);
3160 if (rc == VINF_SUCCESS)
3161 {
3162 switch (cb)
3163 {
3164 case 2: rc = pcnetIoportWriteU16(pData, Port, u32); break;
3165 case 4: rc = pcnetIoportWriteU32(pData, Port, u32); break;
3166 default:
3167 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
3168 rc = VERR_INTERNAL_ERROR;
3169 break;
3170 }
3171 PDMCritSectLeave(&pData->CritSect);
3172 }
3173 STAM_PROFILE_ADV_STOP(&pData->CTXSUFF(StatIOWrite), a);
3174 LogFlow(("#%d pcnetIOPortWrite: Port=%RTiop u32=%#RX32 cb=%d rc=%Vrc\n",
3175 PCNETSTATE_2_DEVINS(pData)->iInstance, Port, u32, cb, rc));
3176 return rc;
3177}
3178
3179
3180/**
3181 * Memory mapped I/O Handler for read operations.
3182 *
3183 * @returns VBox status code.
3184 *
3185 * @param pDevIns The device instance.
3186 * @param pvUser User argument.
3187 * @param GCPhysAddr Physical address (in GC) where the read starts.
3188 * @param pv Where to store the result.
3189 * @param cb Number of bytes read.
3190 */
3191PDMBOTHCBDECL(int) pcnetMMIORead(PPDMDEVINS pDevIns, void *pvUser,
3192 RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
3193{
3194 PCNetState *pData = (PCNetState *)pvUser;
3195 int rc = VINF_SUCCESS;
3196
3197 /*
3198 * We have to check the range, because we're page aligning the MMIO stuff presently.
3199 */
3200 if (GCPhysAddr - pData->MMIOBase < PCNET_PNPMMIO_SIZE)
3201 {
3202 STAM_PROFILE_ADV_START(&pData->CTXSUFF(StatMMIORead), a);
3203 rc = PDMCritSectEnter(&pData->CritSect, VINF_IOM_HC_MMIO_READ);
3204 if (rc == VINF_SUCCESS)
3205 {
3206 switch (cb)
3207 {
3208 case 1: *(uint8_t *)pv = pcnetMMIOReadU8 (pData, GCPhysAddr); break;
3209 case 2: *(uint16_t *)pv = pcnetMMIOReadU16(pData, GCPhysAddr); break;
3210 case 4: *(uint32_t *)pv = pcnetMMIOReadU32(pData, GCPhysAddr); break;
3211 default:
3212 AssertMsgFailed(("cb=%d\n", cb));
3213 rc = VERR_INTERNAL_ERROR;
3214 break;
3215 }
3216 PDMCritSectLeave(&pData->CritSect);
3217 }
3218 STAM_PROFILE_ADV_STOP(&pData->CTXSUFF(StatMMIORead), a);
3219 }
3220 else
3221 memset(pv, 0, cb);
3222
3223 LogFlow(("#%d pcnetMMIORead: pvUser=%p:{%.*Rhxs} cb=%d GCPhysAddr=%RGp rc=%Vrc\n",
3224 PCNETSTATE_2_DEVINS(pData)->iInstance, pv, cb, pv, cb, GCPhysAddr, rc));
3225 return rc;
3226}
3227
3228
3229/**
3230 * Port I/O Handler for write operations.
3231 *
3232 * @returns VBox status code.
3233 *
3234 * @param pDevIns The device instance.
3235 * @param pvUser User argument.
3236 * @param GCPhysAddr Physical address (in GC) where the read starts.
3237 * @param pv Where to fetch the result.
3238 * @param cb Number of bytes to write.
3239 */
3240PDMBOTHCBDECL(int) pcnetMMIOWrite(PPDMDEVINS pDevIns, void *pvUser,
3241 RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
3242{
3243 PCNetState *pData = (PCNetState *)pvUser;
3244 int rc = VINF_SUCCESS;
3245
3246 /*
3247 * We have to check the range, because we're page aligning the MMIO stuff presently.
3248 */
3249 if (GCPhysAddr - pData->MMIOBase < PCNET_PNPMMIO_SIZE)
3250 {
3251 STAM_PROFILE_ADV_START(&pData->CTXSUFF(StatMMIOWrite), a);
3252 rc = PDMCritSectEnter(&pData->CritSect, VINF_IOM_HC_MMIO_WRITE);
3253 if (rc == VINF_SUCCESS)
3254 {
3255 switch (cb)
3256 {
3257 case 1: pcnetMMIOWriteU8 (pData, GCPhysAddr, *(uint8_t *)pv); break;
3258 case 2: pcnetMMIOWriteU16(pData, GCPhysAddr, *(uint16_t *)pv); break;
3259 case 4: pcnetMMIOWriteU32(pData, GCPhysAddr, *(uint32_t *)pv); break;
3260 default:
3261 AssertMsgFailed(("cb=%d\n", cb));
3262 rc = VERR_INTERNAL_ERROR;
3263 break;
3264 }
3265 PDMCritSectLeave(&pData->CritSect);
3266 }
3267 // else rc == VINF_IOM_HC_MMIO_WRITE => handle in ring3
3268
3269 STAM_PROFILE_ADV_STOP(&pData->CTXSUFF(StatMMIOWrite), a);
3270 }
3271 LogFlow(("#%d pcnetMMIOWrite: pvUser=%p:{%.*Rhxs} cb=%d GCPhysAddr=%RGp rc=%Vrc\n",
3272 PCNETSTATE_2_DEVINS(pData)->iInstance, pv, cb, pv, cb, GCPhysAddr, rc));
3273 return rc;
3274}
3275
3276
3277#ifdef IN_RING3
3278/**
3279 * Device timer callback function.
3280 *
3281 * @param pDevIns Device instance of the device which registered the timer.
3282 * @param pTimer The timer handle.
3283 * @thread EMT
3284 */
3285static DECLCALLBACK(void) pcnetTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer)
3286{
3287 PCNetState *pData = PDMINS2DATA(pDevIns, PCNetState *);
3288 int rc;
3289
3290 STAM_PROFILE_ADV_START(&pData->StatTimer, a);
3291 rc = PDMCritSectEnter(&pData->CritSect, VERR_PERMISSION_DENIED);
3292 AssertReleaseRC(rc);
3293
3294 pcnetPollTimer(pData);
3295
3296 PDMCritSectLeave(&pData->CritSect);
3297 STAM_PROFILE_ADV_STOP(&pData->StatTimer, a);
3298}
3299
3300
3301/**
3302 * Restore timer callback.
3303 *
3304 * This is only called when've restored a saved state and temporarily
3305 * disconnected the network link to inform the guest that network connections
3306 * should be considered lost.
3307 *
3308 * @param pDevIns Device instance of the device which registered the timer.
3309 * @param pTimer The timer handle.
3310 */
3311static DECLCALLBACK(void) pcnetTimerRestore(PPDMDEVINS pDevIns, PTMTIMER pTimer)
3312{
3313 PCNetState *pData = PDMINS2DATA(pDevIns, PCNetState *);
3314 int rc = PDMCritSectEnter(&pData->CritSect, VERR_PERMISSION_DENIED);
3315 AssertReleaseRC(rc);
3316
3317 rc = VERR_GENERAL_FAILURE;
3318 if (pData->cLinkDownReported <= PCNET_MAX_LINKDOWN_REPORTED)
3319 rc = TMTimerSetMillies(pData->pTimerRestore, 1500);
3320 if (VBOX_FAILURE(rc))
3321 {
3322 pData->fLinkTempDown = false;
3323 if (pData->fLinkUp)
3324 {
3325 LogRel(("PCNet#%d: The link is back up again after the restore.\n",
3326 pDevIns->iInstance));
3327 Log(("#%d pcnetTimerRestore: Clearing ERR and CERR after load. cLinkDownReported=%d\n",
3328 pDevIns->iInstance, pData->cLinkDownReported));
3329 pData->aCSR[0] &= ~(BIT(15) | BIT(13)); /* ERR | CERR - probably not 100% correct either... */
3330 pData->Led.Actual.s.fError = 0;
3331 }
3332 }
3333 else
3334 Log(("#%d pcnetTimerRestore: cLinkDownReported=%d, wait another 1500ms...\n",
3335 pDevIns->iInstance, pData->cLinkDownReported));
3336
3337 PDMCritSectLeave(&pData->CritSect);
3338}
3339
3340
3341/**
3342 * Callback function for mapping an PCI I/O region.
3343 *
3344 * @return VBox status code.
3345 * @param pPciDev Pointer to PCI device. Use pPciDev->pDevIns to get the device instance.
3346 * @param iRegion The region number.
3347 * @param GCPhysAddress Physical address of the region. If iType is PCI_ADDRESS_SPACE_IO, this is an
3348 * I/O port, else it's a physical address.
3349 * This address is *NOT* relative to pci_mem_base like earlier!
3350 * @param cb Region size.
3351 * @param enmType One of the PCI_ADDRESS_SPACE_* values.
3352 */
3353static DECLCALLBACK(int) pcnetIOPortMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion,
3354 RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
3355{
3356 int rc;
3357 PPDMDEVINS pDevIns = pPciDev->pDevIns;
3358 RTIOPORT Port = (RTIOPORT)GCPhysAddress;
3359 PCNetState *pData = PCIDEV_2_PCNETSTATE(pPciDev);
3360
3361 Assert(enmType == PCI_ADDRESS_SPACE_IO);
3362 Assert(cb >= 0x20);
3363
3364 rc = PDMDevHlpIOPortRegister(pDevIns, Port, 0x10, 0, pcnetIOPortAPromWrite,
3365 pcnetIOPortAPromRead, NULL, NULL, "PCNet ARPOM");
3366 if (VBOX_FAILURE(rc))
3367 return rc;
3368 rc = PDMDevHlpIOPortRegister(pDevIns, Port + 0x10, 0x10, 0, pcnetIOPortWrite,
3369 pcnetIOPortRead, NULL, NULL, "PCNet");
3370 if (VBOX_FAILURE(rc))
3371 return rc;
3372
3373 if (pData->fGCEnabled)
3374 {
3375 rc = PDMDevHlpIOPortRegisterGC(pDevIns, Port, 0x10, 0, "pcnetIOPortAPromWrite",
3376 "pcnetIOPortAPromRead", NULL, NULL, "PCNet aprom");
3377 if (VBOX_FAILURE(rc))
3378 return rc;
3379 rc = PDMDevHlpIOPortRegisterGC(pDevIns, Port + 0x10, 0x10, 0, "pcnetIOPortWrite",
3380 "pcnetIOPortRead", NULL, NULL, "PCNet");
3381 if (VBOX_FAILURE(rc))
3382 return rc;
3383 }
3384 if (pData->fR0Enabled)
3385 {
3386 rc = PDMDevHlpIOPortRegisterR0(pDevIns, Port, 0x10, 0, "pcnetIOPortAPromWrite",
3387 "pcnetIOPortAPromRead", NULL, NULL, "PCNet aprom");
3388 if (VBOX_FAILURE(rc))
3389 return rc;
3390 rc = PDMDevHlpIOPortRegisterR0(pDevIns, Port + 0x10, 0x10, 0, "pcnetIOPortWrite",
3391 "pcnetIOPortRead", NULL, NULL, "PCNet");
3392 if (VBOX_FAILURE(rc))
3393 return rc;
3394 }
3395
3396 pData->IOPortBase = Port;
3397 return VINF_SUCCESS;
3398}
3399
3400
3401/**
3402 * Callback function for mapping the MMIO region.
3403 *
3404 * @return VBox status code.
3405 * @param pPciDev Pointer to PCI device. Use pPciDev->pDevIns to get the device instance.
3406 * @param iRegion The region number.
3407 * @param GCPhysAddress Physical address of the region. If iType is PCI_ADDRESS_SPACE_IO, this is an
3408 * I/O port, else it's a physical address.
3409 * This address is *NOT* relative to pci_mem_base like earlier!
3410 * @param cb Region size.
3411 * @param enmType One of the PCI_ADDRESS_SPACE_* values.
3412 */
3413static DECLCALLBACK(int) pcnetMMIOMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion,
3414 RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
3415{
3416 PCNetState *pData = PCIDEV_2_PCNETSTATE(pPciDev);
3417 int rc;
3418
3419 Assert(enmType == PCI_ADDRESS_SPACE_MEM);
3420 Assert(cb >= PCNET_PNPMMIO_SIZE);
3421
3422 /* We use the assigned size here, because we currently only support page aligned MMIO ranges. */
3423 rc = PDMDevHlpMMIORegister(pPciDev->pDevIns, GCPhysAddress, cb, pData,
3424 pcnetMMIOWrite, pcnetMMIORead, NULL, "PCNet");
3425 if (VBOX_FAILURE(rc))
3426 return rc;
3427 pData->MMIOBase = GCPhysAddress;
3428 return rc;
3429}
3430
3431
3432/**
3433 * PCNET status info callback.
3434 *
3435 * @param pDevIns The device instance.
3436 * @param pHlp The output helpers.
3437 * @param pszArgs The arguments.
3438 */
3439static DECLCALLBACK(void) pcnetInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
3440{
3441 PCNetState *pData = PDMINS2DATA(pDevIns, PCNetState *);
3442 bool fRcvRing = false;
3443 bool fXmtRing = false;
3444
3445 /*
3446 * Parse args.
3447 */
3448 if (pszArgs)
3449 {
3450 fRcvRing = strstr(pszArgs, "verbose") || strstr(pszArgs, "rcv");
3451 fXmtRing = strstr(pszArgs, "verbose") || strstr(pszArgs, "xmt");
3452 }
3453
3454 /*
3455 * Show info.
3456 */
3457 pHlp->pfnPrintf(pHlp,
3458 "pcnet #%d: port=%RTiop mmio=%RGp mac-cfg=%.*Rhxs %s\n",
3459 pDevIns->iInstance,
3460 pData->IOPortBase, pData->MMIOBase, sizeof(pData->MacConfigured), &pData->MacConfigured,
3461 pData->fAm79C973 ? "Am79C973" : "Am79C970A", pData->fGCEnabled ? " GC" : "", pData->fR0Enabled ? " R0" : "");
3462
3463 PDMCritSectEnter(&pData->CritSect, VERR_INTERNAL_ERROR); /* Take it here so we know why we're hanging... */
3464
3465 pHlp->pfnPrintf(pHlp,
3466 "CSR0=%04RX32:\n",
3467 pData->aCSR[0]);
3468
3469 pHlp->pfnPrintf(pHlp,
3470 "CSR1=%04RX32:\n",
3471 pData->aCSR[1]);
3472
3473 pHlp->pfnPrintf(pHlp,
3474 "CSR2=%04RX32:\n",
3475 pData->aCSR[2]);
3476
3477 pHlp->pfnPrintf(pHlp,
3478 "CSR3=%04RX32: BSWP=%d EMBA=%d DXMT2PD=%d LAPPEN=%d DXSUFLO=%d IDONM=%d TINTM=%d RINTM=%d MERRM=%d MISSM=%d BABLM=%d\n",
3479 pData->aCSR[3],
3480 !!(pData->aCSR[3] & BIT(2)), !!(pData->aCSR[3] & BIT(3)), !!(pData->aCSR[3] & BIT(4)), CSR_LAPPEN(pData),
3481 CSR_DXSUFLO(pData), !!(pData->aCSR[3] & BIT(8)), !!(pData->aCSR[3] & BIT(9)), !!(pData->aCSR[3] & BIT(10)),
3482 !!(pData->aCSR[3] & BIT(11)), !!(pData->aCSR[3] & BIT(12)), !!(pData->aCSR[3] & BIT(14)));
3483
3484 pHlp->pfnPrintf(pHlp,
3485 "CSR4=%04RX32: JABM=%d JAB=%d TXSTRM=%d TXSTRT=%d RCVCOOM=%d RCVCCO=%d UINT=%d UINTCMD=%d\n"
3486 " MFCOM=%d MFCO=%d ASTRP_RCV=%d APAD_XMT=%d DPOLL=%d TIMER=%d EMAPLUS=%d EN124=%d\n",
3487 pData->aCSR[4],
3488 !!(pData->aCSR[4] & BIT( 0)), !!(pData->aCSR[4] & BIT( 1)), !!(pData->aCSR[4] & BIT( 2)), !!(pData->aCSR[4] & BIT( 3)),
3489 !!(pData->aCSR[4] & BIT( 4)), !!(pData->aCSR[4] & BIT( 5)), !!(pData->aCSR[4] & BIT( 6)), !!(pData->aCSR[4] & BIT( 7)),
3490 !!(pData->aCSR[4] & BIT( 8)), !!(pData->aCSR[4] & BIT( 9)), !!(pData->aCSR[4] & BIT(10)), !!(pData->aCSR[4] & BIT(11)),
3491 !!(pData->aCSR[4] & BIT(12)), !!(pData->aCSR[4] & BIT(13)), !!(pData->aCSR[4] & BIT(14)), !!(pData->aCSR[4] & BIT(15)));
3492
3493 pHlp->pfnPrintf(pHlp,
3494 "CSR5=%04RX32:\n",
3495 pData->aCSR[5]);
3496
3497 pHlp->pfnPrintf(pHlp,
3498 "CSR6=%04RX32: RLEN=%03x* TLEN=%03x* [* encoded]\n",
3499 pData->aCSR[6],
3500 (pData->aCSR[6] >> 8) & 0xf, (pData->aCSR[6] >> 12) & 0xf);
3501
3502 pHlp->pfnPrintf(pHlp,
3503 "CSR8..11=%04RX32,%04RX32,%04RX32,%04RX32: LADRF=%016RX64\n",
3504 pData->aCSR[8], pData->aCSR[9], pData->aCSR[10], pData->aCSR[11],
3505 (uint64_t)(pData->aCSR[ 8] & 0xffff)
3506 | (uint64_t)(pData->aCSR[ 9] & 0xffff) << 16
3507 | (uint64_t)(pData->aCSR[10] & 0xffff) << 32
3508 | (uint64_t)(pData->aCSR[11] & 0xffff) << 48);
3509
3510 pHlp->pfnPrintf(pHlp,
3511 "CSR12..14=%04RX32,%04RX32,%04RX32: PADR=%02x %02x %02x %02x %02x %02x (Current MAC Address)\n",
3512 pData->aCSR[12], pData->aCSR[13], pData->aCSR[14],
3513 pData->aCSR[12] & 0xff,
3514 (pData->aCSR[12] >> 8) & 0xff,
3515 pData->aCSR[13] & 0xff,
3516 (pData->aCSR[13] >> 8) & 0xff,
3517 pData->aCSR[14] & 0xff,
3518 (pData->aCSR[14] >> 8) & 0xff);
3519
3520 pHlp->pfnPrintf(pHlp,
3521 "CSR15=%04RX32: DXR=%d DTX=%d LOOP=%d DXMTFCS=%d FCOLL=%d DRTY=%d INTL=%d PORTSEL=%d LTR=%d\n"
3522 " MENDECL=%d DAPC=%d DLNKTST=%d DRCVPV=%d DRCVBC=%d PROM=%d\n",
3523 pData->aCSR[15],
3524 !!(pData->aCSR[15] & BIT( 0)), !!(pData->aCSR[15] & BIT( 1)), !!(pData->aCSR[15] & BIT( 2)), !!(pData->aCSR[15] & BIT( 3)),
3525 !!(pData->aCSR[15] & BIT( 4)), !!(pData->aCSR[15] & BIT( 5)), !!(pData->aCSR[15] & BIT( 6)), (pData->aCSR[15] >> 7) & 3,
3526 !!(pData->aCSR[15] & BIT( 9)), !!(pData->aCSR[15] & BIT(10)), !!(pData->aCSR[15] & BIT(11)),
3527 !!(pData->aCSR[15] & BIT(12)), !!(pData->aCSR[15] & BIT(13)), !!(pData->aCSR[15] & BIT(14)), !!(pData->aCSR[15] & BIT(15)));
3528
3529 pHlp->pfnPrintf(pHlp,
3530 "CSR46=%04RX32: POLL=%04x (Poll Time Counter)\n",
3531 pData->aCSR[46], pData->aCSR[46] & 0xffff);
3532
3533 pHlp->pfnPrintf(pHlp,
3534 "CSR47=%04RX32: POLLINT=%04x (Poll Time Interval)\n",
3535 pData->aCSR[47], pData->aCSR[47] & 0xffff);
3536
3537 pHlp->pfnPrintf(pHlp,
3538 "CSR58=%04RX32: SWSTYLE=%02x %s SSIZE32=%d CSRPCNET=%d APERRENT=%d\n",
3539 pData->aCSR[58],
3540 pData->aCSR[58] & 0x7f,
3541 (pData->aCSR[58] & 0x7f) == 0 ? "C-LANCE / PCnet-ISA"
3542 : (pData->aCSR[58] & 0x7f) == 1 ? "ILACC"
3543 : (pData->aCSR[58] & 0x7f) == 2 ? "PCNet-PCI II"
3544 : (pData->aCSR[58] & 0x7f) == 3 ? "PCNet-PCI II controller"
3545 : "!!reserved!!",
3546 !!(pData->aCSR[58] & BIT(8)), !!(pData->aCSR[58] & BIT(9)), !!(pData->aCSR[58] & BIT(10)));
3547
3548 pHlp->pfnPrintf(pHlp,
3549 "CSR112=%04RX32: MFC=%04x (Missed receive Frame Count)\n",
3550 pData->aCSR[112], pData->aCSR[112] & 0xffff);
3551
3552 pHlp->pfnPrintf(pHlp,
3553 "CSR122=%04RX32: RCVALGN=%04x (Receive Frame Align)\n",
3554 pData->aCSR[122], !!(pData->aCSR[122] & BIT(0)));
3555
3556 pHlp->pfnPrintf(pHlp,
3557 "CSR124=%04RX32: RPA=%04x (Runt Packet Accept)\n",
3558 pData->aCSR[122], !!(pData->aCSR[122] & BIT(3)));
3559
3560
3561 /*
3562 * Dump the receive ring.
3563 */
3564 pHlp->pfnPrintf(pHlp,
3565 "RCVRL=%04x RCVRC=%04x GCRDRA=%RX32 \n"
3566 "CRDA=%08RX32 CRBA=%08RX32 CRBC=%03x CRST=%04x\n"
3567 "NRDA=%08RX32 NRBA=%08RX32 NRBC=%03x NRST=%04x\n"
3568 "NNRDA=%08RX32\n"
3569 ,
3570 CSR_RCVRL(pData), CSR_RCVRC(pData), pData->GCRDRA,
3571 CSR_CRDA(pData), CSR_CRBA(pData), CSR_CRBC(pData), CSR_CRST(pData),
3572 CSR_NRDA(pData), CSR_NRBA(pData), CSR_NRBC(pData), CSR_NRST(pData),
3573 CSR_NNRD(pData));
3574 if (fRcvRing)
3575 {
3576 const unsigned cb = 1 << pData->iLog2DescSize;
3577 RTGCPHYS GCPhys = pData->GCRDRA;
3578 unsigned i = CSR_RCVRL(pData);
3579 while (i-- > 0)
3580 {
3581 RMD rmd;
3582 pcnetRmdLoad(pData, &rmd, PHYSADDR(pData, GCPhys));
3583 pHlp->pfnPrintf(pHlp,
3584 "%04x %RGp:%c%c RBADR=%08RX32 BCNT=%03x MCNT=%03x "
3585 "OWN=%d ERR=%d FRAM=%d OFLO=%d CRC=%d BUFF=%d STP=%d ENP=%d BPE=%d "
3586 "PAM=%d LAFM=%d BAM=%d RCC=%02x RPC=%02x ONES=%x ZEROS=%d\n",
3587 i, GCPhys, i + 1 == CSR_RCVRC(pData) ? '*' : ' ', GCPhys == CSR_CRDA(pData) ? '*' : ' ',
3588 rmd.rmd0.rbadr, 4096 - rmd.rmd1.bcnt, rmd.rmd2.mcnt,
3589 rmd.rmd1.own, rmd.rmd1.err, rmd.rmd1.fram, rmd.rmd1.oflo, rmd.rmd1.crc, rmd.rmd1.buff,
3590 rmd.rmd1.stp, rmd.rmd1.enp, rmd.rmd1.bpe,
3591 rmd.rmd1.pam, rmd.rmd1.lafm, rmd.rmd1.bam, rmd.rmd2.rcc, rmd.rmd2.rpc,
3592 rmd.rmd1.ones, rmd.rmd2.zeros);
3593
3594 GCPhys += cb;
3595 }
3596 }
3597
3598 /*
3599 * Dump the transmit ring.
3600 */
3601 pHlp->pfnPrintf(pHlp,
3602 "XMTRL=%04x XMTRC=%04x GCTDRA=%08RX32 BADX=%08RX32\n"
3603 "PXDA=%08RX32 PXBC=%03x PXST=%04x\n"
3604 "CXDA=%08RX32 CXBA=%08RX32 CXBC=%03x CXST=%04x\n"
3605 "NXDA=%08RX32 NXBA=%08RX32 NXBC=%03x NXST=%04x\n"
3606 "NNXDA=%08RX32\n"
3607 ,
3608 CSR_XMTRL(pData), CSR_XMTRC(pData),
3609 pData->GCTDRA, CSR_BADX(pData),
3610 CSR_PXDA(pData), CSR_PXBC(pData), CSR_PXST(pData),
3611 CSR_CXDA(pData), CSR_CXBA(pData), CSR_CXBC(pData), CSR_CXST(pData),
3612 CSR_NXDA(pData), CSR_NXBA(pData), CSR_NXBC(pData), CSR_NXST(pData),
3613 CSR_NNXD(pData));
3614 if (fXmtRing)
3615 {
3616 const unsigned cb = 1 << pData->iLog2DescSize;
3617 RTGCPHYS GCPhys = pData->GCTDRA;
3618 unsigned i = CSR_RCVRL(pData);
3619 while (i-- > 0)
3620 {
3621 TMD tmd;
3622 pcnetTmdLoad(pData, &tmd, PHYSADDR(pData, GCPhys));
3623 pHlp->pfnPrintf(pHlp,
3624 "%04x %RGp:%c%c TBADR=%08RX32 BCNT=%03x OWN=%d "
3625 "ERR=%d NOFCS=%d LTINT=%d ONE=%d DEF=%d STP=%d ENP=%d BPE=%d "
3626 "BUFF=%d UFLO=%d EXDEF=%d LCOL=%d LCAR=%d RTRY=%d TDR=%03x TRC=%x ONES=%x\n"
3627 ,
3628 i, GCPhys, i + 1 == CSR_XMTRC(pData) ? '*' : ' ', GCPhys == CSR_CXDA(pData) ? '*' : ' ',
3629 tmd.tmd0.tbadr, 4096 - tmd.tmd1.bcnt,
3630 tmd.tmd2.tdr,
3631 tmd.tmd2.trc,
3632 tmd.tmd1.own,
3633 tmd.tmd1.err,
3634 tmd.tmd1.nofcs,
3635 tmd.tmd1.ltint,
3636 tmd.tmd1.one,
3637 tmd.tmd1.def,
3638 tmd.tmd1.stp,
3639 tmd.tmd1.enp,
3640 tmd.tmd1.bpe,
3641 tmd.tmd2.buff,
3642 tmd.tmd2.uflo,
3643 tmd.tmd2.exdef,
3644 tmd.tmd2.lcol,
3645 tmd.tmd2.lcar,
3646 tmd.tmd2.rtry,
3647 tmd.tmd2.tdr,
3648 tmd.tmd2.trc,
3649 tmd.tmd1.ones);
3650
3651 GCPhys += cb;
3652 }
3653 }
3654
3655 PDMCritSectLeave(&pData->CritSect);
3656}
3657
3658
3659/**
3660 * Saves a state of the PC-Net II device.
3661 *
3662 * @returns VBox status code.
3663 * @param pDevIns The device instance.
3664 * @param pSSMHandle The handle to save the state to.
3665 */
3666static DECLCALLBACK(int) pcnetSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle)
3667{
3668 PCNetState *pData = PDMINS2DATA(pDevIns, PCNetState *);
3669
3670 SSMR3PutBool(pSSMHandle, pData->fLinkUp);
3671 SSMR3PutU32(pSSMHandle, pData->u32RAP);
3672 SSMR3PutS32(pSSMHandle, pData->iISR);
3673 SSMR3PutU32(pSSMHandle, pData->u32Lnkst);
3674 SSMR3PutGCPhys(pSSMHandle, pData->GCRDRA);
3675 SSMR3PutGCPhys(pSSMHandle, pData->GCTDRA);
3676 SSMR3PutMem(pSSMHandle, pData->aPROM, sizeof(pData->aPROM));
3677 SSMR3PutMem(pSSMHandle, pData->aCSR, sizeof(pData->aCSR));
3678 SSMR3PutMem(pSSMHandle, pData->aBCR, sizeof(pData->aBCR));
3679 SSMR3PutMem(pSSMHandle, pData->aMII, sizeof(pData->aMII));
3680 SSMR3PutU64(pSSMHandle, pData->u64LastPoll);
3681 SSMR3PutMem(pSSMHandle, &pData->MacConfigured, sizeof(pData->MacConfigured));
3682 SSMR3PutBool(pSSMHandle, pData->fAm79C973);
3683#ifdef PCNET_NO_POLLING
3684 return VINF_SUCCESS;
3685#else
3686 return TMR3TimerSave(pData->CTXSUFF(pTimerPoll), pSSMHandle);
3687#endif
3688}
3689
3690
3691/**
3692 * Loads a saved PC-Net II device state.
3693 *
3694 * @returns VBox status code.
3695 * @param pDevIns The device instance.
3696 * @param pSSMHandle The handle to the saved state.
3697 * @param u32Version The data unit version number.
3698 */
3699static DECLCALLBACK(int) pcnetLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle, uint32_t u32Version)
3700{
3701 PCNetState *pData = PDMINS2DATA(pDevIns, PCNetState *);
3702 PDMMAC Mac;
3703 if (u32Version != PCNET_SAVEDSTATE_VERSION)
3704 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
3705
3706 /* restore data */
3707 SSMR3GetBool(pSSMHandle, &pData->fLinkUp);
3708 SSMR3GetU32(pSSMHandle, &pData->u32RAP);
3709 SSMR3GetS32(pSSMHandle, &pData->iISR);
3710 SSMR3GetU32(pSSMHandle, &pData->u32Lnkst);
3711 SSMR3GetGCPhys(pSSMHandle, &pData->GCRDRA);
3712 SSMR3GetGCPhys(pSSMHandle, &pData->GCTDRA);
3713 SSMR3GetMem(pSSMHandle, &pData->aPROM, sizeof(pData->aPROM));
3714 SSMR3GetMem(pSSMHandle, &pData->aCSR, sizeof(pData->aCSR));
3715 SSMR3GetMem(pSSMHandle, &pData->aBCR, sizeof(pData->aBCR));
3716 SSMR3GetMem(pSSMHandle, &pData->aMII, sizeof(pData->aMII));
3717 SSMR3GetU64(pSSMHandle, &pData->u64LastPoll);
3718 SSMR3GetMem(pSSMHandle, &Mac, sizeof(Mac));
3719 Assert(!memcmp(&Mac, &pData->MacConfigured, sizeof(Mac)));
3720 SSMR3GetBool(pSSMHandle, &pData->fAm79C973);
3721#ifndef PCNET_NO_POLLING
3722 TMR3TimerLoad(pData->CTXSUFF(pTimerPoll), pSSMHandle);
3723#endif
3724
3725 pData->iLog2DescSize = BCR_SWSTYLE(pData)
3726 ? 4
3727 : 3;
3728 pData->GCUpperPhys = BCR_SSIZE32(pData)
3729 ? 0
3730 : (0xff00 & (uint32_t)pData->aCSR[2]) << 16;
3731
3732 /* update promiscuous mode. */
3733 if (pData->pDrv)
3734 pData->pDrv->pfnSetPromiscuousMode(pData->pDrv, CSR_PROM(pData));
3735
3736#ifdef PCNET_NO_POLLING
3737 /* Enable physical monitoring again (!) */
3738 pcnetUpdateRingHandlers(pData);
3739#endif
3740 /* Indicate link down to the guest OS that all network connections have been lost. */
3741 if (pData->fLinkUp)
3742 {
3743 pData->fLinkTempDown = true;
3744 pData->cLinkDownReported = 0;
3745 pData->aCSR[0] |= BIT(15) | BIT(13); /* ERR | CERR (this is probably wrong) */
3746 pData->Led.Asserted.s.fError = pData->Led.Actual.s.fError = 1;
3747 return TMTimerSetMillies(pData->pTimerRestore, 5000);
3748 }
3749 return VINF_SUCCESS;
3750}
3751
3752
3753/**
3754 * Queries an interface to the driver.
3755 *
3756 * @returns Pointer to interface.
3757 * @returns NULL if the interface was not supported by the driver.
3758 * @param pInterface Pointer to this interface structure.
3759 * @param enmInterface The requested interface identification.
3760 * @thread Any thread.
3761 */
3762static DECLCALLBACK(void *) pcnetQueryInterface(struct PDMIBASE *pInterface, PDMINTERFACE enmInterface)
3763{
3764 PCNetState *pData = (PCNetState *)((uintptr_t)pInterface - RT_OFFSETOF(PCNetState, IBase));
3765 Assert(&pData->IBase == pInterface);
3766 switch (enmInterface)
3767 {
3768 case PDMINTERFACE_BASE:
3769 return &pData->IBase;
3770 case PDMINTERFACE_NETWORK_PORT:
3771 return &pData->INetworkPort;
3772 case PDMINTERFACE_NETWORK_CONFIG:
3773 return &pData->INetworkConfig;
3774 case PDMINTERFACE_LED_PORTS:
3775 return &pData->ILeds;
3776 default:
3777 return NULL;
3778 }
3779}
3780
3781/** Converts a pointer to PCNetState::INetworkPort to a PCNetState pointer. */
3782#define INETWORKPORT_2_DATA(pInterface) ( (PCNetState *)((uintptr_t)pInterface - RT_OFFSETOF(PCNetState, INetworkPort)) )
3783
3784
3785/**
3786 * Check if the device/driver can receive data now.
3787 * This must be called before the pfnRecieve() method is called.
3788 *
3789 * @returns Number of bytes the driver can receive.
3790 * @param pInterface Pointer to the interface structure containing the called function pointer.
3791 * @thread EMT
3792 */
3793static DECLCALLBACK(size_t) pcnetCanReceive(PPDMINETWORKPORT pInterface)
3794{
3795 size_t cb;
3796 int rc;
3797 PCNetState *pData = INETWORKPORT_2_DATA(pInterface);
3798
3799 rc = PDMCritSectEnter(&pData->CritSect, VERR_PERMISSION_DENIED);
3800 AssertReleaseRC(rc);
3801
3802 cb = pcnetCanReceiveNoSync(pData);
3803
3804 PDMCritSectLeave(&pData->CritSect);
3805 return cb;
3806}
3807
3808
3809/**
3810 * Receive data from the network.
3811 *
3812 * @returns VBox status code.
3813 * @param pInterface Pointer to the interface structure containing the called function pointer.
3814 * @param pvBuf The available data.
3815 * @param cb Number of bytes available in the buffer.
3816 * @thread EMT
3817 */
3818static DECLCALLBACK(int) pcnetReceive(PPDMINETWORKPORT pInterface, const void *pvBuf, size_t cb)
3819{
3820 PCNetState *pData = INETWORKPORT_2_DATA(pInterface);
3821 int rc;
3822
3823 STAM_PROFILE_ADV_START(&pData->StatReceive, a);
3824 rc = PDMCritSectEnter(&pData->CritSect, VERR_PERMISSION_DENIED);
3825 AssertReleaseRC(rc);
3826
3827 if (cb > 70) /* unqualified guess */
3828 pData->Led.Asserted.s.fReading = pData->Led.Actual.s.fReading = 1;
3829 pcnetReceiveNoSync(pData, (const uint8_t*)pvBuf, cb);
3830 pData->Led.Actual.s.fReading = 0;
3831
3832 PDMCritSectLeave(&pData->CritSect);
3833 STAM_PROFILE_ADV_STOP(&pData->StatReceive, a);
3834
3835 return VINF_SUCCESS;
3836}
3837
3838/** Converts a pointer to PCNetState::INetworkConfig to a PCNetState pointer. */
3839#define INETWORKCONFIG_2_DATA(pInterface) ( (PCNetState *)((uintptr_t)pInterface - RT_OFFSETOF(PCNetState, INetworkConfig)) )
3840
3841
3842/**
3843 * Gets the current Media Access Control (MAC) address.
3844 *
3845 * @returns VBox status code.
3846 * @param pInterface Pointer to the interface structure containing the called function pointer.
3847 * @param pMac Where to store the MAC address.
3848 * @thread EMT
3849 */
3850static DECLCALLBACK(int) pcnetGetMac(PPDMINETWORKCONFIG pInterface, PPDMMAC *pMac)
3851{
3852 PCNetState *pData = INETWORKCONFIG_2_DATA(pInterface);
3853 memcpy(pMac, pData->aPROM, sizeof(*pMac));
3854 return VINF_SUCCESS;
3855}
3856
3857
3858/**
3859 * Gets the new link state.
3860 *
3861 * @returns The current link state.
3862 * @param pInterface Pointer to the interface structure containing the called function pointer.
3863 * @thread EMT
3864 */
3865static DECLCALLBACK(PDMNETWORKLINKSTATE) pcnetGetLinkState(PPDMINETWORKCONFIG pInterface)
3866{
3867 PCNetState *pData = INETWORKCONFIG_2_DATA(pInterface);
3868 if (pData->fLinkUp && !pData->fLinkTempDown)
3869 return PDMNETWORKLINKSTATE_UP;
3870 if (!pData->fLinkUp)
3871 return PDMNETWORKLINKSTATE_DOWN;
3872 if (pData->fLinkTempDown)
3873 return PDMNETWORKLINKSTATE_DOWN_RESUME;
3874 AssertMsgFailed(("Invalid link state!\n"));
3875 return PDMNETWORKLINKSTATE_INVALID;
3876}
3877
3878
3879/**
3880 * Sets the new link state.
3881 *
3882 * @returns VBox status code.
3883 * @param pInterface Pointer to the interface structure containing the called function pointer.
3884 * @param enmState The new link state
3885 * @thread EMT
3886 */
3887static DECLCALLBACK(int) pcnetSetLinkState(PPDMINETWORKCONFIG pInterface, PDMNETWORKLINKSTATE enmState)
3888{
3889 PCNetState *pData = INETWORKCONFIG_2_DATA(pInterface);
3890 bool fLinkUp;
3891 if ( enmState != PDMNETWORKLINKSTATE_DOWN
3892 && enmState != PDMNETWORKLINKSTATE_UP)
3893 {
3894 AssertMsgFailed(("Invalid parameter enmState=%d\n", enmState));
3895 return VERR_INVALID_PARAMETER;
3896 }
3897
3898 /* has the state changed? */
3899 fLinkUp = enmState == PDMNETWORKLINKSTATE_UP;
3900 if (pData->fLinkUp != fLinkUp)
3901 {
3902 pData->fLinkUp = fLinkUp;
3903 if (fLinkUp)
3904 {
3905 /* connect */
3906 pData->aCSR[0] &= ~(BIT(15) | BIT(13)); /* ERR | CERR - probably not 100% correct either... */
3907 pData->Led.Actual.s.fError = 0;
3908 }
3909 else
3910 {
3911 /* disconnect */
3912 pData->cLinkDownReported = 0;
3913 pData->aCSR[0] |= BIT(15) | BIT(13); /* ERR | CERR (this is probably wrong) */
3914 pData->Led.Asserted.s.fError = pData->Led.Actual.s.fError = 1;
3915 }
3916 Assert(!PDMCritSectIsOwner(&pData->CritSect));
3917 pData->pDrv->pfnNotifyLinkChanged(pData->pDrv, enmState);
3918 }
3919 return VINF_SUCCESS;
3920}
3921
3922
3923/**
3924 * Gets the pointer to the status LED of a unit.
3925 *
3926 * @returns VBox status code.
3927 * @param pInterface Pointer to the interface structure containing the called function pointer.
3928 * @param iLUN The unit which status LED we desire.
3929 * @param ppLed Where to store the LED pointer.
3930 */
3931static DECLCALLBACK(int) pcnetQueryStatusLed(PPDMILEDPORTS pInterface, unsigned iLUN, PPDMLED *ppLed)
3932{
3933 PCNetState *pData = (PCNetState *)( (uintptr_t)pInterface - RT_OFFSETOF(PCNetState, ILeds) );
3934 if (iLUN == 0)
3935 {
3936 *ppLed = &pData->Led;
3937 return VINF_SUCCESS;
3938 }
3939 return VERR_PDM_LUN_NOT_FOUND;
3940}
3941
3942
3943/**
3944 * @copydoc FNPDMDEVRESET
3945 */
3946static DECLCALLBACK(void) pcnetReset(PPDMDEVINS pDevIns)
3947{
3948 PCNetState *pData = PDMINS2DATA(pDevIns, PCNetState *);
3949 if (pData->fLinkTempDown)
3950 {
3951 pData->cLinkDownReported = 0x10000;
3952 TMTimerStop(pData->pTimerRestore);
3953 pcnetTimerRestore(pDevIns, pData->pTimerRestore);
3954 }
3955
3956 /** @todo How to flush the queues? */
3957 pcnetHardReset(pData);
3958}
3959
3960
3961/**
3962 * @copydoc FNPDMDEVRELOCATE
3963 */
3964static DECLCALLBACK(void) pcnetRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
3965{
3966 PCNetState *pData = PDMINS2DATA(pDevIns, PCNetState *);
3967 pData->pDevInsGC = PDMDEVINS_2_GCPTR(pDevIns);
3968 pData->pXmitQueueGC = PDMQueueGCPtr(pData->pXmitQueueHC);
3969 pData->pCanRxQueueGC = PDMQueueGCPtr(pData->pCanRxQueueHC);
3970#ifdef PCNET_NO_POLLING
3971 *(RTHCUINTPTR *)&pData->pfnEMInterpretInstructionGC += offDelta;
3972#else
3973 pData->pTimerPollGC = TMTimerGCPtr(pData->pTimerPollHC);
3974#endif
3975}
3976
3977
3978/**
3979 * Destruct a device instance.
3980 *
3981 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
3982 * resources can be freed correctly.
3983 *
3984 * @returns VBox status.
3985 * @param pDevIns The device instance data.
3986 */
3987static DECLCALLBACK(int) pcnetDestruct(PPDMDEVINS pDevIns)
3988{
3989 PCNetState *pData = PDMINS2DATA(pDevIns, PCNetState *);
3990
3991 int rc = PDMCritSectEnter(&pData->CritSect, VERR_ACCESS_DENIED);
3992 AssertReleaseRC(rc);
3993
3994 RTSemEventDestroy(pData->hSendEventSem);
3995 pData->hSendEventSem = 0;
3996 PDMCritSectLeave(&pData->CritSect);
3997
3998 PDMR3CritSectDelete(&pData->CritSect);
3999 return VINF_SUCCESS;
4000}
4001
4002
4003/**
4004 * Construct a device instance for a VM.
4005 *
4006 * @returns VBox status.
4007 * @param pDevIns The device instance data.
4008 * If the registration structure is needed, pDevIns->pDevReg points to it.
4009 * @param iInstance Instance number. Use this to figure out which registers and such to use.
4010 * The device number is also found in pDevIns->iInstance, but since it's
4011 * likely to be freqently used PDM passes it as parameter.
4012 * @param pCfgHandle Configuration node handle for the device. Use this to obtain the configuration
4013 * of the device instance. It's also found in pDevIns->pCfgHandle, but like
4014 * iInstance it's expected to be used a bit in this function.
4015 */
4016static DECLCALLBACK(int) pcnetConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfgHandle)
4017{
4018 PCNetState *pData = PDMINS2DATA(pDevIns, PCNetState *);
4019 PPDMIBASE pBase;
4020 char szTmp[128];
4021 int rc;
4022
4023 /* up to four instances are supported */
4024 Assert((iInstance >= 0) && (iInstance < 4));
4025
4026 Assert(RT_ELEMENTS(pData->aBCR) == BCR_MAX_RAP);
4027 Assert(RT_ELEMENTS(pData->aMII) == MII_MAX_REG);
4028 Assert(sizeof(pData->abSendBuf) == RT_ALIGN_Z(sizeof(pData->abSendBuf), 16));
4029
4030 /*
4031 * Validate configuration.
4032 */
4033 if (!CFGMR3AreValuesValid(pCfgHandle, "MAC\0CableConnected\0Am79C973\0GCEnabled\0R0Enabled\0"))
4034 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
4035 N_("Invalid configuraton for pcnet device"));
4036
4037 /*
4038 * Read the configuration.
4039 */
4040 rc = CFGMR3QueryBytes(pCfgHandle, "MAC", &pData->MacConfigured, sizeof(pData->MacConfigured));
4041 if (VBOX_FAILURE(rc))
4042 return PDMDEV_SET_ERROR(pDevIns, rc,
4043 N_("Configuration error: Failed to get the \"MAC\" value"));
4044 rc = CFGMR3QueryBool(pCfgHandle, "CableConnected", &pData->fLinkUp);
4045 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
4046 pData->fLinkUp = true;
4047 else if (VBOX_FAILURE(rc))
4048 return PDMDEV_SET_ERROR(pDevIns, rc,
4049 N_("Configuration error: Failed to get the \"CableConnected\" value"));
4050
4051 rc = CFGMR3QueryBool(pCfgHandle, "Am79C973", &pData->fAm79C973);
4052 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
4053 pData->fAm79C973 = false;
4054 else if (VBOX_FAILURE(rc))
4055 return PDMDEV_SET_ERROR(pDevIns, rc,
4056 N_("Configuration error: Failed to get the \"Am79C973\" value"));
4057
4058#ifdef PCNET_GC_ENABLED
4059 rc = CFGMR3QueryBool(pCfgHandle, "GCEnabled", &pData->fGCEnabled);
4060 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
4061 pData->fGCEnabled = true;
4062 else if (VBOX_FAILURE(rc))
4063 return PDMDEV_SET_ERROR(pDevIns, rc,
4064 N_("Configuration error: Failed to get the \"GCEnabled\" value"));
4065
4066 rc = CFGMR3QueryBool(pCfgHandle, "R0Enabled", &pData->fR0Enabled);
4067 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
4068 pData->fR0Enabled = true;
4069 else if (VBOX_FAILURE(rc))
4070 return PDMDEV_SET_ERROR(pDevIns, rc,
4071 N_("Configuration error: Failed to get the \"R0Enabled\" value"));
4072
4073#else /* !PCNET_GC_ENABLED */
4074 pData->fGCEnabled = false;
4075 pData->fR0Enabled = false;
4076#endif /* !PCNET_GC_ENABLED */
4077
4078
4079 /*
4080 * Initialize data (most of it anyway).
4081 */
4082 pData->pDevInsHC = pDevIns;
4083 pData->pDevInsGC = PDMDEVINS_2_GCPTR(pDevIns);
4084 pData->Led.u32Magic = PDMLED_MAGIC;
4085 /* IBase */
4086 pData->IBase.pfnQueryInterface = pcnetQueryInterface;
4087 /* INeworkPort */
4088 pData->INetworkPort.pfnCanReceive = pcnetCanReceive;
4089 pData->INetworkPort.pfnReceive = pcnetReceive;
4090 /* INetworkConfig */
4091 pData->INetworkConfig.pfnGetMac = pcnetGetMac;
4092 pData->INetworkConfig.pfnGetLinkState = pcnetGetLinkState;
4093 pData->INetworkConfig.pfnSetLinkState = pcnetSetLinkState;
4094 /* ILeds */
4095 pData->ILeds.pfnQueryStatusLed = pcnetQueryStatusLed;
4096
4097 /* PCI Device */
4098 pData->PciDev.config[0x00] = 0x22; /* vendor id */
4099 pData->PciDev.config[0x01] = 0x10;
4100 pData->PciDev.config[0x02] = 0x00; /* device id */
4101 pData->PciDev.config[0x03] = 0x20;
4102 pData->PciDev.config[0x04] = 0x07; /* command */
4103 pData->PciDev.config[0x05] = 0x00;
4104 pData->PciDev.config[0x06] = 0x80; /* status */
4105 pData->PciDev.config[0x07] = 0x02;
4106 pData->PciDev.config[0x08] = pData->fAm79C973 ? 0x30 : 0x10; /* revision */
4107 pData->PciDev.config[0x09] = 0x00;
4108 pData->PciDev.config[0x0a] = 0x00; /* ethernet network controller */
4109 pData->PciDev.config[0x0b] = 0x02;
4110 pData->PciDev.config[0x0e] = 0x00; /* header_type */
4111
4112 pData->PciDev.config[0x10] = 0x01; /* IO Base */
4113 pData->PciDev.config[0x11] = 0x00;
4114 pData->PciDev.config[0x12] = 0x00;
4115 pData->PciDev.config[0x13] = 0x00;
4116 pData->PciDev.config[0x14] = 0x00; /* MMIO Base */
4117 pData->PciDev.config[0x15] = 0x00;
4118 pData->PciDev.config[0x16] = 0x00;
4119 pData->PciDev.config[0x17] = 0x00;
4120
4121 /* subsystem and subvendor IDs */
4122 pData->PciDev.config[0x2c] = 0x22; /* subsystem vendor id */
4123 pData->PciDev.config[0x2d] = 0x10;
4124 pData->PciDev.config[0x2e] = 0x00; /* subsystem id */
4125 pData->PciDev.config[0x2f] = 0x20;
4126 pData->PciDev.config[0x3d] = 1; /* interrupt pin 0 */
4127 pData->PciDev.config[0x3e] = 0x06;
4128 pData->PciDev.config[0x3f] = 0xff;
4129
4130 /*
4131 * Register the PCI device, its I/O regions, the timer and the saved state item.
4132 */
4133 rc = PDMDevHlpPCIRegister(pDevIns, &pData->PciDev);
4134 if (VBOX_FAILURE(rc))
4135 return rc;
4136 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0, PCNET_IOPORT_SIZE,
4137 PCI_ADDRESS_SPACE_IO, pcnetIOPortMap);
4138 if (VBOX_FAILURE(rc))
4139 return rc;
4140 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 1, PCNET_PNPMMIO_SIZE,
4141 PCI_ADDRESS_SPACE_MEM, pcnetMMIOMap);
4142 if (VBOX_FAILURE(rc))
4143 return rc;
4144
4145#ifdef PCNET_NO_POLLING
4146 rc = PDMR3GetSymbolR0Lazy(PDMDevHlpGetVM(pDevIns), NULL, "EMInterpretInstruction", (void **)&pData->pfnEMInterpretInstructionR0);
4147 if (VBOX_SUCCESS(rc))
4148 {
4149 /*
4150 * Resolve the GC handler.
4151 */
4152 RTGCPTR pfnHandlerGC;
4153 rc = PDMR3GetSymbolGCLazy(PDMDevHlpGetVM(pDevIns), NULL, "EMInterpretInstruction", (RTGCPTR *)&pData->pfnEMInterpretInstructionGC);
4154 }
4155 if (VBOX_FAILURE(rc))
4156 {
4157 AssertMsgFailed(("PDMR3GetSymbolGCLazy -> %Vrc\n", rc));
4158 return rc;
4159 }
4160#else
4161 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, pcnetTimer,
4162 "PCNet Poll Timer", &pData->pTimerPollHC);
4163 if (VBOX_FAILURE(rc))
4164 {
4165 AssertMsgFailed(("pfnTMTimerCreate -> %Vrc\n", rc));
4166 return rc;
4167 }
4168#endif
4169 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, pcnetTimerRestore,
4170 "PCNet Restore Timer", &pData->pTimerRestore);
4171 if (VBOX_FAILURE(rc))
4172 {
4173 AssertMsgFailed(("pfnTMTimerCreate -> %Vrc\n", rc));
4174 return rc;
4175 }
4176/** @todo r=bird: we're not locking down pcnet properly during saving and loading! */
4177 rc = PDMDevHlpSSMRegister(pDevIns, pDevIns->pDevReg->szDeviceName, iInstance,
4178 PCNET_SAVEDSTATE_VERSION, sizeof(*pData),
4179 NULL, pcnetSaveExec, NULL,
4180 NULL, pcnetLoadExec, NULL);
4181 if (VBOX_FAILURE(rc))
4182 return rc;
4183
4184 /*
4185 * Initialize critical section.
4186 * This must of course be done before attaching drivers or anything else which can call us back..
4187 */
4188 char szName[24];
4189 RTStrPrintf(szName, sizeof(szName), "PCNet#%d", iInstance);
4190 rc = PDMDevHlpCritSectInit(pDevIns, &pData->CritSect, szName);
4191 if (VBOX_FAILURE(rc))
4192 return rc;
4193
4194 /*
4195 * Create the transmit queue.
4196 */
4197 rc = PDMDevHlpPDMQueueCreate(pDevIns, sizeof(PDMQUEUEITEMCORE), 1, 0,
4198 pcnetXmitQueueConsumer, true, &pData->pXmitQueueHC);
4199 if (VBOX_FAILURE(rc))
4200 return rc;
4201 pData->pXmitQueueGC = PDMQueueGCPtr(pData->pXmitQueueHC);
4202
4203 /*
4204 * Create the RX notifer signaller.
4205 */
4206 rc = PDMDevHlpPDMQueueCreate(pDevIns, sizeof(PDMQUEUEITEMCORE), 1, 0,
4207 pcnetCanRxQueueConsumer, true, &pData->pCanRxQueueHC);
4208 if (VBOX_FAILURE(rc))
4209 return rc;
4210 pData->pCanRxQueueGC = PDMQueueGCPtr(pData->pCanRxQueueHC);
4211
4212 /*
4213 * Register the info item.
4214 */
4215 RTStrPrintf(szTmp, sizeof(szTmp), "pcnet%d", pDevIns->iInstance);
4216 PDMDevHlpDBGFInfoRegister(pDevIns, szTmp, "PCNET info.", pcnetInfo);
4217
4218 /*
4219 * Attach status driver (optional).
4220 */
4221 rc = PDMDevHlpDriverAttach(pDevIns, PDM_STATUS_LUN, &pData->IBase, &pBase, "Status Port");
4222 if (VBOX_SUCCESS(rc))
4223 pData->pLedsConnector = (PPDMILEDCONNECTORS)
4224 pBase->pfnQueryInterface(pBase, PDMINTERFACE_LED_CONNECTORS);
4225 else if (rc != VERR_PDM_NO_ATTACHED_DRIVER)
4226 {
4227 AssertMsgFailed(("Failed to attach to status driver. rc=%Vrc\n", rc));
4228 return rc;
4229 }
4230
4231 /*
4232 * Attach driver.
4233 */
4234 rc = PDMDevHlpDriverAttach(pDevIns, 0, &pData->IBase, &pData->pDrvBase, "Network Port");
4235 if (VBOX_SUCCESS(rc))
4236 {
4237 pData->pDrv = (PPDMINETWORKCONNECTOR)
4238 pData->pDrvBase->pfnQueryInterface(pData->pDrvBase, PDMINTERFACE_NETWORK_CONNECTOR);
4239 if (!pData->pDrv)
4240 {
4241 AssertMsgFailed(("Failed to obtain the PDMINTERFACE_NETWORK_CONNECTOR interface!\n"));
4242 return VERR_PDM_MISSING_INTERFACE_BELOW;
4243 }
4244 }
4245 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
4246 Log(("No attached driver!\n"));
4247 else
4248 return rc;
4249
4250 /*
4251 * Reset the device state. (Do after attaching.)
4252 */
4253 pcnetHardReset(pData);
4254
4255 /* Create send queue for the async send thread. */
4256 rc = RTSemEventCreate(&pData->hSendEventSem);
4257 AssertRC(rc);
4258
4259 /* Create asynchronous thread */
4260 rc = RTThreadCreate(&pData->hSendThread, pcnetAsyncSend, (void *)pData, 128*1024, RTTHREADTYPE_IO, 0, "PCNET_SEND");
4261 AssertRC(rc);
4262
4263#ifdef VBOX_WITH_STATISTICS
4264 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatMMIOReadGC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling MMIO reads in GC", "/Devices/PCNet%d/MMIO/ReadGC", iInstance);
4265 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatMMIOReadHC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling MMIO reads in HC", "/Devices/PCNet%d/MMIO/ReadHC", iInstance);
4266 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatMMIOWriteGC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling MMIO writes in GC", "/Devices/PCNet%d/MMIO/WriteGC", iInstance);
4267 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatMMIOWriteHC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling MMIO writes in HC", "/Devices/PCNet%d/MMIO/WriteHC", iInstance);
4268 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatAPROMRead, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling APROM reads", "/Devices/PCNet%d/IO/APROMRead", iInstance);
4269 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatAPROMWrite, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling APROM writes", "/Devices/PCNet%d/IO/APROMWrite", iInstance);
4270 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatIOReadGC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling PCNetIO reads in GC", "/Devices/PCNet%d/IO/ReadGC", iInstance);
4271 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatIOReadHC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling PCNetIO reads in HC", "/Devices/PCNet%d/IO/ReadHC", iInstance);
4272 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatIOWriteGC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling PCNet IO writes in GC", "/Devices/PCNet%d/IO/WriteGC", iInstance);
4273 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatIOWriteHC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling PCNet IO writes in HC", "/Devices/PCNet%d/IO/WriteHC", iInstance);
4274 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatTimer, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling PCNet Timer", "/Devices/PCNet%d/Timer", iInstance);
4275 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatReceive, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling PCNet receive", "/Devices/PCNet%d/Receive", iInstance);
4276 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatTransmit, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling PCNet transmit in HC", "/Devices/PCNet%d/Transmit/Total", iInstance);
4277 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatTransmitSend, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling PCNet send transmit in HC", "/Devices/PCNet%d/Transmit/Send", iInstance);
4278 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatTdtePollGC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling PCNet TdtePoll in GC", "/Devices/PCNet%d/TdtePollGC", iInstance);
4279 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatTdtePollHC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling PCNet TdtePoll in HC", "/Devices/PCNet%d/TdtePollHC", iInstance);
4280 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatRdtePollGC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling PCNet RdtePoll in GC", "/Devices/PCNet%d/RdtePollGC", iInstance);
4281 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatRdtePollHC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling PCNet RdtePoll in HC", "/Devices/PCNet%d/RdtePollHC", iInstance);
4282
4283 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatTmdStoreGC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling PCNet TmdStore in GC", "/Devices/PCNet%d/TmdStoreGC", iInstance);
4284 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatTmdStoreHC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling PCNet TmdStore in HC", "/Devices/PCNet%d/TmdStoreHC", iInstance);
4285
4286 unsigned i;
4287 for (i = 0; i < ELEMENTS(pData->aStatXmitFlush) - 1; i++)
4288 PDMDevHlpSTAMRegisterF(pDevIns, &pData->aStatXmitFlush[i], STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES, "", "/Devices/PCNet%d/XmitFlushIrq/%d", iInstance, i + 1);
4289 PDMDevHlpSTAMRegisterF(pDevIns, &pData->aStatXmitFlush[i], STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES, "", "/Devices/PCNet%d/XmitFlushIrq/%d+", iInstance, i + 1);
4290
4291 for (i = 0; i < ELEMENTS(pData->aStatXmitChainCounts) - 1; i++)
4292 PDMDevHlpSTAMRegisterF(pDevIns, &pData->aStatXmitChainCounts[i], STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES, "", "/Devices/PCNet%d/XmitChainCounts/%d", iInstance, i + 1);
4293 PDMDevHlpSTAMRegisterF(pDevIns, &pData->aStatXmitChainCounts[i], STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES, "", "/Devices/PCNet%d/XmitChainCounts/%d+", iInstance, i + 1);
4294
4295 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatXmitSkipCurrent, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "", "/Devices/PCNet%d/Xmit/Skipped", iInstance, i + 1);
4296
4297 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatInterrupt, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling PCNet interrupt checks", "/Devices/PCNet%d/Interrupt", iInstance);
4298 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatPollTimer, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling PCNet poll timer", "/Devices/PCNet%d/PollTimer", iInstance);
4299 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatMIIReads, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of MII reads", "/Devices/PCNet%d/MIIReads", iInstance);
4300# ifdef PCNET_NO_POLLING
4301 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatRCVRingWrite, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of receive ring writes", "/Devices/PCNet%d/Ring/RCVWrites", iInstance);
4302 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatTXRingWrite, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of transmit ring writes", "/Devices/PCNet%d/Ring/TXWrites", iInstance);
4303 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatRingWriteHC, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of monitored ring page writes", "/Devices/PCNet%d/Ring/HC/Writes", iInstance);
4304 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatRingWriteR0, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of monitored ring page writes", "/Devices/PCNet%d/Ring/R0/Writes", iInstance);
4305 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatRingWriteGC, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of monitored ring page writes", "/Devices/PCNet%d/Ring/GC/Writes", iInstance);
4306 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatRingWriteFailedHC, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of failed ring page writes", "/Devices/PCNet%d/Ring/HC/Failed", iInstance);
4307 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatRingWriteFailedR0, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of failed ring page writes", "/Devices/PCNet%d/Ring/R0/Failed", iInstance);
4308 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatRingWriteFailedGC, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of failed ring page writes", "/Devices/PCNet%d/Ring/GC/Failed", iInstance);
4309 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatRingWriteOutsideRangeHC, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of monitored writes outside ring range", "/Devices/PCNet%d/Ring/HC/Outside", iInstance);
4310 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatRingWriteOutsideRangeR0, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of monitored writes outside ring range", "/Devices/PCNet%d/Ring/R0/Outside", iInstance);
4311 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatRingWriteOutsideRangeGC, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of monitored writes outside ring range", "/Devices/PCNet%d/Ring/GC/Outside", iInstance);
4312# endif /* PCNET_NO_POLLING */
4313#endif
4314
4315 return VINF_SUCCESS;
4316}
4317
4318
4319/**
4320 * The device registration structure.
4321 */
4322const PDMDEVREG g_DevicePCNet =
4323{
4324 /* u32Version */
4325 PDM_DEVREG_VERSION,
4326 /* szDeviceName */
4327 "pcnet",
4328 /* szGCMod */
4329#ifdef PCNET_GC_ENABLED
4330 "VBoxDDGC.gc",
4331 "VBoxDDR0.r0",
4332#else
4333 "",
4334 "",
4335#endif
4336 /* pszDescription */
4337 "AMD PC-Net II Ethernet controller.\n",
4338 /* fFlags */
4339#ifdef PCNET_GC_ENABLED
4340 PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GC | PDM_DEVREG_FLAGS_R0,
4341#else
4342 PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_DEFAULT,
4343#endif
4344 /* fClass */
4345 PDM_DEVREG_CLASS_NETWORK,
4346 /* cMaxInstances */
4347 4,
4348 /* cbInstance */
4349 sizeof(PCNetState),
4350 /* pfnConstruct */
4351 pcnetConstruct,
4352 /* pfnDestruct */
4353 pcnetDestruct,
4354 /* pfnRelocate */
4355 pcnetRelocate,
4356 /* pfnIOCtl */
4357 NULL,
4358 /* pfnPowerOn */
4359 NULL,
4360 /* pfnReset */
4361 pcnetReset,
4362 /* pfnSuspend */
4363 NULL,
4364 /* pfnResume */
4365 NULL,
4366 /* pfnAttach */
4367 NULL,
4368 /* pfnDetach */
4369 NULL,
4370 /* pfnQueryInterface. */
4371 NULL
4372};
4373
4374#endif /* IN_RING3 */
4375#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
4376
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