VirtualBox

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

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

Enabled delayed transmit interrupts + added async sending of packets (disabled)

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