VirtualBox

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

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

Updated no polling code path.

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