VirtualBox

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

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

introduced PDMDevHlpGetVM()

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

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