VirtualBox

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

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

Some async updates

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette