VirtualBox

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

Last change on this file since 95 was 1, checked in by vboxsync, 55 years ago

import

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

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