VirtualBox

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

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

Completed physical monitoring of ring descriptor table. (disabled)
Currently in an experimental stage, so don't complain.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 157.4 KB
Line 
1/** @file
2 *
3 * VBox network devices:
4 * AMD PC-Net II (Am79C970A + Am79C973) Ethernet Controller
5 */
6
7/*
8 * Copyright (C) 2006 InnoTek Systemberatung GmbH
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License as published by the Free Software Foundation,
14 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
15 * distribution. VirtualBox OSE is distributed in the hope that it will
16 * be useful, but WITHOUT ANY WARRANTY of any kind.
17 *
18 * If you received this file as part of a commercial VirtualBox
19 * distribution, then only the terms of your commercial VirtualBox
20 * license agreement apply instead of the previous paragraph.
21 *
22 * --------------------------------------------------------------------
23 *
24 * This code is based on:
25 *
26 * AMD PC-Net II (Am79C970A) emulation
27 *
28 * Copyright (c) 2004 Antony T Curtis
29 *
30 * Permission is hereby granted, free of charge, to any person obtaining a copy
31 * of this software and associated documentation files (the "Software"), to deal
32 * in the Software without restriction, including without limitation the rights
33 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
34 * copies of the Software, and to permit persons to whom the Software is
35 * furnished to do so, subject to the following conditions:
36 *
37 * The above copyright notice and this permission notice shall be included in
38 * all copies or substantial portions of the Software.
39 *
40 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
41 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
42 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
43 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
44 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
45 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
46 * THE SOFTWARE.
47 */
48
49/* This software was written to be compatible with the specification:
50 * AMD Am79C970A PCnet-PCI II Ethernet Controller Data-Sheet
51 * AMD Publication# 19436 Rev:E Amendment/0 Issue Date: June 2000
52 */
53
54/*******************************************************************************
55* Header Files *
56*******************************************************************************/
57#define LOG_GROUP LOG_GROUP_DEV_PCNET
58#include <VBox/err.h>
59#include <VBox/log.h>
60#include <VBox/mm.h>
61#include <VBox/pdm.h>
62#include <VBox/pgm.h>
63#include <VBox/stam.h>
64#include <iprt/asm.h>
65#include <iprt/assert.h>
66#include <iprt/critsect.h>
67#include <iprt/string.h>
68#include <iprt/time.h>
69
70#include "Builtins.h"
71#include "vl_vbox.h"
72
73/* Enable this to catch writes to the ring descriptors instead of using excessive polling */
74/* #define PCNET_NO_POLLING */
75
76/* Enable to handle frequent io reads in the guest context */
77#define PCNET_GC_ENABLED
78
79#ifdef __GNUC__
80#define PACKED __attribute__ ((packed))
81#else
82#define PACKED
83#endif
84
85#if 0
86#define LOG_REGISTER(a) LogRel(a)
87#else
88#define LOG_REGISTER(a)
89#endif
90#if 0
91#define LOG_PACKET(name, buf, count) LogPkt(name, buf, count)
92#define LOG_PACKETS
93#else
94#define LOG_PACKET(name, buf, count)
95#undef LOG_PACKETS
96#endif
97
98#if defined(LOG_ENABLED)
99#define PCNET_DEBUG_IO
100#define PCNET_DEBUG_BCR
101#define PCNET_DEBUG_CSR
102#define PCNET_DEBUG_RMD
103#define PCNET_DEBUG_TMD
104#define PCNET_DEBUG_MATCH
105#define PCNET_DEBUG_MII
106#endif
107
108#define PCNET_IOPORT_SIZE 0x20
109#define PCNET_PNPMMIO_SIZE 0x20
110
111#define PCNET_SAVEDSTATE_VERSION 4
112
113#define BCR_MAX_RAP 50
114#define MII_MAX_REG 32
115#define CSR_MAX_REG 128
116
117typedef struct PCNetState_st PCNetState;
118
119struct PCNetState_st
120{
121 PCIDEVICE PciDev;
122#ifndef PCNET_NO_POLLING
123 /** Poll timer (address for host context) */
124 PTMTIMERHC pTimerPollHC;
125 /** Poll timer (address for guest context) */
126 PTMTIMERGC pTimerPollGC;
127#endif
128 /** Register Address Pointer */
129 uint32_t u32RAP;
130 /** Internal interrupt service */
131 int32_t iISR;
132 /** ??? */
133 uint32_t u32Lnkst;
134 /** Address of the RX descriptor table (ring). Loaded at init. */
135 RTGCPHYS GCRDRA;
136 /** Address of the TX descriptor table (ring). Loaded at init. */
137 RTGCPHYS GCTDRA;
138 uint8_t aPROM[16];
139 uint16_t aCSR[CSR_MAX_REG];
140 uint16_t aBCR[BCR_MAX_RAP];
141 uint16_t aMII[MII_MAX_REG];
142 uint16_t u16CSR0LastSeenByGuest; /** @todo SSM!! */
143 /** 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
996 PDMCritSectLeave(&pData->CritSect);
997 return VINF_SUCCESS;
998 }
999 }
1000 else
1001 {
1002 STAM_COUNTER_INC(&CTXALLSUFF(pData->StatRingWriteOutsideRange)); ;
1003 return VINF_SUCCESS; /* outside of the ring range */
1004 }
1005 }
1006 STAM_COUNTER_INC(&CTXALLSUFF(pData->StatRingWriteFailed)); ;
1007 return VINF_IOM_HC_MMIO_WRITE; /* handle in ring3 */
1008}
1009
1010# else /* IN_RING3 */
1011
1012/**
1013 * #PF Handler callback for physical access handler ranges (MMIO among others) in HC.
1014 *
1015 * The handler can not raise any faults, it's mainly for monitoring write access
1016 * to certain pages.
1017 *
1018 * @returns VINF_SUCCESS if the handler have carried out the operation.
1019 * @returns VINF_PGM_HANDLER_DO_DEFAULT if the caller should carry out the access operation.
1020 * @param pVM VM Handle.
1021 * @param GCPhys The physical address the guest is writing to.
1022 * @param pvPhys The HC mapping of that address.
1023 * @param pvBuf What the guest is reading/writing.
1024 * @param cbBuf How much it's reading/writing.
1025 * @param enmAccessType The access type.
1026 * @param pvUser User argument.
1027 */
1028static DECLCALLBACK(int) pcnetHandleRingWrite(PVM pVM, RTGCPHYS GCPhys, void *pvPhys, void *pvBuf,
1029 size_t cbBuf, PGMACCESSTYPE enmAccessType, void *pvUser)
1030{
1031 PPDMDEVINS pDevIns = (PPDMDEVINS)pvUser;
1032 PCNetState *pData = PDMINS2DATA(pDevIns, PCNetState *);
1033
1034 Log(("#%d pcnetHandleRingWrite: write to %08x\n", PCNETSTATE_2_DEVINS(pData)->iInstance, GCPhys));
1035#ifdef VBOX_WITH_STATISTICS
1036 STAM_COUNTER_INC(&CTXSUFF(pData->StatRingWrite));
1037 if (GCPhys >= pData->GCRDRA && GCPhys < pcnetRdraAddr(pData, 0))
1038 STAM_COUNTER_INC(&pData->StatRCVRingWrite);
1039 else if (GCPhys >= pData->GCTDRA && GCPhys < pcnetTdraAddr(pData, 0))
1040 STAM_COUNTER_INC(&pData->StatTXRingWrite);
1041#endif
1042 /* Perform the actual write */
1043 memcpy((char *)pvPhys, pvBuf, cbBuf);
1044
1045 /* Writes done by our code don't require polling of course */
1046 if (PDMCritSectIsOwner(&pData->CritSect) == false)
1047 {
1048 int rc = PDMCritSectEnter(&pData->CritSect, VERR_SEM_BUSY);
1049 AssertReleaseRC(rc);
1050 /* Check if we can do something now */
1051 pcnetPollRxTx(pData);
1052 pcnetUpdateIrq(pData);
1053 PDMCritSectLeave(&pData->CritSect);
1054 }
1055 return VINF_SUCCESS;
1056}
1057# endif /* !IN_RING3 */
1058#endif /* PCNET_NO_POLLING */
1059
1060static void pcnetSoftReset(PCNetState *pData)
1061{
1062 Log(("#%d pcnetSoftReset:\n", PCNETSTATE_2_DEVINS(pData)->iInstance));
1063
1064 pData->u32Lnkst = 0x40;
1065 pData->GCRDRA = 0;
1066 pData->GCTDRA = 0;
1067 pData->u32RAP = 0;
1068
1069 pData->aBCR[BCR_BSBC] &= ~0x0080;
1070
1071 pData->aCSR[0] = 0x0004;
1072 pData->aCSR[3] = 0x0000;
1073 pData->aCSR[4] = 0x0115;
1074 pData->aCSR[5] = 0x0000;
1075 pData->aCSR[6] = 0x0000;
1076 pData->aCSR[8] = 0;
1077 pData->aCSR[9] = 0;
1078 pData->aCSR[10] = 0;
1079 pData->aCSR[11] = 0;
1080 pData->aCSR[12] = le16_to_cpu(((uint16_t *)&pData->aPROM[0])[0]);
1081 pData->aCSR[13] = le16_to_cpu(((uint16_t *)&pData->aPROM[0])[1]);
1082 pData->aCSR[14] = le16_to_cpu(((uint16_t *)&pData->aPROM[0])[2]);
1083 pData->aCSR[15] &= 0x21c4;
1084 CSR_RCVRC(pData) = 1;
1085 CSR_XMTRC(pData) = 1;
1086 CSR_RCVRL(pData) = 1;
1087 CSR_XMTRL(pData) = 1;
1088 pData->aCSR[80] = 0x1410;
1089 pData->aCSR[88] = pData->fAm79C973 ? CSR_VERSION_LOW_79C973 : CSR_VERSION_LOW_79C970A;
1090 pData->aCSR[89] = CSR_VERSION_HIGH;
1091 pData->aCSR[94] = 0x0000;
1092 pData->aCSR[100] = 0x0200;
1093 pData->aCSR[103] = 0x0105;
1094 pData->aCSR[103] = 0x0105;
1095 CSR_MISSC(pData) = 0;
1096 pData->aCSR[114] = 0x0000;
1097 pData->aCSR[122] = 0x0000;
1098 pData->aCSR[124] = 0x0000;
1099}
1100
1101/**
1102 * Check if we have to send an interrupt to the guest. An interrupt can occur on
1103 * - csr0 (written quite often)
1104 * - csr4 (only written by pcnetSoftReset(), pcnetStop() or by the guest driver)
1105 * - csr5 (only written by pcnetSoftReset(), pcnetStop or by the driver guest)
1106 */
1107static void pcnetUpdateIrq(PCNetState *pData)
1108{
1109 register int iISR = 0;
1110 register uint16_t csr0 = pData->aCSR[0];
1111
1112 csr0 &= ~0x0080; /* clear INTR */
1113
1114 STAM_PROFILE_ADV_START(&pData->StatInterrupt, a);
1115
1116 /* Linux guests set csr4=0x0915
1117 * W2k guests set csr3=0x4940 (disable BABL, MERR, IDON, DXSUFLO */
1118
1119#if 1
1120 if ( ( (csr0 & ~pData->aCSR[3]) & 0x5f00)
1121 || (((pData->aCSR[4]>>1) & ~pData->aCSR[4]) & 0x0115)
1122 || (((pData->aCSR[5]>>1) & pData->aCSR[5]) & 0x0048))
1123#else
1124 if ( ( !(pData->aCSR[3] & 0x4000) && !!(csr0 & 0x4000)) /* BABL */
1125 ||( !(pData->aCSR[3] & 0x1000) && !!(csr0 & 0x1000)) /* MISS */
1126 ||( !(pData->aCSR[3] & 0x0100) && !!(csr0 & 0x0100)) /* IDON */
1127 ||( !(pData->aCSR[3] & 0x0200) && !!(csr0 & 0x0200)) /* TINT */
1128 ||( !(pData->aCSR[3] & 0x0400) && !!(csr0 & 0x0400)) /* RINT */
1129 ||( !(pData->aCSR[3] & 0x0800) && !!(csr0 & 0x0800)) /* MERR */
1130 ||( !(pData->aCSR[4] & 0x0001) && !!(pData->aCSR[4] & 0x0002)) /* JAB */
1131 ||( !(pData->aCSR[4] & 0x0004) && !!(pData->aCSR[4] & 0x0008)) /* TXSTRT */
1132 ||( !(pData->aCSR[4] & 0x0010) && !!(pData->aCSR[4] & 0x0020)) /* RCVO */
1133 ||( !(pData->aCSR[4] & 0x0100) && !!(pData->aCSR[4] & 0x0200)) /* MFCO */
1134 ||(!!(pData->aCSR[5] & 0x0040) && !!(pData->aCSR[5] & 0x0080)) /* EXDINT */
1135 ||(!!(pData->aCSR[5] & 0x0008) && !!(pData->aCSR[5] & 0x0010)) /* MPINT */)
1136#endif
1137 {
1138 iISR = !!(csr0 & 0x0040); /* CSR_INEA */
1139 csr0 |= 0x0080; /* set INTR */
1140 }
1141
1142#ifdef VBOX
1143 if (pData->aCSR[4] & 0x0080) /* UINTCMD */
1144 {
1145 pData->aCSR[4] &= ~0x0080; /* clear UINTCMD */
1146 pData->aCSR[4] |= 0x0040; /* set UINT */
1147 Log(("#%d user int\n", PCNETSTATE_2_DEVINS(pData)->iInstance));
1148 }
1149 if (pData->aCSR[4] & csr0 & 0x0040 /* CSR_INEA */)
1150 {
1151 csr0 |= 0x0080; /* set INTR */
1152 iISR = 1;
1153 }
1154#else /* !VBOX */
1155 if (!!(pData->aCSR[4] & 0x0080) && CSR_INEA(pData)) /* UINTCMD */
1156 {
1157 pData->aCSR[4] &= ~0x0080;
1158 pData->aCSR[4] |= 0x0040; /* set UINT */
1159 csr0 |= 0x0080; /* set INTR */
1160 iISR = 1;
1161 Log(("#%d user int\n", PCNETSTATE_2_DEVINS(pData)->iInstance));
1162 }
1163#endif /* !VBOX */
1164
1165#if 1
1166 if (((pData->aCSR[5]>>1) & pData->aCSR[5]) & 0x0500)
1167#else
1168 if ( (!!(pData->aCSR[5] & 0x0400) && !!(pData->aCSR[5] & 0x0800)) /* SINT */
1169 ||(!!(pData->aCSR[5] & 0x0100) && !!(pData->aCSR[5] & 0x0200)) /* SLPINT */)
1170#endif
1171 {
1172 iISR = 1;
1173 csr0 |= 0x0080; /* INTR */
1174 }
1175
1176 pData->aCSR[0] = csr0;
1177
1178 Log2(("#%d set irq iISR=%d\n", PCNETSTATE_2_DEVINS(pData)->iInstance, iISR));
1179
1180 /* normal path is to _not_ change the IRQ status */
1181 if (RT_UNLIKELY(iISR != pData->iISR))
1182 {
1183 Log(("#%d INTA=%d\n", PCNETSTATE_2_DEVINS(pData)->iInstance, iISR));
1184 PDMDevHlpPCISetIrqNoWait(PCNETSTATE_2_DEVINS(pData), 0, iISR);
1185 pData->iISR = iISR;
1186 }
1187 STAM_PROFILE_ADV_STOP(&pData->StatInterrupt, a);
1188}
1189
1190#ifdef IN_RING3
1191#ifdef PCNET_NO_POLLING
1192static void pcnetUpdateRingHandlers(PCNetState *pData)
1193{
1194 PPDMDEVINS pDevIns = PCNETSTATE_2_DEVINS(pData);
1195
1196 Log(("pcnetUpdateRingHandlers TD %VGp size %x -> %VGp size %x\n", pData->TRDAPhysOld, pData->cbTRDAOld, pData->GCTDRA, pcnetTdraAddr(pData, 0)));
1197 Log(("pcnetUpdateRingHandlers RX %VGp size %x -> %VGp size %x\n", pData->RDRAPhysOld, pData->cbRDRAOld, pData->GCRDRA, pcnetRdraAddr(pData, 0)));
1198
1199#if 0
1200 if (pData->RDRAPhysOld != 0 && pData->GCRDRA != pData->RDRAPhysOld)
1201 PGMHandlerPhysicalDeregister(pDevIns->pDevHlp->pfnGetVM(pDevIns),
1202 pData->RDRAPhysOld & ~PAGE_OFFSET_MASK);
1203 if ( pData->TRDAPhysOld != 0 && pData->GCTDRA != pData->TRDAPhysOld
1204 && (pData->GCRDRA & ~PAGE_OFFSET_MASK) != (pData->GCTDRA & ~PAGE_OFFSET_MASK))
1205#endif
1206#if 0
1207 if (pData->GCRDRA != oldrdra)
1208 {
1209 int rc;
1210 rc = PGMR3HandlerPhysicalRegister(pDevIns->pDevHlp->pfnGetVM(pDevIns),
1211 PGMPHYSHANDLERTYPE_PHYSICAL_WRITE,
1212 pData->GCRDRA & ~PAGE_OFFSET_MASK,
1213 RT_ALIGN(pcnetRdraAddr(pData, 0), PAGE_SIZE) - 1,
1214 pcnetHandleRingWrite, pDevIns,
1215 g_DevicePCNet.szR0Mod, "pcnetHandleRingWrite",
1216 pData->pDevInsHC->pvInstanceDataHC,
1217 g_DevicePCNet.szGCMod, "pcnetHandleRingWrite",
1218 pData->pDevInsHC->pvInstanceDataGC,
1219 "PCNet receive ring write access handler");
1220 AssertRC(rc);
1221
1222 pData->RDRAPhysOld = pData->GCRDRA;
1223 pData->cbRDRAOld = pcnetRdraAddr(pData, 0);
1224 }
1225#endif
1226 if (pData->GCTDRA != pData->TRDAPhysOld || CSR_XMTRL(pData) != pData->cbTRDAOld)
1227 {
1228 if (pData->TRDAPhysOld != 0)
1229 PGMHandlerPhysicalDeregister(pDevIns->pDevHlp->pfnGetVM(pDevIns),
1230 pData->TRDAPhysOld & ~PAGE_OFFSET_MASK);
1231
1232 int rc;
1233
1234 rc = PGMR3HandlerPhysicalRegister(pDevIns->pDevHlp->pfnGetVM(pDevIns),
1235 PGMPHYSHANDLERTYPE_PHYSICAL_WRITE,
1236 pData->GCTDRA & ~PAGE_OFFSET_MASK,
1237 RT_ALIGN(pcnetTdraAddr(pData, 0), PAGE_SIZE) - 1,
1238 pcnetHandleRingWrite, pDevIns,
1239 g_DevicePCNet.szR0Mod, "pcnetHandleRingWrite",
1240 pData->pDevInsHC->pvInstanceDataHC,
1241 g_DevicePCNet.szGCMod, "pcnetHandleRingWrite",
1242 pData->pDevInsHC->pvInstanceDataGC,
1243 "PCNet transmit ring write access handler");
1244 AssertRC(rc);
1245
1246 pData->TRDAPhysOld = pData->GCTDRA;
1247 pData->cbTRDAOld = pcnetTdraAddr(pData, 0);
1248 }
1249}
1250#endif /* PCNET_NO_POLLING */
1251
1252static void pcnetInit(PCNetState *pData)
1253{
1254 PPDMDEVINS pDevIns = PCNETSTATE_2_DEVINS(pData);
1255 Log(("#%d pcnetInit: init_addr=0x%08x\n", PCNETSTATE_2_DEVINS(pData)->iInstance,
1256 PHYSADDR(pData, CSR_IADR(pData))));
1257
1258 /** @todo Documentation says that RCVRL and XMTRL are stored as two's complement!
1259 * Software is allowed to write these registers directly. */
1260#define PCNET_INIT() do { \
1261 PDMDevHlpPhysRead(pDevIns, PHYSADDR(pData, CSR_IADR(pData)), \
1262 (uint8_t *)&initblk, sizeof(initblk)); \
1263 pData->aCSR[15] = le16_to_cpu(initblk.mode); \
1264 CSR_RCVRL(pData) = (initblk.rlen < 9) ? (1 << initblk.rlen) : 512; \
1265 CSR_XMTRL(pData) = (initblk.tlen < 9) ? (1 << initblk.tlen) : 512; \
1266 pData->aCSR[ 6] = (initblk.tlen << 12) | (initblk.rlen << 8); \
1267 pData->aCSR[ 8] = le16_to_cpu(initblk.ladrf1); \
1268 pData->aCSR[ 9] = le16_to_cpu(initblk.ladrf2); \
1269 pData->aCSR[10] = le16_to_cpu(initblk.ladrf3); \
1270 pData->aCSR[11] = le16_to_cpu(initblk.ladrf4); \
1271 pData->aCSR[12] = le16_to_cpu(initblk.padr1); \
1272 pData->aCSR[13] = le16_to_cpu(initblk.padr2); \
1273 pData->aCSR[14] = le16_to_cpu(initblk.padr3); \
1274 pData->GCRDRA = PHYSADDR(pData, initblk.rdra); \
1275 pData->GCTDRA = PHYSADDR(pData, initblk.tdra); \
1276} while (0)
1277
1278 if (BCR_SSIZE32(pData))
1279 {
1280 struct INITBLK32 initblk;
1281 pData->GCUpperPhys = 0;
1282 PCNET_INIT();
1283 Log(("#%d initblk.rlen=0x%02x, initblk.tlen=0x%02x\n",
1284 PCNETSTATE_2_DEVINS(pData)->iInstance, initblk.rlen, initblk.tlen));
1285 }
1286 else
1287 {
1288 struct INITBLK16 initblk;
1289 pData->GCUpperPhys = (0xff00 & (uint32_t)pData->aCSR[2]) << 16;
1290 PCNET_INIT();
1291 Log(("#%d initblk.rlen=0x%02x, initblk.tlen=0x%02x\n",
1292 PCNETSTATE_2_DEVINS(pData)->iInstance, initblk.rlen, initblk.tlen));
1293 }
1294
1295#undef PCNET_INIT
1296
1297 if (pData->pDrv)
1298 pData->pDrv->pfnSetPromiscuousMode(pData->pDrv, CSR_PROM(pData));
1299
1300 CSR_RCVRC(pData) = CSR_RCVRL(pData);
1301 CSR_XMTRC(pData) = CSR_XMTRL(pData);
1302
1303#ifdef PCNET_NO_POLLING
1304 pcnetUpdateRingHandlers(pData);
1305#endif
1306
1307 /* Reset cached RX and TX states */
1308 CSR_CRST(pData) = CSR_CRBC(pData) = CSR_NRST(pData) = CSR_NRBC(pData) = 0;
1309 CSR_CXST(pData) = CSR_CXBC(pData) = CSR_NXST(pData) = CSR_NXBC(pData) = 0;
1310
1311 LogRel(("PCNet#%d: Init: ss32=%d GCRDRA=0x%08x[%d] GCTDRA=0x%08x[%d]\n",
1312 PCNETSTATE_2_DEVINS(pData)->iInstance, BCR_SSIZE32(pData),
1313 pData->GCRDRA, CSR_RCVRL(pData), pData->GCTDRA, CSR_XMTRL(pData)));
1314
1315 pData->aCSR[0] |= 0x0101; /* Initialization done */
1316 pData->aCSR[0] &= ~0x0004; /* clear STOP bit */
1317}
1318#endif /* IN_RING3 */
1319
1320/**
1321 * Start RX/TX operation.
1322 */
1323static void pcnetStart(PCNetState *pData)
1324{
1325 Log(("%#d pcnetStart:\n", PCNETSTATE_2_DEVINS(pData)->iInstance));
1326 if (!CSR_DTX(pData))
1327 pData->aCSR[0] |= 0x0010; /* set TXON */
1328 if (!CSR_DRX(pData))
1329 pData->aCSR[0] |= 0x0020; /* set RXON */
1330 pData->aCSR[0] &= ~0x0004; /* clear STOP bit */
1331 pData->aCSR[0] |= 0x0002; /* STRT */
1332}
1333
1334/**
1335 * Stop RX/TX operation.
1336 */
1337static void pcnetStop(PCNetState *pData)
1338{
1339 Log(("#%d pcnetStop:\n", PCNETSTATE_2_DEVINS(pData)->iInstance));
1340 pData->aCSR[0] &= ~0x7feb;
1341 pData->aCSR[0] |= 0x0014;
1342 pData->aCSR[4] &= ~0x02c2;
1343 pData->aCSR[5] &= ~0x0011;
1344 pcnetPollTimer(pData);
1345}
1346
1347#ifdef IN_RING3
1348static DECLCALLBACK(bool) pcnetCanRxQueueConsumer(PPDMDEVINS pDevIns, PPDMQUEUEITEMCORE pItem)
1349{
1350 PCNetState *pData = PDMINS2DATA(pDevIns, PCNetState *);
1351 pData->pDrv->pfnNotifyCanReceive(pData->pDrv);
1352 return true;
1353}
1354#endif
1355
1356/**
1357 * Poll Receive Descriptor Table Entry and cache the results in the appropriate registers.
1358 * Note: Once a descriptor belongs to the network card (this driver), it cannot be changed
1359 * by the host (the guest driver) anymore. Well, it could but the results are undefined by
1360 * definition.
1361 * @param fSkipCurrent if true, don't scan the current RDTE.
1362 */
1363static void pcnetRdtePoll(PCNetState *pData, bool fSkipCurrent=false)
1364{
1365 /* assume lack of a next receive descriptor */
1366 CSR_NRST(pData) = 0;
1367
1368 if (RT_LIKELY(pData->GCRDRA))
1369 {
1370 /*
1371 * The current receive message descriptor.
1372 */
1373 RMD rmd;
1374 int i = CSR_RCVRC(pData);
1375 RTGCPHYS addr;
1376
1377 if (i < 1)
1378 i = CSR_RCVRL(pData);
1379
1380 if (!fSkipCurrent)
1381 {
1382 addr = pcnetRdraAddr(pData, i);
1383 pcnetRmdLoad(pData, &rmd, PHYSADDR(pData, addr));
1384 CSR_CRDA(pData) = CSR_CRBA(pData) = 0;
1385 CSR_CRBC(pData) = CSR_CRST(pData) = 0;
1386 if (!rmd.rmd1.own)
1387 return;
1388 if (RT_LIKELY(!IS_RMD_BAD(rmd)))
1389 {
1390 CSR_CRDA(pData) = addr; /* Receive Descriptor Address */
1391 CSR_CRBA(pData) = rmd.rmd0.rbadr; /* Receive Buffer Address */
1392 CSR_CRBC(pData) = rmd.rmd1.bcnt; /* Receive Byte Count */
1393 CSR_CRST(pData) = ((uint32_t *)&rmd)[1] >> 16; /* Receive Status */
1394#ifdef IN_RING3
1395 pData->pDrv->pfnNotifyCanReceive(pData->pDrv);
1396#else
1397 PPDMQUEUEITEMCORE pItem = PDMQueueAlloc(CTXSUFF(pData->pCanRxQueue));
1398 if (pItem)
1399 PDMQueueInsert(CTXSUFF(pData->pCanRxQueue), pItem);
1400#endif
1401 }
1402 else
1403 {
1404 /* This is not problematic since we don't own the descriptor */
1405 LogRel(("PCNet#%d: BAD RMD ENTRIES AT 0x%08x (i=%d)\n",
1406 PCNETSTATE_2_DEVINS(pData)->iInstance, addr, i));
1407 return;
1408 }
1409 }
1410
1411 /*
1412 * The next descriptor.
1413 */
1414 if (--i < 1)
1415 i = CSR_RCVRL(pData);
1416 addr = pcnetRdraAddr(pData, i);
1417 pcnetRmdLoad(pData, &rmd, PHYSADDR(pData, addr));
1418 CSR_NRDA(pData) = CSR_NRBA(pData) = 0;
1419 CSR_NRBC(pData) = 0;
1420 if (!rmd.rmd1.own)
1421 return;
1422 if (RT_LIKELY(!IS_RMD_BAD(rmd)))
1423 {
1424 CSR_NRDA(pData) = addr; /* Receive Descriptor Address */
1425 CSR_NRBA(pData) = rmd.rmd0.rbadr; /* Receive Buffer Address */
1426 CSR_NRBC(pData) = rmd.rmd1.bcnt; /* Receive Byte Count */
1427 CSR_NRST(pData) = ((uint32_t *)&rmd)[1] >> 16; /* Receive Status */
1428 }
1429 else
1430 {
1431 /* This is not problematic since we don't own the descriptor */
1432 LogRel(("PCNet#%d: BAD RMD ENTRIES + AT 0x%08x (i=%d)\n",
1433 PCNETSTATE_2_DEVINS(pData)->iInstance, addr, i));
1434 return;
1435 }
1436
1437 /**
1438 * @todo NNRD
1439 */
1440 }
1441 else
1442 {
1443 CSR_CRDA(pData) = CSR_CRBA(pData) = CSR_NRDA(pData) = CSR_NRBA(pData) = 0;
1444 CSR_CRBC(pData) = CSR_NRBC(pData) = CSR_CRST(pData) = 0;
1445 }
1446}
1447
1448/**
1449 * Poll Transmit Descriptor Table Entry
1450 * @return true if transmit descriptors available
1451 */
1452static int pcnetTdtePoll(PCNetState *pData, TMD *tmd)
1453{
1454 if (RT_LIKELY(pData->GCTDRA))
1455 {
1456 RTGCPHYS cxda = pcnetTdraAddr(pData, CSR_XMTRC(pData));
1457
1458 pcnetTmdLoad(pData, tmd, PHYSADDR(pData, cxda));
1459
1460 if (!tmd->tmd1.own)
1461 return 0;
1462
1463 if (RT_UNLIKELY(tmd->tmd1.ones != 15))
1464 {
1465 LogRel(("PCNet#%d: BAD TMD XDA=0x%08x\n",
1466 PCNETSTATE_2_DEVINS(pData)->iInstance, PHYSADDR(pData, cxda)));
1467 return 0;
1468 }
1469
1470 /* previous xmit descriptor */
1471 CSR_PXDA(pData) = CSR_CXDA(pData);
1472 CSR_PXBC(pData) = CSR_CXBC(pData);
1473 CSR_PXST(pData) = CSR_CXST(pData);
1474
1475 /* set current trasmit decriptor. */
1476 CSR_CXDA(pData) = cxda;
1477 CSR_CXBC(pData) = tmd->tmd1.bcnt;
1478 CSR_CXST(pData) = ((uint32_t *)tmd)[1] >> 16;
1479 return CARD_IS_OWNER(CSR_CXST(pData));
1480 }
1481 else
1482 {
1483 /** @todo consistency with previous receive descriptor */
1484 CSR_CXDA(pData) = 0;
1485 CSR_CXBC(pData) = CSR_CXST(pData) = 0;
1486 return 0;
1487 }
1488}
1489
1490#ifdef IN_RING3
1491/**
1492 * Check if there is at least one free receive buffer available.
1493 */
1494static int pcnetCanReceiveNoSync(PCNetState *pData)
1495{
1496 if (RT_UNLIKELY(CSR_DRX(pData) || CSR_STOP(pData) || CSR_SPND(pData)))
1497 return 0;
1498
1499 if (HOST_IS_OWNER(CSR_CRST(pData)) && pData->GCRDRA)
1500 pcnetRdtePoll(pData);
1501
1502 if (HOST_IS_OWNER(CSR_CRST(pData)))
1503 {
1504 /** @todo Notify the guest _now_. Will potentially increase the interrupt load */
1505 pData->aCSR[0] |= 0x1000; /* Set MISS flag */
1506 return 0;
1507 }
1508
1509 /* byte count stored in two's complement 12 bits wide */
1510 Log(("#%d pcnetCanReceiveNoSync %d bytes\n", PCNETSTATE_2_DEVINS(pData)->iInstance,
1511 4096 - CSR_CRBC(pData)));
1512 return 4096 - CSR_CRBC(pData);
1513}
1514#endif
1515
1516/**
1517 * Write data into guest receive buffers.
1518 */
1519static void pcnetReceiveNoSync(PCNetState *pData, const uint8_t *buf, int size)
1520{
1521 PPDMDEVINS pDevIns = PCNETSTATE_2_DEVINS(pData);
1522 int is_padr = 0, is_bcast = 0, is_ladr = 0;
1523
1524 if (RT_UNLIKELY(CSR_DRX(pData) || CSR_STOP(pData) || CSR_SPND(pData) || !size))
1525 return;
1526
1527 Log(("#%d pcnetReceiveNoSync: size=%d\n", PCNETSTATE_2_DEVINS(pData)->iInstance, size));
1528
1529 LOG_PACKET("rraw", buf, size);
1530
1531 /*
1532 * Perform address matching.
1533 */
1534 if ( CSR_PROM(pData)
1535 || (is_padr = padr_match(pData, buf, size))
1536 || (is_bcast = padr_bcast(pData, buf, size))
1537 || (is_ladr = ladr_match(pData, buf, size)))
1538 {
1539 if (HOST_IS_OWNER(CSR_CRST(pData)))
1540 pcnetRdtePoll(pData);
1541 if (RT_UNLIKELY(HOST_IS_OWNER(CSR_CRST(pData))))
1542 {
1543 /* Not owned by controller. This should not be possible as
1544 * we already called pcnetCanReceive(). */
1545 LogRel(("PCNet#%d: no buffer: RCVRC=%d\n",
1546 PCNETSTATE_2_DEVINS(pData)->iInstance, CSR_RCVRC(pData)));
1547 /* Dump the status of all RX descriptors */
1548 const unsigned cb = 1 << pData->iLog2DescSize;
1549 RTGCPHYS GCPhys = pData->GCRDRA;
1550 unsigned i = CSR_RCVRL(pData);
1551 while (i-- > 0)
1552 {
1553 RMD rmd;
1554 pcnetRmdLoad(pData, &rmd, PHYSADDR(pData, GCPhys));
1555 LogRel((" %08x\n", rmd.rmd1));
1556 GCPhys += cb;
1557 }
1558 pData->aCSR[0] |= 0x1000; /* Set MISS flag */
1559 CSR_MISSC(pData)++;
1560 }
1561 else
1562 {
1563 uint8_t *src = &pData->abRecvBuf[8];
1564 RTGCPHYS crda = CSR_CRDA(pData);
1565 RMD rmd;
1566 int pktcount = 0;
1567
1568 memcpy(src, buf, size);
1569 if (!CSR_ASTRP_RCV(pData))
1570 {
1571 uint32_t fcs = ~0;
1572 uint8_t *p = src;
1573
1574 while (size < 60)
1575 src[size++] = 0;
1576 while (p != &src[size])
1577 CRC(fcs, *p++);
1578 ((uint32_t *)&src[size])[0] = htonl(fcs);
1579 /* FCS at end of packet */
1580 }
1581 size += 4;
1582
1583#ifdef PCNET_DEBUG_MATCH
1584 PRINT_PKTHDR(buf);
1585#endif
1586
1587 pcnetRmdLoad(pData, &rmd, PHYSADDR(pData, crda));
1588 /*if (!CSR_LAPPEN(pData))*/
1589 rmd.rmd1.stp = 1;
1590
1591 int count = RT_MIN(4096 - (int)rmd.rmd1.bcnt, size);
1592 RTGCPHYS rbadr = PHYSADDR(pData, rmd.rmd0.rbadr);
1593 PDMDevHlpPhysWrite(pDevIns, rbadr, src, count);
1594 src += count;
1595 size -= count;
1596 rmd.rmd2.mcnt = count;
1597 pktcount++;
1598 if (size > 0)
1599 {
1600 if (HOST_IS_OWNER(CSR_NRST(pData)))
1601 {
1602 /* From the manual: ``Regardless of ownership of the second receive
1603 * descriptor, the Am79C972 controller will continue to perform receive
1604 * data DMA transfers to the first buffer. If the frame length exceeds
1605 * the length of the first buffer, and the Am79C972 controller does not
1606 * own the second buffer, ownership of the current descriptor will be
1607 * passed back to the system by writing a 0 to the OWN bit of RMD1.
1608 * Status will be written indicating buffer (BUFF = 1) and possibly
1609 * overflow (OFLO = 1) errors.
1610 * If the frame length exceeds the length of the first (current) buffer,
1611 * and the Am79C972 controller does own the second (next) buffer,
1612 * ownership will be passed back to the system by writing a 0 to the OWN
1613 * bit of RMD1 when the first buffer is full. The OWN bit is the only bit
1614 * modified in the descriptor. Receive data transfers to the second buffer
1615 * may occur before the Am79C972 controller proceeds to look ahead to the
1616 * ownership of the third buffer. Such action will depend upon the state
1617 * of the FIFO when the OWN bit has been updated in the first descriptor.
1618 * In any case, lookahead will be performed to the third buffer and the
1619 * information gathered will be stored in the chip, regardless of the state
1620 * of the ownership bit.'' */
1621 pcnetRdtePoll(pData, true);
1622 }
1623 if (CARD_IS_OWNER(CSR_NRST(pData)))
1624 {
1625 /* write back, clear the own bit */
1626 pcnetRmdStorePassHost(pData, &rmd, PHYSADDR(pData, crda));
1627 crda = CSR_NRDA(pData);
1628 pcnetRmdLoad(pData, &rmd, PHYSADDR(pData, crda));
1629 count = RT_MIN(4096 - (int)rmd.rmd1.bcnt, size);
1630 rbadr = PHYSADDR(pData, rmd.rmd0.rbadr);
1631 PDMDevHlpPhysWrite(pDevIns, rbadr, src, count);
1632 src += count;
1633 size -= count;
1634 rmd.rmd2.mcnt = count;
1635 pktcount++;
1636 }
1637 }
1638
1639 if (RT_LIKELY(size == 0))
1640 {
1641 rmd.rmd1.enp = 1;
1642 rmd.rmd1.pam = !CSR_PROM(pData) && is_padr;
1643 rmd.rmd1.lafm = !CSR_PROM(pData) && is_ladr;
1644 rmd.rmd1.bam = !CSR_PROM(pData) && is_bcast;
1645 }
1646 else
1647 {
1648 LogRel(("PCNet#%d: Overflow by %ubytes\n",
1649 PCNETSTATE_2_DEVINS(pData)->iInstance, size));
1650 rmd.rmd1.oflo = 1;
1651 rmd.rmd1.buff = 1;
1652 rmd.rmd1.err = 1;
1653 }
1654 /* write back, clear the own bit */
1655 pcnetRmdStorePassHost(pData, &rmd, PHYSADDR(pData, crda));
1656
1657 pData->aCSR[0] |= 0x0400;
1658
1659 Log(("#%d RCVRC=%d CRDA=0x%08x BLKS=%d\n", PCNETSTATE_2_DEVINS(pData)->iInstance,
1660 CSR_RCVRC(pData), PHYSADDR(pData, CSR_CRDA(pData)), pktcount));
1661#ifdef PCNET_DEBUG_RMD
1662 PRINT_RMD(&rmd);
1663#endif
1664
1665 while (pktcount--)
1666 {
1667 if (CSR_RCVRC(pData) < 2)
1668 CSR_RCVRC(pData) = CSR_RCVRL(pData);
1669 else
1670 CSR_RCVRC(pData)--;
1671 }
1672 /* guest driver is owner: force repoll of current and next RDTEs */
1673 CSR_CRST(pData) = 0;
1674 }
1675 }
1676
1677 /* see description of TXDPOLL:
1678 * ``transmit polling will take place following receive activities'' */
1679 pcnetPollRxTx(pData);
1680 pcnetUpdateIrq(pData);
1681}
1682
1683
1684/**
1685 * Checks if the link is up.
1686 * @returns true if the link is up.
1687 * @returns false if the link is down.
1688 */
1689DECLINLINE(bool) pcnetIsLinkUp(PCNetState *pData)
1690{
1691 return pData->pDrv && !pData->fLinkTempDown && pData->fLinkUp;
1692}
1693
1694#ifdef IN_RING3
1695/**
1696 * Transmit queue consumer
1697 * This is just a very simple way of delaying sending to R3.
1698 *
1699 * @returns Success indicator.
1700 * If false the item will not be removed and the flushing will stop.
1701 * @param pDevIns The device instance.
1702 * @param pItem The item to consume. Upon return this item will be freed.
1703 */
1704static DECLCALLBACK(bool) pcnetXmitQueueConsumer(PPDMDEVINS pDevIns, PPDMQUEUEITEMCORE pItem)
1705{
1706 PCNetState *pData = PDMINS2DATA(pDevIns, PCNetState *);
1707 unsigned i;
1708 int rc;
1709
1710 STAM_PROFILE_START(&pData->StatXmitQueue, a);
1711 STAM_COUNTER_INC(&pData->aStatFlushCounts[pData->iFrame]);
1712 rc = PDMCritSectEnter(&pData->CritSect, VERR_PERMISSION_DENIED);
1713 AssertReleaseRC(rc);
1714 LogFlow(("#%d pcnetXmitQueueConsumer: iFrame=%d\n", PCNETSTATE_2_DEVINS(pData)->iInstance, pData->iFrame));
1715
1716 pData->fTransmitting = true;
1717 for (i = 0; i < pData->iFrame; i++)
1718 {
1719 RTR3PTR pv = pData->aFrames[i].pvR3 != NIL_RTR3PTR
1720 ? pData->aFrames[i].pvR3
1721 : &pData->abFrameBuf[pData->aFrames[i].off];
1722 if (pData->aFrames[i].cb > 70) /* unqualified guess */
1723 pData->Led.Asserted.s.fWriting = pData->Led.Actual.s.fWriting = 1;
1724 if (pcnetIsLinkUp(pData))
1725 {
1726 pData->pDrv->pfnSend(pData->pDrv, pv, pData->aFrames[i].cb);
1727 LOG_PACKET("xmit", pv, pData->aFrames[i].cb);
1728 }
1729 }
1730
1731 pData->fTransmitting = false;
1732
1733 pData->aFrames[0].off = 0;
1734 pData->aFrames[0].cb = -1;
1735 pData->aFrames[0].pvR3 = NIL_RTR3PTR;
1736 pData->iFrame = 0;
1737 pData->Led.Actual.s.fWriting = 0;
1738
1739 PDMCritSectLeave(&pData->CritSect);
1740 STAM_PROFILE_STOP(&pData->StatXmitQueue, a);
1741 NOREF(pItem);
1742 return true;
1743}
1744#endif /* IN_RING3 */
1745
1746
1747/**
1748 * Flushes queued frames.
1749 */
1750DECLINLINE(void) pcnetXmitFlushFrames(PCNetState *pData)
1751{
1752 if (pData->iFrame)
1753 {
1754 LogFlow(("#%d pcnetXmitFlushFrames: flushing %d frames\n", PCNETSTATE_2_DEVINS(pData)->iInstance, pData->iFrame));
1755#ifdef IN_RING3
1756 pcnetXmitQueueConsumer(CTXSUFF(pData->pDevIns), NULL);
1757#else
1758 STAM_PROFILE_ADV_START(&pData->StatXmitQueueFlushGC, a);
1759 PDMQueueFlush(pData->CTXSUFF(pXmitQueue));
1760 STAM_PROFILE_ADV_STOP(&pData->StatXmitQueueFlushGC, a);
1761#endif
1762 }
1763 pData->aFrames[0].off = 0;
1764 pData->aFrames[0].cb = -1;
1765 pData->aFrames[0].pvR3 = NIL_RTR3PTR;
1766 pData->iFrame = 0;
1767}
1768
1769
1770/**
1771 * Scraps the top frame.
1772 * This is done as a precaution against mess left over by on
1773 */
1774DECLINLINE(void) pcnetXmitScrapFrame(PCNetState *pData)
1775{
1776 const uint32_t iFrame = pData->iFrame;
1777 pData->aFrames[iFrame].cb = -1;
1778}
1779
1780
1781/**
1782 * Ensures that we've got enough buffer space for the frame.
1783 */
1784DECLINLINE(void) pcnetXmitEnsureSpace(PCNetState *pData, const unsigned cb, const bool fForceFlush)
1785{
1786 const uint32_t iFrame = pData->iFrame;
1787 if ( fForceFlush
1788 || cb > sizeof(pData->abFrameBuf) - pData->aFrames[iFrame].off)
1789 pcnetXmitFlushFrames(pData);
1790}
1791
1792
1793#ifdef IN_RING3
1794/**
1795 * If we are in RING3 don't copy the frame from GC here but only store the address. We
1796 * don't need to buffer the frames because we will flush all pending frames at the end of
1797 * pcnetTransmit anyway.
1798 */
1799DECLINLINE(void) pcnetXmitZeroCopyFrame(PCNetState *pData, RTR3PTR pv, const unsigned cbFrame)
1800{
1801 const uint32_t iFrame = pData->iFrame;
1802 pData->aFrames[iFrame].pvR3 = pv;
1803 pData->aFrames[iFrame].cb = cbFrame;
1804}
1805#endif
1806
1807
1808/**
1809 * Reads the first part of a frame
1810 */
1811DECLINLINE(void) pcnetXmitRead1st(PCNetState *pData, RTGCPHYS GCPhysFrame, const unsigned cbFrame)
1812{
1813 const uint32_t iFrame = pData->iFrame;
1814 PDMDevHlpPhysRead(pData->CTXSUFF(pDevIns), GCPhysFrame,
1815 &pData->abFrameBuf[pData->aFrames[iFrame].off],
1816 cbFrame);
1817 pData->aFrames[iFrame].cb = cbFrame;
1818}
1819
1820
1821/**
1822 * Reads more into the current frame.
1823 */
1824DECLINLINE(void) pcnetXmitReadMore(PCNetState *pData, RTGCPHYS GCPhysFrame, const unsigned cbFrame)
1825{
1826 const uint32_t iFrame = pData->iFrame;
1827 PDMDevHlpPhysRead(pData->CTXSUFF(pDevIns), GCPhysFrame,
1828 &pData->abFrameBuf[pData->aFrames[iFrame].off + pData->aFrames[iFrame].cb],
1829 cbFrame);
1830 pData->aFrames[iFrame].cb += cbFrame;
1831}
1832
1833
1834/**
1835 * Completes the current frame.
1836 * If we've reached the maxium number of frames, they will be flushed.
1837 */
1838DECLINLINE(void) pcnetXmitCompleteFrame(PCNetState *pData)
1839{
1840 const uint32_t iFrame = ++pData->iFrame;
1841 if (iFrame == ELEMENTS(pData->aFrames))
1842 pcnetXmitFlushFrames(pData);
1843 else
1844 {
1845 /* initialize next frame */
1846 pData->aFrames[iFrame].off = pData->aFrames[iFrame - 1].off
1847 + RT_ALIGN_32(pData->aFrames[iFrame - 1].cb, 16);
1848 pData->aFrames[iFrame].cb = -1;
1849 pData->aFrames[iFrame].pvR3 = NIL_RTR3PTR;
1850 }
1851}
1852
1853
1854/**
1855 * Fails a TMD with a link down error.
1856 */
1857static void pcnetXmitFailTMDLinkDown(PCNetState *pData, TMD *pTmd)
1858{
1859 /* make carrier error - hope this is correct. */
1860 pData->cLinkDownReported++;
1861 pTmd->tmd2.lcar = pTmd->tmd1.err = 1;
1862 pData->aCSR[0] |= BIT(15) | BIT(13); /* ERR | CERR */
1863 pData->Led.Asserted.s.fError = pData->Led.Actual.s.fError = 1;
1864 Log(("#%d pcnetTransmit: Signaling send error. swstyle=%#x\n",
1865 PCNETSTATE_2_DEVINS(pData)->iInstance, pData->aBCR[BCR_SWS]));
1866}
1867
1868
1869/**
1870 * Transmit a loopback frame.
1871 */
1872DECLINLINE(void) pcnetXmitLoopbackFrame(PCNetState *pData)
1873{
1874 Assert(pData->iFrame == 0);
1875 pData->Led.Asserted.s.fReading = pData->Led.Actual.s.fReading = 1;
1876 if (HOST_IS_OWNER(CSR_CRST(pData)))
1877 pcnetRdtePoll(pData);
1878 pcnetReceiveNoSync(pData, &pData->abFrameBuf[pData->aFrames[0].off], pData->aFrames[0].cb);
1879 pcnetXmitScrapFrame(pData);
1880 pData->Led.Actual.s.fReading = 0;
1881}
1882
1883
1884/**
1885 * Try to transmit frames
1886 */
1887static void pcnetTransmit(PCNetState *pData)
1888{
1889 /*
1890 * Prevent various pollers (esp the one in pcnetReceiveNoSync) from causing
1891 * recursion when flushing a queue.
1892 */
1893 if (pData->fTransmitting)
1894 return;
1895
1896 if (RT_UNLIKELY(!CSR_TXON(pData)))
1897 {
1898 pData->aCSR[0] &= ~0x0008; /* Clear TDMD */
1899 return;
1900 }
1901
1902 /*
1903 * Iterate the transmit descriptors.
1904 */
1905 STAM_PROFILE_ADV_START(&pData->CTXSUFF(StatTransmit), a);
1906 do
1907 {
1908#ifdef VBOX_WITH_STATISTICS
1909 unsigned cBuffers = 1;
1910#endif
1911 TMD tmd;
1912 if (!pcnetTdtePoll(pData, &tmd))
1913 break;
1914
1915#ifdef PCNET_DEBUG_TMD
1916 Log(("#%d TMDLOAD 0x%08x\n", PCNETSTATE_2_DEVINS(pData)->iInstance, PHYSADDR(pData, CSR_CXDA(pData))));
1917 PRINT_TMD(&tmd);
1918#endif
1919 pcnetXmitScrapFrame(pData);
1920
1921 /*
1922 * The typical case - a complete packet.
1923 * This can be performed with zero copy in Ring-3.
1924 */
1925 if (tmd.tmd1.stp && tmd.tmd1.enp)
1926 {
1927 const unsigned cb = 4096 - tmd.tmd1.bcnt;
1928 Log(("#%d pcnetTransmit: stp&enp: cb=%d xmtrc=%#x\n", PCNETSTATE_2_DEVINS(pData)->iInstance, cb, CSR_XMTRC(pData)));
1929 if (RT_LIKELY(pcnetIsLinkUp(pData) || CSR_LOOP(pData)))
1930 {
1931#ifdef IN_RING3
1932 RTR3PTR pv;
1933 int rc = PDMDevHlpPhys2HCVirt(pData->pDevInsHC,
1934 PHYSADDR(pData, tmd.tmd0.tbadr), cb, &pv);
1935 if (RT_SUCCESS(rc))
1936 pcnetXmitZeroCopyFrame(pData, pv, cb);
1937 else
1938#endif
1939 {
1940 pcnetXmitEnsureSpace(pData, cb, CSR_LOOP(pData));
1941 pcnetXmitRead1st(pData, PHYSADDR(pData, tmd.tmd0.tbadr), cb);
1942 }
1943 if (CSR_LOOP(pData))
1944 pcnetXmitLoopbackFrame(pData);
1945 else
1946 pcnetXmitCompleteFrame(pData);
1947 }
1948 else
1949 pcnetXmitFailTMDLinkDown(pData, &tmd);
1950
1951 /* Write back the TMD and pass it to the host (clear own bit). */
1952 pcnetTmdStorePassHost(pData, &tmd, PHYSADDR(pData, CSR_CXDA(pData)));
1953
1954 /* advance the ring counter register */
1955 if (CSR_XMTRC(pData) < 2)
1956 CSR_XMTRC(pData) = CSR_XMTRL(pData);
1957 else
1958 CSR_XMTRC(pData)--;
1959 }
1960 else if (tmd.tmd1.stp)
1961 {
1962 /*
1963 * Read TMDs until end-of-packet or tdte poll fails (underflow).
1964 */
1965 const unsigned cbMaxFrame = 4096;
1966 bool fDropFrame = false;
1967 unsigned cb = 4096 - tmd.tmd1.bcnt;
1968 pcnetXmitEnsureSpace(pData, cbMaxFrame, CSR_LOOP(pData));
1969 pcnetXmitRead1st(pData, PHYSADDR(pData, tmd.tmd0.tbadr), cb);
1970 for (;;)
1971 {
1972 /*
1973 * Advance the ring counter register and check the next tmd.
1974 */
1975#ifdef LOG_ENABLED
1976 const uint32_t iStart = CSR_XMTRC(pData);
1977#endif
1978 const uint32_t GCPhysPrevTmd = PHYSADDR(pData, CSR_CXDA(pData));
1979 if (CSR_XMTRC(pData) < 2)
1980 CSR_XMTRC(pData) = CSR_XMTRL(pData);
1981 else
1982 CSR_XMTRC(pData)--;
1983
1984 TMD dummy;
1985 if (!pcnetTdtePoll(pData, &dummy))
1986 {
1987 /*
1988 * Underflow!
1989 */
1990 tmd.tmd2.buff = tmd.tmd2.uflo = tmd.tmd1.err = 1;
1991 pData->aCSR[0] |= 0x0200; /* set TINT */
1992 if (!CSR_DXSUFLO(pData)) /* stop on xmit underflow */
1993 pData->aCSR[0] &= ~0x0010; /* clear TXON */
1994 pcnetTmdStorePassHost(pData, &tmd, GCPhysPrevTmd);
1995 AssertMsgFailed(("pcnetTransmit: Underflow!!!\n"));
1996 break;
1997 }
1998
1999 /* release & save the previous tmd, pass it to the host */
2000 pcnetTmdStorePassHost(pData, &tmd, GCPhysPrevTmd);
2001
2002 /*
2003 * The next tdm.
2004 */
2005#ifdef VBOX_WITH_STATISTICS
2006 cBuffers++;
2007#endif
2008 pcnetTmdLoad(pData, &tmd, PHYSADDR(pData, CSR_CXDA(pData)));
2009 cb = 4096 - tmd.tmd1.bcnt;
2010 if ( pData->aFrames[pData->iFrame].cb + cb < cbMaxFrame
2011 && !fDropFrame)
2012 pcnetXmitReadMore(pData, PHYSADDR(pData, tmd.tmd0.tbadr), cb);
2013 else
2014 {
2015 AssertMsg(fDropFrame, ("pcnetTransmit: Frame is too big!!! %d bytes\n",
2016 pData->aFrames[pData->iFrame].cb + cb));
2017 fDropFrame = true;
2018 }
2019 if (tmd.tmd1.enp)
2020 {
2021 Log(("#%d pcnetTransmit: stp: cb=%d xmtrc=%#x-%#x\n", PCNETSTATE_2_DEVINS(pData)->iInstance,
2022 pData->aFrames[pData->iFrame].cb, iStart, CSR_XMTRC(pData)));
2023 if (pcnetIsLinkUp(pData) && !fDropFrame)
2024 pcnetXmitCompleteFrame(pData);
2025 else if (CSR_LOOP(pData) && !fDropFrame)
2026 pcnetXmitLoopbackFrame(pData);
2027 else
2028 {
2029 if (!fDropFrame)
2030 pcnetXmitFailTMDLinkDown(pData, &tmd);
2031 pcnetXmitScrapFrame(pData);
2032 }
2033
2034 /* Write back the TMD, pass it to the host */
2035 pcnetTmdStorePassHost(pData, &tmd, PHYSADDR(pData, CSR_CXDA(pData)));
2036
2037 /* advance the ring counter register */
2038 if (CSR_XMTRC(pData) < 2)
2039 CSR_XMTRC(pData) = CSR_XMTRL(pData);
2040 else
2041 CSR_XMTRC(pData)--;
2042 break;
2043 }
2044 }
2045 }
2046 else
2047 {
2048 /*
2049 * We underflowed in a previous transfer, or the driver is giving us shit.
2050 * Simply stop the transmitting for now.
2051 */
2052 Log(("#%d pcnetTransmit: guest is giving us shit!\n", PCNETSTATE_2_DEVINS(pData)->iInstance));
2053 break;
2054 }
2055
2056 /* Update TDMD, TXSTRT and TINT. */
2057 pData->aCSR[0] &= ~0x0008; /* clear TDMD */
2058 pData->aCSR[4] |= 0x0004; /* set TXSTRT */
2059 if ( !CSR_TOKINTD(pData) /* Transmit OK Interrupt Disable, no infl. on errors. */
2060 || (CSR_LTINTEN(pData) && tmd.tmd1.ltint)
2061 || tmd.tmd1.err)
2062 pData->aCSR[0] |= 0x0200; /* set TINT */
2063
2064 STAM_COUNTER_INC(&pData->aStatXmitChainCounts[RT_MIN(cBuffers,
2065 ELEMENTS(pData->aStatXmitChainCounts)) - 1]);
2066 } while (CSR_TXON(pData)); /* transfer on */
2067
2068 STAM_PROFILE_ADV_STOP(&pData->CTXSUFF(StatTransmit), a);
2069
2070 /*
2071 * If we're in Ring-3 we should flush the queue now, in GC/R0 we'll queue a flush job.
2072 */
2073#ifdef IN_RING3
2074 pcnetXmitFlushFrames(pData);
2075#else
2076 if (pData->iFrame)
2077 {
2078 PPDMQUEUEITEMCORE pItem = PDMQueueAlloc(CTXSUFF(pData->pXmitQueue));
2079 if (pItem)
2080# if 0 /* send before resuming guest (last argument isn't implemented yet and read as 0). */
2081 PDMQueueInsertEx(CTXSUFF(pData->pXmitQueue), pItem, 50000);
2082# else /* send when going back to r3. */
2083 PDMQueueInsert(CTXSUFF(pData->pXmitQueue), pItem);
2084# endif
2085 }
2086#endif
2087}
2088
2089/**
2090 * Poll for changes in RX and TX descriptor rings.
2091 */
2092static void pcnetPollRxTx(PCNetState *pData)
2093{
2094 if (CSR_RXON(pData))
2095 if (HOST_IS_OWNER(CSR_CRST(pData))) /* Only poll RDTEs if none available */
2096 pcnetRdtePoll(pData);
2097
2098 if (CSR_TDMD(pData) || CSR_TXON(pData) && !CSR_DPOLL(pData))
2099 pcnetTransmit(pData);
2100}
2101
2102/**
2103 * Update the poller timer
2104 * @thread EMT,
2105 */
2106static void pcnetPollTimer(PCNetState *pData)
2107{
2108 STAM_PROFILE_ADV_START(&pData->StatPollTimer, a);
2109
2110#ifdef LOG_ENABLED
2111 TMD dummy;
2112 Log2(("#%d pcnetPollTimer time=%08x TDMD=%d TXON=%d POLL=%d TDTE=%d TRDA=%x\n",
2113 PCNETSTATE_2_DEVINS(pData)->iInstance, RTTimeMilliTS(), CSR_TDMD(pData), CSR_TXON(pData),
2114 !CSR_DPOLL(pData), pcnetTdtePoll(pData, &dummy), pData->GCTDRA));
2115 Log2(("#%d pcnetPollTimer: CSR_CXDA=%x CSR_XMTRL=%d CSR_XMTRC=%d\n",
2116 PCNETSTATE_2_DEVINS(pData)->iInstance, CSR_CXDA(pData), CSR_XMTRL(pData), CSR_XMTRC(pData)));
2117#endif
2118#ifdef PCNET_DEBUG_TMD
2119 if (CSR_CXDA(pData))
2120 {
2121 TMD tmd;
2122 pcnetTmdLoad(pData, &tmd, PHYSADDR(pData, CSR_CXDA(pData)));
2123 Log2(("#%d pcnetPollTimer: TMDLOAD 0x%08x\n", PCNETSTATE_2_DEVINS(pData)->iInstance, PHYSADDR(pData, CSR_CXDA(pData))));
2124 PRINT_TMD(&tmd);
2125 }
2126#endif
2127 if (CSR_TDMD(pData))
2128 pcnetTransmit(pData);
2129
2130 pcnetUpdateIrq(pData);
2131
2132 if (RT_LIKELY(!CSR_STOP(pData) && !CSR_SPND(pData) && !CSR_DPOLL(pData)))
2133 {
2134 /* We ensure that we poll at least every 2ms (500Hz) but not more often than
2135 * 5000 times per second. This way we completely prevent the overhead from
2136 * heavy reprogramming the timer which turned out to be very CPU-intensive.
2137 * The drawback is that csr46 and csr47 are not updated properly anymore
2138 * but so far I have not seen any guest depending on these values. The 2ms
2139 * interval is the default polling interval of the PCNet card (65536/33MHz). */
2140#ifdef PCNET_NO_POLLING
2141 pcnetPollRxTx(pData);
2142#else
2143 uint64_t u64Now = TMTimerGet(pData->CTXSUFF(pTimerPoll));
2144 if (RT_UNLIKELY(u64Now - pData->u64LastPoll > 200000))
2145 {
2146 pData->u64LastPoll = u64Now;
2147 pcnetPollRxTx(pData);
2148 }
2149 if (!TMTimerIsActive(pData->CTXSUFF(pTimerPoll)))
2150 /* Poll timer interval is fixed to 500Hz. Don't stop it. */
2151 TMTimerSet(pData->CTXSUFF(pTimerPoll),
2152 TMTimerGet(pData->CTXSUFF(pTimerPoll)) + 2000000);
2153#endif
2154 }
2155 STAM_PROFILE_ADV_STOP(&pData->StatPollTimer, a);
2156}
2157
2158
2159static int pcnetCSRWriteU16(PCNetState *pData, uint32_t u32RAP, uint32_t new_value)
2160{
2161 uint16_t val = new_value;
2162 int rc = VINF_SUCCESS;
2163#ifdef PCNET_DEBUG_CSR
2164 Log(("#%d pcnetCSRWriteU16: rap=%d val=0x%04x\n", PCNETSTATE_2_DEVINS(pData)->iInstance, u32RAP, val));
2165#endif
2166 switch (u32RAP)
2167 {
2168 case 0:
2169 {
2170 uint16_t csr0 = pData->aCSR[0];
2171 /* Clear any interrupt flags.
2172 * Don't clear an interrupt flag which was not seen by the guest yet. */
2173 csr0 &= ~(val & 0x7f00 & pData->u16CSR0LastSeenByGuest);
2174 csr0 = (csr0 & ~0x0040) | (val & 0x0048);
2175 val = (val & 0x007f) | (csr0 & 0x7f00);
2176
2177 /* Iff STOP, STRT and INIT are set, clear STRT and INIT */
2178 if ((val & 7) == 7)
2179 val &= ~3;
2180
2181#ifndef IN_RING3
2182 if (!(csr0 & 0x0001/*init*/) && (val & 1))
2183 {
2184 Log(("#%d pcnetCSRWriteU16: pcnetInit requested => HC\n", PCNETSTATE_2_DEVINS(pData)->iInstance));
2185 return VINF_IOM_HC_IOPORT_WRITE;
2186 }
2187#endif
2188 LOG_REGISTER(("PCNet#%d: WRITE CSR%d, %04x => %04x (%04x)\n",
2189 PCNETSTATE_2_DEVINS(pData)->iInstance,
2190 u32RAP, new_value, csr0, pData->aCSR[0]));
2191 pData->aCSR[0] = csr0;
2192
2193 if (!CSR_STOP(pData) && (val & 4))
2194 pcnetStop(pData);
2195
2196#ifdef IN_RING3
2197 if (!CSR_INIT(pData) && (val & 1))
2198 pcnetInit(pData);
2199#endif
2200
2201 if (!CSR_STRT(pData) && (val & 2))
2202 pcnetStart(pData);
2203
2204 if (CSR_TDMD(pData))
2205 pcnetTransmit(pData);
2206
2207 return rc;
2208 }
2209 case 1: /* IADRL */
2210 case 2: /* IADRH */
2211 case 8: /* LADRF 0..15 */
2212 case 9: /* LADRF 16..31 */
2213 case 10: /* LADRF 32..47 */
2214 case 11: /* LADRF 48..63 */
2215 case 12: /* PADR 0..15 */
2216 case 13: /* PADR 16..31 */
2217 case 14: /* PADR 32..47 */
2218 case 18: /* CRBAL */
2219 case 19: /* CRBAU */
2220 case 20: /* CXBAL */
2221 case 21: /* CXBAU */
2222 case 22: /* NRBAL */
2223 case 23: /* NRBAU */
2224 case 24: /* BADRL */
2225 case 25: /* BADRU */
2226 case 26: /* NRDAL */
2227 case 27: /* NRDAU */
2228 case 28: /* CRDAL */
2229 case 29: /* CRDAU */
2230 case 30: /* BADXL */
2231 case 31: /* BADXU */
2232 case 32: /* NXDAL */
2233 case 33: /* NXDAU */
2234 case 34: /* CXDAL */
2235 case 35: /* CXDAU */
2236 case 36: /* NNRDL */
2237 case 37: /* NNRDU */
2238 case 38: /* NNXDL */
2239 case 39: /* NNXDU */
2240 case 40: /* CRBCL */
2241 case 41: /* CRBCU */
2242 case 42: /* CXBCL */
2243 case 43: /* CXBCU */
2244 case 44: /* NRBCL */
2245 case 45: /* NRBCU */
2246 case 46: /* POLL */
2247 case 47: /* POLLINT */
2248 case 72: /* RCVRC */
2249 case 74: /* XMTRC */
2250 case 76: /* RCVRL */ /** @todo call pcnetUpdateRingHandlers */
2251 /** @todo receive ring length is stored in two's complement! */
2252 case 78: /* XMTRL */ /** @todo call pcnetUpdateRingHandlers */
2253 /** @todo transmit ring length is stored in two's complement! */
2254 case 112: /* MISSC */
2255 if (CSR_STOP(pData) || CSR_SPND(pData))
2256 break;
2257 LOG_REGISTER(("PCNet#%d: WRITE CSR%d, %04x\n",
2258 PCNETSTATE_2_DEVINS(pData)->iInstance, u32RAP, val));
2259 return rc;
2260 case 3: /* Interrupt Mask and Deferral Control */
2261 LOG_REGISTER(("PCNet#%d: WRITE CSR%d, %04x\n",
2262 PCNETSTATE_2_DEVINS(pData)->iInstance, u32RAP, val));
2263 break;
2264 case 4: /* Test and Features Control */
2265 LOG_REGISTER(("PCNet#%d: WRITE CSR%d, %04x\n",
2266 PCNETSTATE_2_DEVINS(pData)->iInstance, u32RAP, val));
2267 pData->aCSR[4] &= ~(val & 0x026a);
2268 val &= ~0x026a;
2269 val |= pData->aCSR[4] & 0x026a;
2270 break;
2271 case 5: /* Extended Control and Interrupt 1 */
2272 LOG_REGISTER(("PCNet#%d: WRITE CSR%d, %04x\n",
2273 PCNETSTATE_2_DEVINS(pData)->iInstance, u32RAP, val));
2274 pData->aCSR[5] &= ~(val & 0x0a90);
2275 val &= ~0x0a90;
2276 val |= pData->aCSR[5] & 0x0a90;
2277 break;
2278 case 15: /* Mode */
2279 if ((pData->aCSR[15] & 0x8000) != (val & 0x8000) && pData->pDrv)
2280 {
2281 Log(("PCNet#%d: promiscuous mode changed to %d\n",
2282 PCNETSTATE_2_DEVINS(pData)->iInstance, !!(val & 0x8000)));
2283#ifndef IN_RING3
2284 return VINF_IOM_HC_IOPORT_WRITE;
2285#else
2286 /* check for promiscuous mode change */
2287 pData->pDrv->pfnSetPromiscuousMode(pData->pDrv, !!(val & 0x8000));
2288#endif
2289 }
2290 break;
2291 case 16: /* IADRL */
2292 return pcnetCSRWriteU16(pData, 1, val);
2293 case 17: /* IADRH */
2294 return pcnetCSRWriteU16(pData, 2, val);
2295 case 58: /* Software Style */
2296 LOG_REGISTER(("PCNet#%d: WRITE SW_STYLE, %04x\n",
2297 PCNETSTATE_2_DEVINS(pData)->iInstance, val));
2298 rc = pcnetBCRWriteU16(pData, BCR_SWS, val);
2299 break;
2300 default:
2301 return rc;
2302 }
2303 pData->aCSR[u32RAP] = val;
2304 return rc;
2305}
2306
2307static uint32_t pcnetCSRReadU16(PCNetState *pData, uint32_t u32RAP)
2308{
2309 uint32_t val;
2310 switch (u32RAP)
2311 {
2312 case 0:
2313 pcnetUpdateIrq(pData);
2314 val = pData->aCSR[0];
2315 val |= (val & 0x7800) ? 0x8000 : 0;
2316 pData->u16CSR0LastSeenByGuest = val;
2317 break;
2318 case 16:
2319 return pcnetCSRReadU16(pData, 1);
2320 case 17:
2321 return pcnetCSRReadU16(pData, 2);
2322 case 58:
2323 return pcnetBCRReadU16(pData, BCR_SWS);
2324 case 88:
2325 val = pData->aCSR[89];
2326 val <<= 16;
2327 val |= pData->aCSR[88];
2328 break;
2329 default:
2330 val = pData->aCSR[u32RAP];
2331 LOG_REGISTER(("PCNet#%d: read CSR%d => %04x\n",
2332 PCNETSTATE_2_DEVINS(pData)->iInstance, u32RAP, val));
2333 }
2334#ifdef PCNET_DEBUG_CSR
2335 Log(("#%d pcnetCSRReadU16: u32RAP=%d val=0x%04x\n", PCNETSTATE_2_DEVINS(pData)->iInstance,
2336 u32RAP, val));
2337#endif
2338 return val;
2339}
2340
2341static int pcnetBCRWriteU16(PCNetState *pData, uint32_t u32RAP, uint32_t val)
2342{
2343 int rc = VINF_SUCCESS;
2344 u32RAP &= 0x7f;
2345#ifdef PCNET_DEBUG_BCR
2346 Log(("#%d pcnetBCRWriteU16: u32RAP=%d val=0x%04x\n", PCNETSTATE_2_DEVINS(pData)->iInstance,
2347 u32RAP, val));
2348#endif
2349 switch (u32RAP)
2350 {
2351 case BCR_SWS:
2352 if (!(CSR_STOP(pData) || CSR_SPND(pData)))
2353 return rc;
2354 val &= ~0x0300;
2355 switch (val & 0x00ff)
2356 {
2357 default:
2358 Log(("Bad SWSTYLE=0x%02x\n", val & 0xff));
2359 // fall through
2360 case 0:
2361 val |= 0x0200; /* 16 bit */
2362 pData->iLog2DescSize = 3;
2363 pData->GCUpperPhys = (0xff00 & (uint32_t)pData->aCSR[2]) << 16;
2364 break;
2365 case 1:
2366 val |= 0x0100; /* 32 bit */
2367 pData->iLog2DescSize = 4;
2368 pData->GCUpperPhys = 0;
2369 break;
2370 case 2:
2371 case 3:
2372 val |= 0x0300; /* 32 bit */
2373 pData->iLog2DescSize = 4;
2374 pData->GCUpperPhys = 0;
2375 break;
2376 }
2377 LOG_REGISTER(("PCNet#%d: WRITE SW_STYLE, %04x\n",
2378 PCNETSTATE_2_DEVINS(pData)->iInstance, val));
2379 Log(("BCR_SWS=0x%04x\n", val));
2380 pData->aCSR[58] = val;
2381 /* fall through */
2382 case BCR_LNKST:
2383 case BCR_LED1:
2384 case BCR_LED2:
2385 case BCR_LED3:
2386 case BCR_MC:
2387 case BCR_FDC:
2388 case BCR_BSBC:
2389 case BCR_EECAS:
2390 case BCR_PLAT:
2391 case BCR_MIIADDR:
2392 LOG_REGISTER(("PCNet#%d: WRITE BCR%d, %04x\n",
2393 PCNETSTATE_2_DEVINS(pData)->iInstance, u32RAP, val));
2394 pData->aBCR[u32RAP] = val;
2395 break;
2396
2397 case BCR_MIIMDR:
2398 LOG_REGISTER(("PCNet#%d: WRITE MII%d, %04x\n",
2399 PCNETSTATE_2_DEVINS(pData)->iInstance, u32RAP, val));
2400 pData->aMII[pData->aBCR[BCR_MIIADDR] & 0x1f] = val;
2401 break;
2402
2403 default:
2404 break;
2405 }
2406 return rc;
2407}
2408
2409static uint32_t pcnetMIIReadU16(PCNetState *pData, uint32_t miiaddr)
2410{
2411 uint32_t val;
2412 STAM_COUNTER_INC(&pData->StatMIIReads);
2413
2414 switch (miiaddr)
2415 {
2416 case 0:
2417 /* MII basic mode control register. */
2418 val = 0x1000; /* Enable auto negotiation. */
2419 break;
2420
2421 case 1:
2422 /* MII basic mode status register. */
2423 if (pData->fLinkUp && !pData->fLinkTempDown)
2424 val = 0x7800 /* Can do 100mbps FD/HD and 10mbps FD/HD. */
2425 | 0x0020 /* Auto-negotiation complete. */
2426 | 0x0008 /* Able to do auto-negotiation. */
2427 | 0x0004 /* Link status. */
2428 | 0x0001; /* Extended Capability, i.e. registers 4+ valid. */
2429 else
2430 {
2431 val = 0x7800 /* Can do 100mbps FD/HD and 10mbps FD/HD. */
2432 | 0x0008 /* Able to do auto-negotiation. */
2433 | 0x0001; /* Extended Capability, i.e. registers 4+ valid. */
2434 pData->cLinkDownReported++;
2435 }
2436 break;
2437
2438 case 2:
2439 /* PHY identifier 1. */
2440 val = 0; /* No name PHY. */
2441 break;
2442
2443 case 3:
2444 /* PHY identifier 2. */
2445 val = 0; /* No name PHY. */
2446 break;
2447
2448 case 4:
2449 /* Advertisement control register. */
2450 val = 0x05e0 /* Try flow control, 100mbps FD/HD and 10mbps FD/HD. */
2451 | 0x0001; /* CSMA selector. */
2452 break;
2453
2454 case 5:
2455 /* Link partner ability register. */
2456 if (pData->fLinkUp && !pData->fLinkTempDown)
2457 val = 0x8000 /* Next page bit. */
2458 | 0x4000 /* Link partner acked us. */
2459 | 0x05e0 /* Can do flow control, 100mbps FD/HD and 10mbps FD/HD. */
2460 | 0x0001; /* Use CSMA selector. */
2461 else
2462 {
2463 val = 0;
2464 pData->cLinkDownReported++;
2465 }
2466 break;
2467
2468 case 6:
2469 /* Auto negotiation expansion register. */
2470 if (pData->fLinkUp && !pData->fLinkTempDown)
2471 val = 0x0008 /* Link partner supports npage. */
2472 | 0x0004 /* Enable npage words. */
2473 | 0x0001; /* Can do N-way auto-negotiation. */
2474 else
2475 {
2476 val = 0;
2477 pData->cLinkDownReported++;
2478 }
2479 break;
2480
2481 default:
2482 val = 0;
2483 break;
2484 }
2485
2486#ifdef PCNET_DEBUG_MII
2487 Log(("#%d pcnet: mii read %d -> %#x\n", PCNETSTATE_2_DEVINS(pData)->iInstance,
2488 miiaddr, val));
2489#endif
2490 return val;
2491}
2492
2493static uint32_t pcnetBCRReadU16(PCNetState *pData, uint32_t u32RAP)
2494{
2495 uint32_t val;
2496 u32RAP &= 0x7f;
2497 switch (u32RAP)
2498 {
2499 case BCR_LNKST:
2500 case BCR_LED1:
2501 case BCR_LED2:
2502 case BCR_LED3:
2503 val = pData->aBCR[u32RAP] & ~0x8000;
2504 /* Clear LNKSTE if we're not connected or if we've just loaded a VM state. */
2505 if (!pData->pDrv || pData->fLinkTempDown || !pData->fLinkUp)
2506 {
2507 if (u32RAP == 4)
2508 pData->cLinkDownReported++;
2509 val &= ~0x40;
2510 }
2511 val |= (val & 0x017f & pData->u32Lnkst) ? 0x8000 : 0;
2512 break;
2513
2514 case BCR_MIIMDR:
2515 if (pData->fAm79C973 && (pData->aBCR[BCR_MIIADDR] >> 5 & 0x1f) == 0)
2516 {
2517 size_t miiaddr = pData->aBCR[BCR_MIIADDR] & 0x1f;
2518 val = pcnetMIIReadU16(pData, miiaddr);
2519 }
2520 else
2521 val = 0xffff;
2522 break;
2523
2524 default:
2525 val = u32RAP < BCR_MAX_RAP ? pData->aBCR[u32RAP] : 0;
2526 break;
2527 }
2528#ifdef PCNET_DEBUG_BCR
2529 Log(("#%d pcnetBCRReadU16: u32RAP=%d val=0x%04x\n", PCNETSTATE_2_DEVINS(pData)->iInstance,
2530 u32RAP, val));
2531#endif
2532 return val;
2533}
2534
2535#ifdef IN_RING3 /* move down */
2536static void pcnetHardReset(PCNetState *pData)
2537{
2538 int i;
2539 uint16_t checksum;
2540
2541 /* Initialize the PROM */
2542 Assert(sizeof(pData->MacConfigured) == 6);
2543 memcpy(pData->aPROM, &pData->MacConfigured, sizeof(pData->MacConfigured));
2544 pData->aPROM[12] = pData->aPROM[13] = 0x00;
2545 pData->aPROM[14] = pData->aPROM[15] = 0x57;
2546
2547 for (i = 0, checksum = 0; i < 16; i++)
2548 checksum += pData->aPROM[i];
2549 *(uint16_t *)&pData->aPROM[12] = cpu_to_le16(checksum);
2550
2551 pData->aBCR[BCR_MSRDA] = 0x0005;
2552 pData->aBCR[BCR_MSWRA] = 0x0005;
2553 pData->aBCR[BCR_MC ] = 0x0002;
2554 pData->aBCR[BCR_LNKST] = 0x00c0;
2555 pData->aBCR[BCR_LED1 ] = 0x0084;
2556 pData->aBCR[BCR_LED2 ] = 0x0088;
2557 pData->aBCR[BCR_LED3 ] = 0x0090;
2558 pData->aBCR[BCR_FDC ] = 0x0000;
2559 pData->aBCR[BCR_BSBC ] = 0x9001;
2560 pData->aBCR[BCR_EECAS] = 0x0002;
2561 pData->aBCR[BCR_SWS ] = 0x0200;
2562 pData->iLog2DescSize = 3;
2563 pData->aBCR[BCR_PLAT ] = 0xff06;
2564
2565 pcnetSoftReset(pData);
2566}
2567#endif /* IN_RING3 */
2568
2569static void pcnetAPROMWriteU8(PCNetState *pData, uint32_t addr, uint32_t val)
2570{
2571 addr &= 0x0f;
2572 val &= 0xff;
2573 Log(("#%d pcnetAPROMWriteU8: addr=0x%08x val=0x%02x\n", PCNETSTATE_2_DEVINS(pData)->iInstance,
2574 addr, val));
2575 /* Check APROMWE bit to enable write access */
2576 if (pcnetBCRReadU16(pData, 2) & 0x80)
2577 pData->aPROM[addr] = val;
2578}
2579
2580static uint32_t pcnetAPROMReadU8(PCNetState *pData, uint32_t addr)
2581{
2582 uint32_t val = pData->aPROM[addr &= 0x0f];
2583 Log(("#%d pcnetAPROMReadU8: addr=0x%08x val=0x%02x\n", PCNETSTATE_2_DEVINS(pData)->iInstance,
2584 addr, val));
2585 return val;
2586}
2587
2588static int pcnetIoportWriteU16(PCNetState *pData, uint32_t addr, uint32_t val)
2589{
2590 int rc = VINF_SUCCESS;
2591
2592#ifdef PCNET_DEBUG_IO
2593 Log(("#%d pcnetIoportWriteU16: addr=0x%08x val=0x%04x\n", PCNETSTATE_2_DEVINS(pData)->iInstance,
2594 addr, val));
2595#endif
2596 if (!BCR_DWIO(pData))
2597 {
2598 switch (addr & 0x0f)
2599 {
2600 case 0x00: /* RDP */
2601 pcnetPollTimer(pData);
2602 rc = pcnetCSRWriteU16(pData, pData->u32RAP, val);
2603 pcnetUpdateIrq(pData);
2604 break;
2605 case 0x02: /* RAP */
2606 pData->u32RAP = val & 0x7f;
2607 break;
2608 case 0x06: /* BDP */
2609 rc = pcnetBCRWriteU16(pData, pData->u32RAP, val);
2610 break;
2611 }
2612 }
2613
2614 return rc;
2615}
2616
2617static uint32_t pcnetIoportReadU16(PCNetState *pData, uint32_t addr, int *pRC)
2618{
2619 uint32_t val = ~0U;
2620
2621 *pRC = VINF_SUCCESS;
2622
2623 if (!BCR_DWIO(pData))
2624 {
2625 switch (addr & 0x0f)
2626 {
2627 case 0x00: /* RDP */
2628#ifndef PCNET_NO_POLLING
2629 pcnetPollTimer(pData);
2630#endif
2631 val = pcnetCSRReadU16(pData, pData->u32RAP);
2632 if (pData->u32RAP == 0) // pcnetUpdateIrq() already called by pcnetCSRReadU16()
2633 goto skip_update_irq;
2634 break;
2635 case 0x02: /* RAP */
2636 val = pData->u32RAP;
2637 goto skip_update_irq;
2638 case 0x04: /* RESET */
2639 pcnetSoftReset(pData);
2640 val = 0;
2641 break;
2642 case 0x06: /* BDP */
2643 val = pcnetBCRReadU16(pData, pData->u32RAP);
2644 break;
2645 }
2646 }
2647#ifndef PCNET_NO_POLLING
2648 pcnetUpdateIrq(pData);
2649#endif
2650
2651skip_update_irq:
2652#ifdef PCNET_DEBUG_IO
2653 Log(("#%d pcnetIoportReadU16: addr=0x%08x val=0x%04x\n", PCNETSTATE_2_DEVINS(pData)->iInstance,
2654 addr, val & 0xffff));
2655#endif
2656 return val;
2657}
2658
2659static int pcnetIoportWriteU32(PCNetState *pData, uint32_t addr, uint32_t val)
2660{
2661 int rc = VINF_SUCCESS;
2662
2663#ifdef PCNET_DEBUG_IO
2664 Log(("#%d pcnetIoportWriteU32: addr=0x%08x val=0x%08x\n", PCNETSTATE_2_DEVINS(pData)->iInstance,
2665 addr, val));
2666#endif
2667 if (RT_LIKELY(BCR_DWIO(pData)))
2668 {
2669 switch (addr & 0x0f)
2670 {
2671 case 0x00: /* RDP */
2672 pcnetPollTimer(pData);
2673 rc = pcnetCSRWriteU16(pData, pData->u32RAP, val & 0xffff);
2674 pcnetUpdateIrq(pData);
2675 break;
2676 case 0x04: /* RAP */
2677 pData->u32RAP = val & 0x7f;
2678 break;
2679 case 0x0c: /* BDP */
2680 rc = pcnetBCRWriteU16(pData, pData->u32RAP, val & 0xffff);
2681 break;
2682 }
2683 }
2684 else if (addr == 0)
2685 {
2686 /* switch device to dword I/O mode */
2687 pcnetBCRWriteU16(pData, BCR_BSBC, pcnetBCRReadU16(pData, BCR_BSBC) | 0x0080);
2688#ifdef PCNET_DEBUG_IO
2689 Log(("device switched into dword i/o mode\n"));
2690#endif
2691 }
2692
2693 return rc;
2694}
2695
2696static uint32_t pcnetIoportReadU32(PCNetState *pData, uint32_t addr, int *pRC)
2697{
2698 uint32_t val = ~0U;
2699
2700 *pRC = VINF_SUCCESS;
2701
2702 if (RT_LIKELY(BCR_DWIO(pData)))
2703 {
2704 switch (addr & 0x0f)
2705 {
2706 case 0x00: /* RDP */
2707#ifndef PCNET_NO_POLLING
2708 pcnetPollTimer(pData);
2709#endif
2710 val = pcnetCSRReadU16(pData, pData->u32RAP);
2711 if (pData->u32RAP == 0) // pcnetUpdateIrq() already called by pcnetCSRReadU16()
2712 goto skip_update_irq;
2713 break;
2714 case 0x04: /* RAP */
2715 val = pData->u32RAP;
2716 goto skip_update_irq;
2717 case 0x08: /* RESET */
2718 pcnetSoftReset(pData);
2719 val = 0;
2720 break;
2721 case 0x0c: /* BDP */
2722 val = pcnetBCRReadU16(pData, pData->u32RAP);
2723 break;
2724 }
2725 }
2726#ifndef PCNET_NO_POLLING
2727 pcnetUpdateIrq(pData);
2728#endif
2729
2730skip_update_irq:
2731#ifdef PCNET_DEBUG_IO
2732 Log(("#%d pcnetIoportReadU32: addr=0x%08x val=0x%08x\n", PCNETSTATE_2_DEVINS(pData)->iInstance,
2733 addr, val));
2734#endif
2735 return val;
2736}
2737
2738static void pcnetMMIOWriteU8(PCNetState *pData, RTGCPHYS addr, uint32_t val)
2739{
2740#ifdef PCNET_DEBUG_IO
2741 Log(("#%d pcnetMMIOWriteU8: addr=0x%08x val=0x%02x\n", PCNETSTATE_2_DEVINS(pData)->iInstance,
2742 addr, val));
2743#endif
2744 if (!(addr & 0x10))
2745 pcnetAPROMWriteU8(pData, addr, val);
2746}
2747
2748static uint32_t pcnetMMIOReadU8(PCNetState *pData, RTGCPHYS addr)
2749{
2750 uint32_t val = ~0U;
2751 if (!(addr & 0x10))
2752 val = pcnetAPROMReadU8(pData, addr);
2753#ifdef PCNET_DEBUG_IO
2754 Log(("#%d pcnetMMIOReadU8: addr=0x%08x val=0x%02x\n", PCNETSTATE_2_DEVINS(pData)->iInstance,
2755 addr, val & 0xff));
2756#endif
2757 return val;
2758}
2759
2760static void pcnetMMIOWriteU16(PCNetState *pData, RTGCPHYS addr, uint32_t val)
2761{
2762#ifdef PCNET_DEBUG_IO
2763 Log(("#%d pcnetMMIOWriteU16: addr=0x%08x val=0x%04x\n", PCNETSTATE_2_DEVINS(pData)->iInstance,
2764 addr, val));
2765#endif
2766 if (addr & 0x10)
2767 pcnetIoportWriteU16(pData, addr & 0x0f, val);
2768 else
2769 {
2770 pcnetAPROMWriteU8(pData, addr, val );
2771 pcnetAPROMWriteU8(pData, addr+1, val >> 8);
2772 }
2773}
2774
2775static uint32_t pcnetMMIOReadU16(PCNetState *pData, RTGCPHYS addr)
2776{
2777 uint32_t val = ~0U;
2778 int rc;
2779
2780 if (addr & 0x10)
2781 val = pcnetIoportReadU16(pData, addr & 0x0f, &rc);
2782 else
2783 {
2784 val = pcnetAPROMReadU8(pData, addr+1);
2785 val <<= 8;
2786 val |= pcnetAPROMReadU8(pData, addr);
2787 }
2788#ifdef PCNET_DEBUG_IO
2789 Log(("#%d pcnetMMIOReadU16: addr=0x%08x val = 0x%04x\n", PCNETSTATE_2_DEVINS(pData)->iInstance,
2790 addr, val & 0xffff));
2791#endif
2792 return val;
2793}
2794
2795static void pcnetMMIOWriteU32(PCNetState *pData, RTGCPHYS addr, uint32_t val)
2796{
2797#ifdef PCNET_DEBUG_IO
2798 Log(("#%d pcnetMMIOWriteU32: addr=0x%08x val=0x%08x\n", PCNETSTATE_2_DEVINS(pData)->iInstance,
2799 addr, val));
2800#endif
2801 if (addr & 0x10)
2802 pcnetIoportWriteU32(pData, addr & 0x0f, val);
2803 else
2804 {
2805 pcnetAPROMWriteU8(pData, addr, val );
2806 pcnetAPROMWriteU8(pData, addr+1, val >> 8);
2807 pcnetAPROMWriteU8(pData, addr+2, val >> 16);
2808 pcnetAPROMWriteU8(pData, addr+3, val >> 24);
2809 }
2810}
2811
2812static uint32_t pcnetMMIOReadU32(PCNetState *pData, RTGCPHYS addr)
2813{
2814 uint32_t val;
2815 int rc;
2816
2817 if (addr & 0x10)
2818 val = pcnetIoportReadU32(pData, addr & 0x0f, &rc);
2819 else
2820 {
2821 val = pcnetAPROMReadU8(pData, addr+3);
2822 val <<= 8;
2823 val |= pcnetAPROMReadU8(pData, addr+2);
2824 val <<= 8;
2825 val |= pcnetAPROMReadU8(pData, addr+1);
2826 val <<= 8;
2827 val |= pcnetAPROMReadU8(pData, addr );
2828 }
2829#ifdef PCNET_DEBUG_IO
2830 Log(("#%d pcnetMMIOReadU32: addr=0x%08x val=0x%08x\n", PCNETSTATE_2_DEVINS(pData)->iInstance,
2831 addr, val));
2832#endif
2833 return val;
2834}
2835
2836
2837/**
2838 * Port I/O Handler for IN operations.
2839 *
2840 * @returns VBox status code.
2841 *
2842 * @param pDevIns The device instance.
2843 * @param pvUser User argument.
2844 * @param Port Port number used for the IN operation.
2845 * @param pu32 Where to store the result.
2846 * @param cb Number of bytes read.
2847 */
2848PDMBOTHCBDECL(int) pcnetIOPortAPromRead(PPDMDEVINS pDevIns, void *pvUser,
2849 RTIOPORT Port, uint32_t *pu32, unsigned cb)
2850{
2851 PCNetState *pData = PDMINS2DATA(pDevIns, PCNetState *);
2852 int rc;
2853 if (cb == 1)
2854 {
2855 STAM_PROFILE_ADV_START(&pData->StatAPROMRead, a);
2856 rc = PDMCritSectEnter(&pData->CritSect, VINF_IOM_HC_IOPORT_WRITE);
2857 if (rc == VINF_SUCCESS)
2858 {
2859 *pu32 = pcnetAPROMReadU8(pData, Port);
2860 PDMCritSectLeave(&pData->CritSect);
2861 }
2862 STAM_PROFILE_ADV_STOP(&pData->StatAPROMRead, a);
2863 }
2864 else
2865 rc = VERR_IOM_IOPORT_UNUSED;
2866 LogFlow(("#%d pcnetIOPortAPromRead: Port=%RTiop *pu32=%#RX32 cb=%d rc=%Vrc\n",
2867 PCNETSTATE_2_DEVINS(pData)->iInstance, Port, *pu32, cb, rc));
2868 return rc;
2869}
2870
2871
2872/**
2873 * Port I/O Handler for OUT operations.
2874 *
2875 * @returns VBox status code.
2876 *
2877 * @param pDevIns The device instance.
2878 * @param pvUser User argument.
2879 * @param Port Port number used for the IN operation.
2880 * @param u32 The value to output.
2881 * @param cb The value size in bytes.
2882 */
2883PDMBOTHCBDECL(int) pcnetIOPortAPromWrite(PPDMDEVINS pDevIns, void *pvUser,
2884 RTIOPORT Port, uint32_t u32, unsigned cb)
2885{
2886 PCNetState *pData = PDMINS2DATA(pDevIns, PCNetState *);
2887 int rc;
2888
2889 if (cb == 1)
2890 {
2891 STAM_PROFILE_ADV_START(&pData->StatAPROMWrite, a);
2892 rc = PDMCritSectEnter(&pData->CritSect, VINF_IOM_HC_IOPORT_WRITE);
2893 if (rc == VINF_SUCCESS)
2894 {
2895 pcnetAPROMWriteU8(pData, Port, u32);
2896 PDMCritSectLeave(&pData->CritSect);
2897 }
2898 STAM_PROFILE_ADV_STOP(&pData->StatAPROMWrite, a);
2899 }
2900 else
2901 {
2902 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
2903 rc = VINF_SUCCESS;
2904 }
2905 LogFlow(("#%d pcnetIOPortAPromWrite: Port=%RTiop u32=%#RX32 cb=%d rc=%Vrc\n",
2906 PCNETSTATE_2_DEVINS(pData)->iInstance, Port, u32, cb, rc));
2907 return rc;
2908}
2909
2910
2911/**
2912 * Port I/O Handler for IN operations.
2913 *
2914 * @returns VBox status code.
2915 *
2916 * @param pDevIns The device instance.
2917 * @param pvUser User argument.
2918 * @param Port Port number used for the IN operation.
2919 * @param pu32 Where to store the result.
2920 * @param cb Number of bytes read.
2921 */
2922PDMBOTHCBDECL(int) pcnetIOPortRead(PPDMDEVINS pDevIns, void *pvUser,
2923 RTIOPORT Port, uint32_t *pu32, unsigned cb)
2924{
2925 PCNetState *pData = PDMINS2DATA(pDevIns, PCNetState *);
2926 int rc = VINF_SUCCESS;
2927
2928 STAM_PROFILE_ADV_START(&pData->CTXSUFF(StatIORead), a);
2929 rc = PDMCritSectEnter(&pData->CritSect, VINF_IOM_HC_IOPORT_READ);
2930 if (rc == VINF_SUCCESS)
2931 {
2932 switch (cb)
2933 {
2934 case 2: *pu32 = pcnetIoportReadU16(pData, Port, &rc); break;
2935 case 4: *pu32 = pcnetIoportReadU32(pData, Port, &rc); break;
2936 default:
2937 rc = VERR_IOM_IOPORT_UNUSED;
2938 break;
2939 }
2940 PDMCritSectLeave(&pData->CritSect);
2941 }
2942 STAM_PROFILE_ADV_STOP(&pData->CTXSUFF(StatIORead), a);
2943 LogFlow(("#%d pcnetIOPortRead: Port=%RTiop *pu32=%#RX32 cb=%d rc=%Vrc\n",
2944 PCNETSTATE_2_DEVINS(pData)->iInstance, Port, *pu32, cb, rc));
2945 return rc;
2946}
2947
2948
2949/**
2950 * Port I/O Handler for OUT operations.
2951 *
2952 * @returns VBox status code.
2953 *
2954 * @param pDevIns The device instance.
2955 * @param pvUser User argument.
2956 * @param Port Port number used for the IN operation.
2957 * @param u32 The value to output.
2958 * @param cb The value size in bytes.
2959 */
2960PDMBOTHCBDECL(int) pcnetIOPortWrite(PPDMDEVINS pDevIns, void *pvUser,
2961 RTIOPORT Port, uint32_t u32, unsigned cb)
2962{
2963 PCNetState *pData = PDMINS2DATA(pDevIns, PCNetState *);
2964 int rc = VINF_SUCCESS;
2965
2966 STAM_PROFILE_ADV_START(&pData->CTXSUFF(StatIOWrite), a);
2967 rc = PDMCritSectEnter(&pData->CritSect, VINF_IOM_HC_IOPORT_WRITE);
2968 if (rc == VINF_SUCCESS)
2969 {
2970 switch (cb)
2971 {
2972 case 2: rc = pcnetIoportWriteU16(pData, Port, u32); break;
2973 case 4: rc = pcnetIoportWriteU32(pData, Port, u32); break;
2974 default:
2975 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
2976 rc = VERR_INTERNAL_ERROR;
2977 break;
2978 }
2979 PDMCritSectLeave(&pData->CritSect);
2980 }
2981 STAM_PROFILE_ADV_STOP(&pData->CTXSUFF(StatIOWrite), a);
2982 LogFlow(("#%d pcnetIOPortWrite: Port=%RTiop u32=%#RX32 cb=%d rc=%Vrc\n",
2983 PCNETSTATE_2_DEVINS(pData)->iInstance, Port, u32, cb, rc));
2984 return rc;
2985}
2986
2987
2988/**
2989 * Memory mapped I/O Handler for read operations.
2990 *
2991 * @returns VBox status code.
2992 *
2993 * @param pDevIns The device instance.
2994 * @param pvUser User argument.
2995 * @param GCPhysAddr Physical address (in GC) where the read starts.
2996 * @param pv Where to store the result.
2997 * @param cb Number of bytes read.
2998 */
2999PDMBOTHCBDECL(int) pcnetMMIORead(PPDMDEVINS pDevIns, void *pvUser,
3000 RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
3001{
3002 PCNetState *pData = (PCNetState *)pvUser;
3003 int rc = VINF_SUCCESS;
3004
3005 /*
3006 * We have to check the range, because we're page aligning the MMIO stuff presently.
3007 */
3008 if (GCPhysAddr - pData->MMIOBase < PCNET_PNPMMIO_SIZE)
3009 {
3010 STAM_PROFILE_ADV_START(&pData->CTXSUFF(StatMMIORead), a);
3011 rc = PDMCritSectEnter(&pData->CritSect, VINF_IOM_HC_MMIO_READ);
3012 if (rc == VINF_SUCCESS)
3013 {
3014 switch (cb)
3015 {
3016 case 1: *(uint8_t *)pv = pcnetMMIOReadU8 (pData, GCPhysAddr); break;
3017 case 2: *(uint16_t *)pv = pcnetMMIOReadU16(pData, GCPhysAddr); break;
3018 case 4: *(uint32_t *)pv = pcnetMMIOReadU32(pData, GCPhysAddr); break;
3019 default:
3020 AssertMsgFailed(("cb=%d\n", cb));
3021 rc = VERR_INTERNAL_ERROR;
3022 break;
3023 }
3024 PDMCritSectLeave(&pData->CritSect);
3025 }
3026 STAM_PROFILE_ADV_STOP(&pData->CTXSUFF(StatMMIORead), a);
3027 }
3028 else
3029 memset(pv, 0, cb);
3030
3031 LogFlow(("#%d pcnetMMIORead: pvUser=%p:{%.*Rhxs} cb=%d GCPhysAddr=%RGp rc=%Vrc\n",
3032 PCNETSTATE_2_DEVINS(pData)->iInstance, pv, cb, pv, cb, GCPhysAddr, rc));
3033 return rc;
3034}
3035
3036
3037/**
3038 * Port I/O Handler for write operations.
3039 *
3040 * @returns VBox status code.
3041 *
3042 * @param pDevIns The device instance.
3043 * @param pvUser User argument.
3044 * @param GCPhysAddr Physical address (in GC) where the read starts.
3045 * @param pv Where to fetch the result.
3046 * @param cb Number of bytes to write.
3047 */
3048PDMBOTHCBDECL(int) pcnetMMIOWrite(PPDMDEVINS pDevIns, void *pvUser,
3049 RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
3050{
3051 PCNetState *pData = (PCNetState *)pvUser;
3052 int rc = VINF_SUCCESS;
3053
3054 /*
3055 * We have to check the range, because we're page aligning the MMIO stuff presently.
3056 */
3057 if (GCPhysAddr - pData->MMIOBase < PCNET_PNPMMIO_SIZE)
3058 {
3059 STAM_PROFILE_ADV_START(&pData->CTXSUFF(StatMMIOWrite), a);
3060 rc = PDMCritSectEnter(&pData->CritSect, VINF_IOM_HC_MMIO_WRITE);
3061 if (rc == VINF_SUCCESS)
3062 {
3063 switch (cb)
3064 {
3065 case 1: pcnetMMIOWriteU8 (pData, GCPhysAddr, *(uint8_t *)pv); break;
3066 case 2: pcnetMMIOWriteU16(pData, GCPhysAddr, *(uint16_t *)pv); break;
3067 case 4: pcnetMMIOWriteU32(pData, GCPhysAddr, *(uint32_t *)pv); break;
3068 default:
3069 AssertMsgFailed(("cb=%d\n", cb));
3070 rc = VERR_INTERNAL_ERROR;
3071 break;
3072 }
3073 PDMCritSectLeave(&pData->CritSect);
3074 }
3075 // else rc == VINF_IOM_HC_MMIO_WRITE => handle in ring3
3076
3077 STAM_PROFILE_ADV_STOP(&pData->CTXSUFF(StatMMIOWrite), a);
3078 }
3079 LogFlow(("#%d pcnetMMIOWrite: pvUser=%p:{%.*Rhxs} cb=%d GCPhysAddr=%RGp rc=%Vrc\n",
3080 PCNETSTATE_2_DEVINS(pData)->iInstance, pv, cb, pv, cb, GCPhysAddr, rc));
3081 return rc;
3082}
3083
3084
3085#ifdef IN_RING3
3086/**
3087 * Device timer callback function.
3088 *
3089 * @param pDevIns Device instance of the device which registered the timer.
3090 * @param pTimer The timer handle.
3091 * @thread EMT
3092 */
3093static DECLCALLBACK(void) pcnetTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer)
3094{
3095 PCNetState *pData = PDMINS2DATA(pDevIns, PCNetState *);
3096 int rc;
3097
3098 STAM_PROFILE_ADV_START(&pData->StatTimer, a);
3099 rc = PDMCritSectEnter(&pData->CritSect, VERR_PERMISSION_DENIED);
3100 AssertReleaseRC(rc);
3101
3102 pcnetPollTimer(pData);
3103
3104 PDMCritSectLeave(&pData->CritSect);
3105 STAM_PROFILE_ADV_STOP(&pData->StatTimer, a);
3106}
3107
3108
3109/**
3110 * Restore timer callback.
3111 *
3112 * This is only called when've restored a saved state and temporarily
3113 * disconnected the network link to inform the guest that network connections
3114 * should be considered lost.
3115 *
3116 * @param pDevIns Device instance of the device which registered the timer.
3117 * @param pTimer The timer handle.
3118 */
3119static DECLCALLBACK(void) pcnetTimerRestore(PPDMDEVINS pDevIns, PTMTIMER pTimer)
3120{
3121 PCNetState *pData = PDMINS2DATA(pDevIns, PCNetState *);
3122 int rc = PDMCritSectEnter(&pData->CritSect, VERR_PERMISSION_DENIED);
3123 AssertReleaseRC(rc);
3124
3125 rc = VERR_GENERAL_FAILURE;
3126 if (pData->cLinkDownReported <= 3)
3127 rc = TMTimerSetMillies(pData->pTimerRestore, 1500);
3128 if (VBOX_FAILURE(rc))
3129 {
3130 pData->fLinkTempDown = false;
3131 if (pData->fLinkUp)
3132 {
3133 LogRel(("PCNet#%d: The link is back up again after the restore.\n",
3134 pDevIns->iInstance));
3135 Log(("#%d pcnetTimerRestore: Clearing ERR and CERR after load. cLinkDownReported=%d\n",
3136 pDevIns->iInstance, pData->cLinkDownReported));
3137 pData->aCSR[0] &= ~(BIT(15) | BIT(13)); /* ERR | CERR - probably not 100% correct either... */
3138 pData->Led.Actual.s.fError = 0;
3139 }
3140 }
3141 else
3142 Log(("#%d pcnetTimerRestore: cLinkDownReported=%d, wait another 1500ms...\n",
3143 pDevIns->iInstance, pData->cLinkDownReported));
3144
3145 PDMCritSectLeave(&pData->CritSect);
3146}
3147
3148
3149/**
3150 * Callback function for mapping an PCI I/O region.
3151 *
3152 * @return VBox status code.
3153 * @param pPciDev Pointer to PCI device. Use pPciDev->pDevIns to get the device instance.
3154 * @param iRegion The region number.
3155 * @param GCPhysAddress Physical address of the region. If iType is PCI_ADDRESS_SPACE_IO, this is an
3156 * I/O port, else it's a physical address.
3157 * This address is *NOT* relative to pci_mem_base like earlier!
3158 * @param cb Region size.
3159 * @param enmType One of the PCI_ADDRESS_SPACE_* values.
3160 */
3161static DECLCALLBACK(int) pcnetIOPortMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion,
3162 RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
3163{
3164 int rc;
3165 PPDMDEVINS pDevIns = pPciDev->pDevIns;
3166 RTIOPORT Port = (RTIOPORT)GCPhysAddress;
3167 PCNetState *pData = PCIDEV_2_PCNETSTATE(pPciDev);
3168
3169 Assert(enmType == PCI_ADDRESS_SPACE_IO);
3170 Assert(cb >= 0x20);
3171
3172 rc = PDMDevHlpIOPortRegister(pDevIns, Port, 0x10, 0, pcnetIOPortAPromWrite,
3173 pcnetIOPortAPromRead, NULL, NULL, "PCNet ARPOM");
3174 if (VBOX_FAILURE(rc))
3175 return rc;
3176 rc = PDMDevHlpIOPortRegister(pDevIns, Port + 0x10, 0x10, 0, pcnetIOPortWrite,
3177 pcnetIOPortRead, NULL, NULL, "PCNet");
3178 if (VBOX_FAILURE(rc))
3179 return rc;
3180
3181 if (pData->fGCEnabled)
3182 {
3183 rc = PDMDevHlpIOPortRegisterGC(pDevIns, Port, 0x10, 0, "pcnetIOPortAPromWrite",
3184 "pcnetIOPortAPromRead", NULL, NULL, "PCNet aprom");
3185 if (VBOX_FAILURE(rc))
3186 return rc;
3187 rc = PDMDevHlpIOPortRegisterGC(pDevIns, Port + 0x10, 0x10, 0, "pcnetIOPortWrite",
3188 "pcnetIOPortRead", NULL, NULL, "PCNet");
3189 if (VBOX_FAILURE(rc))
3190 return rc;
3191 }
3192 if (pData->fR0Enabled)
3193 {
3194 rc = PDMDevHlpIOPortRegisterR0(pDevIns, Port, 0x10, 0, "pcnetIOPortAPromWrite",
3195 "pcnetIOPortAPromRead", NULL, NULL, "PCNet aprom");
3196 if (VBOX_FAILURE(rc))
3197 return rc;
3198 rc = PDMDevHlpIOPortRegisterR0(pDevIns, Port + 0x10, 0x10, 0, "pcnetIOPortWrite",
3199 "pcnetIOPortRead", NULL, NULL, "PCNet");
3200 if (VBOX_FAILURE(rc))
3201 return rc;
3202 }
3203
3204 pData->IOPortBase = Port;
3205 return VINF_SUCCESS;
3206}
3207
3208
3209/**
3210 * Callback function for mapping the MMIO region.
3211 *
3212 * @return VBox status code.
3213 * @param pPciDev Pointer to PCI device. Use pPciDev->pDevIns to get the device instance.
3214 * @param iRegion The region number.
3215 * @param GCPhysAddress Physical address of the region. If iType is PCI_ADDRESS_SPACE_IO, this is an
3216 * I/O port, else it's a physical address.
3217 * This address is *NOT* relative to pci_mem_base like earlier!
3218 * @param cb Region size.
3219 * @param enmType One of the PCI_ADDRESS_SPACE_* values.
3220 */
3221static DECLCALLBACK(int) pcnetMMIOMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion,
3222 RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
3223{
3224 PCNetState *pData = PCIDEV_2_PCNETSTATE(pPciDev);
3225 int rc;
3226
3227 Assert(enmType == PCI_ADDRESS_SPACE_MEM);
3228 Assert(cb >= PCNET_PNPMMIO_SIZE);
3229
3230 /* We use the assigned size here, because we currently only support page aligned MMIO ranges. */
3231 rc = PDMDevHlpMMIORegister(pPciDev->pDevIns, GCPhysAddress, cb, pData,
3232 pcnetMMIOWrite, pcnetMMIORead, NULL, "PCNet");
3233 if (VBOX_FAILURE(rc))
3234 return rc;
3235 pData->MMIOBase = GCPhysAddress;
3236 return rc;
3237}
3238
3239
3240/**
3241 * PCNET status info callback.
3242 *
3243 * @param pDevIns The device instance.
3244 * @param pHlp The output helpers.
3245 * @param pszArgs The arguments.
3246 */
3247static DECLCALLBACK(void) pcnetInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
3248{
3249 PCNetState *pData = PDMINS2DATA(pDevIns, PCNetState *);
3250 bool fRcvRing = false;
3251 bool fXmtRing = false;
3252
3253 /*
3254 * Parse args.
3255 */
3256 if (pszArgs)
3257 {
3258 fRcvRing = strstr(pszArgs, "verbose") || strstr(pszArgs, "rcv");
3259 fXmtRing = strstr(pszArgs, "verbose") || strstr(pszArgs, "xmt");
3260 }
3261
3262 /*
3263 * Show info.
3264 */
3265 pHlp->pfnPrintf(pHlp,
3266 "pcnet #%d: port=%RTiop mmio=%RGp mac-cfg=%.*Rhxs %s\n",
3267 pDevIns->iInstance,
3268 pData->IOPortBase, pData->MMIOBase, sizeof(pData->MacConfigured), &pData->MacConfigured,
3269 pData->fAm79C973 ? "Am79C973" : "Am79C970A", pData->fGCEnabled ? " GC" : "", pData->fR0Enabled ? " R0" : "");
3270
3271 PDMCritSectEnter(&pData->CritSect, VERR_INTERNAL_ERROR); /* Take it here so we know why we're hanging... */
3272
3273 pHlp->pfnPrintf(pHlp,
3274 "CSR0=%04RX32:\n",
3275 pData->aCSR[0]);
3276
3277 pHlp->pfnPrintf(pHlp,
3278 "CSR1=%04RX32:\n",
3279 pData->aCSR[1]);
3280
3281 pHlp->pfnPrintf(pHlp,
3282 "CSR2=%04RX32:\n",
3283 pData->aCSR[2]);
3284
3285 pHlp->pfnPrintf(pHlp,
3286 "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",
3287 pData->aCSR[3],
3288 !!(pData->aCSR[3] & BIT(2)), !!(pData->aCSR[3] & BIT(3)), !!(pData->aCSR[3] & BIT(4)), CSR_LAPPEN(pData),
3289 CSR_DXSUFLO(pData), !!(pData->aCSR[3] & BIT(8)), !!(pData->aCSR[3] & BIT(9)), !!(pData->aCSR[3] & BIT(10)),
3290 !!(pData->aCSR[3] & BIT(11)), !!(pData->aCSR[3] & BIT(12)), !!(pData->aCSR[3] & BIT(14)));
3291
3292 pHlp->pfnPrintf(pHlp,
3293 "CSR4=%04RX32: JABM=%d JAB=%d TXSTRM=%d TXSTRT=%d RCVCOOM=%d RCVCCO=%d UINT=%d UINTCMD=%d\n"
3294 " MFCOM=%d MFCO=%d ASTRP_RCV=%d APAD_XMT=%d DPOLL=%d TIMER=%d EMAPLUS=%d EN124=%d\n",
3295 pData->aCSR[4],
3296 !!(pData->aCSR[4] & BIT( 0)), !!(pData->aCSR[4] & BIT( 1)), !!(pData->aCSR[4] & BIT( 2)), !!(pData->aCSR[4] & BIT( 3)),
3297 !!(pData->aCSR[4] & BIT( 4)), !!(pData->aCSR[4] & BIT( 5)), !!(pData->aCSR[4] & BIT( 6)), !!(pData->aCSR[4] & BIT( 7)),
3298 !!(pData->aCSR[4] & BIT( 8)), !!(pData->aCSR[4] & BIT( 9)), !!(pData->aCSR[4] & BIT(10)), !!(pData->aCSR[4] & BIT(11)),
3299 !!(pData->aCSR[4] & BIT(12)), !!(pData->aCSR[4] & BIT(13)), !!(pData->aCSR[4] & BIT(14)), !!(pData->aCSR[4] & BIT(15)));
3300
3301 pHlp->pfnPrintf(pHlp,
3302 "CSR5=%04RX32:\n",
3303 pData->aCSR[5]);
3304
3305 pHlp->pfnPrintf(pHlp,
3306 "CSR6=%04RX32: RLEN=%03x* TLEN=%03x* [* encoded]\n",
3307 pData->aCSR[6],
3308 (pData->aCSR[6] >> 8) & 0xf, (pData->aCSR[6] >> 12) & 0xf);
3309
3310 pHlp->pfnPrintf(pHlp,
3311 "CSR8..11=%04RX32,%04RX32,%04RX32,%04RX32: LADRF=%016RX64\n",
3312 pData->aCSR[8], pData->aCSR[9], pData->aCSR[10], pData->aCSR[11],
3313 (uint64_t)(pData->aCSR[ 8] & 0xffff)
3314 | (uint64_t)(pData->aCSR[ 9] & 0xffff) << 16
3315 | (uint64_t)(pData->aCSR[10] & 0xffff) << 32
3316 | (uint64_t)(pData->aCSR[11] & 0xffff) << 48);
3317
3318 pHlp->pfnPrintf(pHlp,
3319 "CSR12..14=%04RX32,%04RX32,%04RX32: PADR=%02x %02x %02x %02x %02x %02x (Current MAC Address)\n",
3320 pData->aCSR[12], pData->aCSR[13], pData->aCSR[14],
3321 pData->aCSR[12] & 0xff,
3322 (pData->aCSR[12] >> 8) & 0xff,
3323 pData->aCSR[13] & 0xff,
3324 (pData->aCSR[13] >> 8) & 0xff,
3325 pData->aCSR[14] & 0xff,
3326 (pData->aCSR[14] >> 8) & 0xff);
3327
3328 pHlp->pfnPrintf(pHlp,
3329 "CSR15=%04RX32: DXR=%d DTX=%d LOOP=%d DXMTFCS=%d FCOLL=%d DRTY=%d INTL=%d PORTSEL=%d LTR=%d\n"
3330 " MENDECL=%d DAPC=%d DLNKTST=%d DRCVPV=%d DRCVBC=%d PROM=%d\n",
3331 pData->aCSR[15],
3332 !!(pData->aCSR[15] & BIT( 0)), !!(pData->aCSR[15] & BIT( 1)), !!(pData->aCSR[15] & BIT( 2)), !!(pData->aCSR[15] & BIT( 3)),
3333 !!(pData->aCSR[15] & BIT( 4)), !!(pData->aCSR[15] & BIT( 5)), !!(pData->aCSR[15] & BIT( 6)), (pData->aCSR[15] >> 7) & 3,
3334 !!(pData->aCSR[15] & BIT( 9)), !!(pData->aCSR[15] & BIT(10)), !!(pData->aCSR[15] & BIT(11)),
3335 !!(pData->aCSR[15] & BIT(12)), !!(pData->aCSR[15] & BIT(13)), !!(pData->aCSR[15] & BIT(14)), !!(pData->aCSR[15] & BIT(15)));
3336
3337 pHlp->pfnPrintf(pHlp,
3338 "CSR46=%04RX32: POLL=%04x (Poll Time Counter)\n",
3339 pData->aCSR[46], pData->aCSR[46] & 0xffff);
3340
3341 pHlp->pfnPrintf(pHlp,
3342 "CSR47=%04RX32: POLLINT=%04x (Poll Time Interval)\n",
3343 pData->aCSR[47], pData->aCSR[47] & 0xffff);
3344
3345 pHlp->pfnPrintf(pHlp,
3346 "CSR58=%04RX32: SWSTYLE=%02x %s SSIZE32=%d CSRPCNET=%d APERRENT=%d\n",
3347 pData->aCSR[58],
3348 pData->aCSR[58] & 0x7f,
3349 (pData->aCSR[58] & 0x7f) == 0 ? "C-LANCE / PCnet-ISA"
3350 : (pData->aCSR[58] & 0x7f) == 1 ? "ILACC"
3351 : (pData->aCSR[58] & 0x7f) == 2 ? "PCNet-PCI II"
3352 : (pData->aCSR[58] & 0x7f) == 3 ? "PCNet-PCI II controller"
3353 : "!!reserved!!",
3354 !!(pData->aCSR[58] & BIT(8)), !!(pData->aCSR[58] & BIT(9)), !!(pData->aCSR[58] & BIT(10)));
3355
3356 pHlp->pfnPrintf(pHlp,
3357 "CSR112=%04RX32: MFC=%04x (Missed receive Frame Count)\n",
3358 pData->aCSR[112], pData->aCSR[112] & 0xffff);
3359
3360 pHlp->pfnPrintf(pHlp,
3361 "CSR122=%04RX32: RCVALGN=%04x (Receive Frame Align)\n",
3362 pData->aCSR[122], !!(pData->aCSR[122] & BIT(0)));
3363
3364 pHlp->pfnPrintf(pHlp,
3365 "CSR124=%04RX32: RPA=%04x (Runt Packet Accept)\n",
3366 pData->aCSR[122], !!(pData->aCSR[122] & BIT(3)));
3367
3368
3369 /*
3370 * Dump the receive ring.
3371 */
3372 pHlp->pfnPrintf(pHlp,
3373 "RCVRL=%04x RCVRC=%04x GCRDRA=%RX32 \n"
3374 "CRDA=%08RX32 CRBA=%08RX32 CRBC=%03x CRST=%04x\n"
3375 "NRDA=%08RX32 NRBA=%08RX32 NRBC=%03x NRST=%04x\n"
3376 "NNRDA=%08RX32\n"
3377 ,
3378 CSR_RCVRL(pData), CSR_RCVRC(pData), pData->GCRDRA,
3379 CSR_CRDA(pData), CSR_CRBA(pData), CSR_CRBC(pData), CSR_CRST(pData),
3380 CSR_NRDA(pData), CSR_NRBA(pData), CSR_NRBC(pData), CSR_NRST(pData),
3381 CSR_NNRD(pData));
3382 if (fRcvRing)
3383 {
3384 const unsigned cb = 1 << pData->iLog2DescSize;
3385 RTGCPHYS GCPhys = pData->GCRDRA;
3386 unsigned i = CSR_RCVRL(pData);
3387 while (i-- > 0)
3388 {
3389 RMD rmd;
3390 pcnetRmdLoad(pData, &rmd, PHYSADDR(pData, GCPhys));
3391 pHlp->pfnPrintf(pHlp,
3392 "%04x %RGp:%c%c RBADR=%08RX32 BCNT=%03x MCNT=%03x "
3393 "OWN=%d ERR=%d FRAM=%d OFLO=%d CRC=%d BUFF=%d STP=%d ENP=%d BPE=%d "
3394 "PAM=%d LAFM=%d BAM=%d RCC=%02x RPC=%02x ONES=%x ZEROS=%d\n",
3395 i, GCPhys, i + 1 == CSR_RCVRC(pData) ? '*' : ' ', GCPhys == CSR_CRDA(pData) ? '*' : ' ',
3396 rmd.rmd0.rbadr, 4096 - rmd.rmd1.bcnt, rmd.rmd2.mcnt,
3397 rmd.rmd1.own, rmd.rmd1.err, rmd.rmd1.fram, rmd.rmd1.oflo, rmd.rmd1.crc, rmd.rmd1.buff,
3398 rmd.rmd1.stp, rmd.rmd1.enp, rmd.rmd1.bpe,
3399 rmd.rmd1.pam, rmd.rmd1.lafm, rmd.rmd1.bam, rmd.rmd2.rcc, rmd.rmd2.rpc,
3400 rmd.rmd1.ones, rmd.rmd2.zeros);
3401
3402 GCPhys += cb;
3403 }
3404 }
3405
3406 /*
3407 * Dump the transmit ring.
3408 */
3409 pHlp->pfnPrintf(pHlp,
3410 "XMTRL=%04x XMTRC=%04x GCTDRA=%08RX32 BADX=%08RX32\n"
3411 "PXDA=%08RX32 PXBC=%03x PXST=%04x\n"
3412 "CXDA=%08RX32 CXBA=%08RX32 CXBC=%03x CXST=%04x\n"
3413 "NXDA=%08RX32 NXBA=%08RX32 NXBC=%03x NXST=%04x\n"
3414 "NNXDA=%08RX32\n"
3415 ,
3416 CSR_XMTRL(pData), CSR_XMTRC(pData),
3417 pData->GCTDRA, CSR_BADX(pData),
3418 CSR_PXDA(pData), CSR_PXBC(pData), CSR_PXST(pData),
3419 CSR_CXDA(pData), CSR_CXBA(pData), CSR_CXBC(pData), CSR_CXST(pData),
3420 CSR_NXDA(pData), CSR_NXBA(pData), CSR_NXBC(pData), CSR_NXST(pData),
3421 CSR_NNXD(pData));
3422 if (fXmtRing)
3423 {
3424 const unsigned cb = 1 << pData->iLog2DescSize;
3425 RTGCPHYS GCPhys = pData->GCTDRA;
3426 unsigned i = CSR_RCVRL(pData);
3427 while (i-- > 0)
3428 {
3429 TMD tmd;
3430 pcnetTmdLoad(pData, &tmd, PHYSADDR(pData, GCPhys));
3431 pHlp->pfnPrintf(pHlp,
3432 "%04x %RGp:%c%c TBADR=%08RX32 BCNT=%03x OWN=%d "
3433 "ERR=%d NOFCS=%d LTINT=%d ONE=%d DEF=%d STP=%d ENP=%d BPE=%d "
3434 "BUFF=%d UFLO=%d EXDEF=%d LCOL=%d LCAR=%d RTRY=%d TDR=%03x TRC=%x ONES=%x\n"
3435 ,
3436 i, GCPhys, i + 1 == CSR_XMTRC(pData) ? '*' : ' ', GCPhys == CSR_CXDA(pData) ? '*' : ' ',
3437 tmd.tmd0.tbadr, 4096 - tmd.tmd1.bcnt,
3438 tmd.tmd2.tdr,
3439 tmd.tmd2.trc,
3440 tmd.tmd1.own,
3441 tmd.tmd1.err,
3442 tmd.tmd1.nofcs,
3443 tmd.tmd1.ltint,
3444 tmd.tmd1.one,
3445 tmd.tmd1.def,
3446 tmd.tmd1.stp,
3447 tmd.tmd1.enp,
3448 tmd.tmd1.bpe,
3449 tmd.tmd2.buff,
3450 tmd.tmd2.uflo,
3451 tmd.tmd2.exdef,
3452 tmd.tmd2.lcol,
3453 tmd.tmd2.lcar,
3454 tmd.tmd2.rtry,
3455 tmd.tmd2.tdr,
3456 tmd.tmd2.trc,
3457 tmd.tmd1.ones);
3458
3459 GCPhys += cb;
3460 }
3461 }
3462
3463 PDMCritSectLeave(&pData->CritSect);
3464}
3465
3466
3467/**
3468 * Saves a state of the PC-Net II device.
3469 *
3470 * @returns VBox status code.
3471 * @param pDevIns The device instance.
3472 * @param pSSMHandle The handle to save the state to.
3473 */
3474static DECLCALLBACK(int) pcnetSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle)
3475{
3476 PCNetState *pData = PDMINS2DATA(pDevIns, PCNetState *);
3477
3478 SSMR3PutBool(pSSMHandle, pData->fLinkUp);
3479 SSMR3PutU32(pSSMHandle, pData->u32RAP);
3480 SSMR3PutS32(pSSMHandle, pData->iISR);
3481 SSMR3PutU32(pSSMHandle, pData->u32Lnkst);
3482 SSMR3PutGCPhys(pSSMHandle, pData->GCRDRA);
3483 SSMR3PutGCPhys(pSSMHandle, pData->GCTDRA);
3484 SSMR3PutMem(pSSMHandle, pData->aPROM, sizeof(pData->aPROM));
3485 SSMR3PutMem(pSSMHandle, pData->aCSR, sizeof(pData->aCSR));
3486 SSMR3PutMem(pSSMHandle, pData->aBCR, sizeof(pData->aBCR));
3487 SSMR3PutMem(pSSMHandle, pData->aMII, sizeof(pData->aMII));
3488 SSMR3PutU64(pSSMHandle, pData->u64LastPoll);
3489 SSMR3PutMem(pSSMHandle, &pData->MacConfigured, sizeof(pData->MacConfigured));
3490 SSMR3PutBool(pSSMHandle, pData->fAm79C973);
3491#ifdef PCNET_NO_POLLING
3492 return VINF_SUCCESS;
3493#else
3494 return TMR3TimerSave(pData->CTXSUFF(pTimerPoll), pSSMHandle);
3495#endif
3496}
3497
3498
3499/**
3500 * Loads a saved PC-Net II device state.
3501 *
3502 * @returns VBox status code.
3503 * @param pDevIns The device instance.
3504 * @param pSSMHandle The handle to the saved state.
3505 * @param u32Version The data unit version number.
3506 */
3507static DECLCALLBACK(int) pcnetLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle, uint32_t u32Version)
3508{
3509 PCNetState *pData = PDMINS2DATA(pDevIns, PCNetState *);
3510 PDMMAC Mac;
3511 if (u32Version != PCNET_SAVEDSTATE_VERSION)
3512 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
3513
3514 /* restore data */
3515 SSMR3GetBool(pSSMHandle, &pData->fLinkUp);
3516 SSMR3GetU32(pSSMHandle, &pData->u32RAP);
3517 SSMR3GetS32(pSSMHandle, &pData->iISR);
3518 SSMR3GetU32(pSSMHandle, &pData->u32Lnkst);
3519 SSMR3GetGCPhys(pSSMHandle, &pData->GCRDRA);
3520 SSMR3GetGCPhys(pSSMHandle, &pData->GCTDRA);
3521 SSMR3GetMem(pSSMHandle, &pData->aPROM, sizeof(pData->aPROM));
3522 SSMR3GetMem(pSSMHandle, &pData->aCSR, sizeof(pData->aCSR));
3523 SSMR3GetMem(pSSMHandle, &pData->aBCR, sizeof(pData->aBCR));
3524 SSMR3GetMem(pSSMHandle, &pData->aMII, sizeof(pData->aMII));
3525 SSMR3GetU64(pSSMHandle, &pData->u64LastPoll);
3526 SSMR3GetMem(pSSMHandle, &Mac, sizeof(Mac));
3527 Assert(!memcmp(&Mac, &pData->MacConfigured, sizeof(Mac)));
3528 SSMR3GetBool(pSSMHandle, &pData->fAm79C973);
3529#ifndef PCNET_NO_POLLING
3530 TMR3TimerLoad(pData->CTXSUFF(pTimerPoll), pSSMHandle);
3531#endif
3532
3533 pData->iLog2DescSize = BCR_SWSTYLE(pData)
3534 ? 4
3535 : 3;
3536 pData->GCUpperPhys = BCR_SSIZE32(pData)
3537 ? 0
3538 : (0xff00 & (uint32_t)pData->aCSR[2]) << 16;
3539
3540 /* Initialize stuff we don't store. */
3541 pData->iFrame = 0;
3542
3543 /* update promiscuous mode. */
3544 if (pData->pDrv)
3545 pData->pDrv->pfnSetPromiscuousMode(pData->pDrv, CSR_PROM(pData));
3546
3547 /* Indicate link down to the guest OS that all network connections have been lost. */
3548 if (pData->fLinkUp)
3549 {
3550 pData->fLinkTempDown = true;
3551 pData->cLinkDownReported = 0;
3552 pData->aCSR[0] |= BIT(15) | BIT(13); /* ERR | CERR (this is probably wrong) */
3553 pData->Led.Asserted.s.fError = pData->Led.Actual.s.fError = 1;
3554 return TMTimerSetMillies(pData->pTimerRestore, 5000);
3555 }
3556 return VINF_SUCCESS;
3557}
3558
3559
3560/**
3561 * Queries an interface to the driver.
3562 *
3563 * @returns Pointer to interface.
3564 * @returns NULL if the interface was not supported by the driver.
3565 * @param pInterface Pointer to this interface structure.
3566 * @param enmInterface The requested interface identification.
3567 * @thread Any thread.
3568 */
3569static DECLCALLBACK(void *) pcnetQueryInterface(struct PDMIBASE *pInterface, PDMINTERFACE enmInterface)
3570{
3571 PCNetState *pData = (PCNetState *)((uintptr_t)pInterface - RT_OFFSETOF(PCNetState, IBase));
3572 Assert(&pData->IBase == pInterface);
3573 switch (enmInterface)
3574 {
3575 case PDMINTERFACE_BASE:
3576 return &pData->IBase;
3577 case PDMINTERFACE_NETWORK_PORT:
3578 return &pData->INetworkPort;
3579 case PDMINTERFACE_NETWORK_CONFIG:
3580 return &pData->INetworkConfig;
3581 case PDMINTERFACE_LED_PORTS:
3582 return &pData->ILeds;
3583 default:
3584 return NULL;
3585 }
3586}
3587
3588/** Converts a pointer to PCNetState::INetworkPort to a PCNetState pointer. */
3589#define INETWORKPORT_2_DATA(pInterface) ( (PCNetState *)((uintptr_t)pInterface - RT_OFFSETOF(PCNetState, INetworkPort)) )
3590
3591
3592/**
3593 * Check if the device/driver can receive data now.
3594 * This must be called before the pfnRecieve() method is called.
3595 *
3596 * @returns Number of bytes the driver can receive.
3597 * @param pInterface Pointer to the interface structure containing the called function pointer.
3598 * @thread EMT
3599 */
3600static DECLCALLBACK(size_t) pcnetCanReceive(PPDMINETWORKPORT pInterface)
3601{
3602 size_t cb;
3603 int rc;
3604 PCNetState *pData = INETWORKPORT_2_DATA(pInterface);
3605
3606 rc = PDMCritSectEnter(&pData->CritSect, VERR_PERMISSION_DENIED);
3607 AssertReleaseRC(rc);
3608
3609 cb = pcnetCanReceiveNoSync(pData);
3610
3611 PDMCritSectLeave(&pData->CritSect);
3612 return cb;
3613}
3614
3615
3616/**
3617 * Receive data from the network.
3618 *
3619 * @returns VBox status code.
3620 * @param pInterface Pointer to the interface structure containing the called function pointer.
3621 * @param pvBuf The available data.
3622 * @param cb Number of bytes available in the buffer.
3623 * @thread EMT
3624 */
3625static DECLCALLBACK(int) pcnetReceive(PPDMINETWORKPORT pInterface, const void *pvBuf, size_t cb)
3626{
3627 PCNetState *pData = INETWORKPORT_2_DATA(pInterface);
3628 int rc;
3629
3630 STAM_PROFILE_ADV_START(&pData->StatReceive, a);
3631 rc = PDMCritSectEnter(&pData->CritSect, VERR_PERMISSION_DENIED);
3632 AssertReleaseRC(rc);
3633
3634 if (cb > 70) /* unqualified guess */
3635 pData->Led.Asserted.s.fReading = pData->Led.Actual.s.fReading = 1;
3636 pcnetReceiveNoSync(pData, (const uint8_t*)pvBuf, cb);
3637 pData->Led.Actual.s.fReading = 0;
3638
3639 PDMCritSectLeave(&pData->CritSect);
3640 STAM_PROFILE_ADV_STOP(&pData->StatReceive, a);
3641
3642 return VINF_SUCCESS;
3643}
3644
3645/** Converts a pointer to PCNetState::INetworkConfig to a PCNetState pointer. */
3646#define INETWORKCONFIG_2_DATA(pInterface) ( (PCNetState *)((uintptr_t)pInterface - RT_OFFSETOF(PCNetState, INetworkConfig)) )
3647
3648
3649/**
3650 * Gets the current Media Access Control (MAC) address.
3651 *
3652 * @returns VBox status code.
3653 * @param pInterface Pointer to the interface structure containing the called function pointer.
3654 * @param pMac Where to store the MAC address.
3655 * @thread EMT
3656 */
3657static DECLCALLBACK(int) pcnetGetMac(PPDMINETWORKCONFIG pInterface, PPDMMAC *pMac)
3658{
3659 PCNetState *pData = INETWORKCONFIG_2_DATA(pInterface);
3660 memcpy(pMac, pData->aPROM, sizeof(*pMac));
3661 return VINF_SUCCESS;
3662}
3663
3664
3665/**
3666 * Gets the new link state.
3667 *
3668 * @returns The current link state.
3669 * @param pInterface Pointer to the interface structure containing the called function pointer.
3670 * @thread EMT
3671 */
3672static DECLCALLBACK(PDMNETWORKLINKSTATE) pcnetGetLinkState(PPDMINETWORKCONFIG pInterface)
3673{
3674 PCNetState *pData = INETWORKCONFIG_2_DATA(pInterface);
3675 if (pData->fLinkUp && !pData->fLinkTempDown)
3676 return PDMNETWORKLINKSTATE_UP;
3677 if (!pData->fLinkUp)
3678 return PDMNETWORKLINKSTATE_DOWN;
3679 if (pData->fLinkTempDown)
3680 return PDMNETWORKLINKSTATE_DOWN_RESUME;
3681 AssertMsgFailed(("Invalid link state!\n"));
3682 return PDMNETWORKLINKSTATE_INVALID;
3683}
3684
3685
3686/**
3687 * Sets the new link state.
3688 *
3689 * @returns VBox status code.
3690 * @param pInterface Pointer to the interface structure containing the called function pointer.
3691 * @param enmState The new link state
3692 * @thread EMT
3693 */
3694static DECLCALLBACK(int) pcnetSetLinkState(PPDMINETWORKCONFIG pInterface, PDMNETWORKLINKSTATE enmState)
3695{
3696 PCNetState *pData = INETWORKCONFIG_2_DATA(pInterface);
3697 bool fLinkUp;
3698 if ( enmState != PDMNETWORKLINKSTATE_DOWN
3699 && enmState != PDMNETWORKLINKSTATE_UP)
3700 {
3701 AssertMsgFailed(("Invalid parameter enmState=%d\n", enmState));
3702 return VERR_INVALID_PARAMETER;
3703 }
3704
3705 /* has the state changed? */
3706 fLinkUp = enmState == PDMNETWORKLINKSTATE_UP;
3707 if (pData->fLinkUp != fLinkUp)
3708 {
3709 pData->fLinkUp = fLinkUp;
3710 if (fLinkUp)
3711 {
3712 /* connect */
3713 pData->aCSR[0] &= ~(BIT(15) | BIT(13)); /* ERR | CERR - probably not 100% correct either... */
3714 pData->Led.Actual.s.fError = 0;
3715 }
3716 else
3717 {
3718 /* disconnect */
3719 pData->cLinkDownReported = 0;
3720 pData->aCSR[0] |= BIT(15) | BIT(13); /* ERR | CERR (this is probably wrong) */
3721 pData->Led.Asserted.s.fError = pData->Led.Actual.s.fError = 1;
3722 }
3723 pData->pDrv->pfnNotifyLinkChanged(pData->pDrv, enmState);
3724 }
3725 return VINF_SUCCESS;
3726}
3727
3728
3729/**
3730 * Gets the pointer to the status LED of a unit.
3731 *
3732 * @returns VBox status code.
3733 * @param pInterface Pointer to the interface structure containing the called function pointer.
3734 * @param iLUN The unit which status LED we desire.
3735 * @param ppLed Where to store the LED pointer.
3736 */
3737static DECLCALLBACK(int) pcnetQueryStatusLed(PPDMILEDPORTS pInterface, unsigned iLUN, PPDMLED *ppLed)
3738{
3739 PCNetState *pData = (PCNetState *)( (uintptr_t)pInterface - RT_OFFSETOF(PCNetState, ILeds) );
3740 if (iLUN == 0)
3741 {
3742 *ppLed = &pData->Led;
3743 return VINF_SUCCESS;
3744 }
3745 return VERR_PDM_LUN_NOT_FOUND;
3746}
3747
3748
3749/**
3750 * @copydoc FNPDMDEVRESET
3751 */
3752static DECLCALLBACK(void) pcnetReset(PPDMDEVINS pDevIns)
3753{
3754 PCNetState *pData = PDMINS2DATA(pDevIns, PCNetState *);
3755 if (pData->fLinkTempDown)
3756 {
3757 pData->cLinkDownReported = 0x10000;
3758 TMTimerStop(pData->pTimerRestore);
3759 pcnetTimerRestore(pDevIns, pData->pTimerRestore);
3760 }
3761
3762 /** @todo figure out what else which have to reset. I'm sure there is some stuff... */
3763}
3764
3765
3766/**
3767 * @copydoc FNPDMDEVRELOCATE
3768 */
3769static DECLCALLBACK(void) pcnetRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
3770{
3771 PCNetState *pData = PDMINS2DATA(pDevIns, PCNetState *);
3772 pData->pDevInsGC = PDMDEVINS_2_GCPTR(pDevIns);
3773 pData->pXmitQueueGC = PDMQueueGCPtr(pData->pXmitQueueHC);
3774 pData->pCanRxQueueGC = PDMQueueGCPtr(pData->pCanRxQueueHC);
3775#ifdef PCNET_NO_POLLING
3776 *(RTHCUINTPTR *)&pData->pfnEMInterpretInstructionGC += offDelta;
3777#else
3778 pData->pTimerPollGC = TMTimerGCPtr(pData->pTimerPollHC);
3779#endif
3780}
3781
3782
3783/**
3784 * Destruct a device instance.
3785 *
3786 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
3787 * resources can be freed correctly.
3788 *
3789 * @returns VBox status.
3790 * @param pDevIns The device instance data.
3791 */
3792static DECLCALLBACK(int) pcnetDestruct(PPDMDEVINS pDevIns)
3793{
3794 PCNetState *pData = PDMINS2DATA(pDevIns, PCNetState *);
3795 PDMR3CritSectDelete(&pData->CritSect);
3796 return VINF_SUCCESS;
3797}
3798
3799
3800/**
3801 * Construct a device instance for a VM.
3802 *
3803 * @returns VBox status.
3804 * @param pDevIns The device instance data.
3805 * If the registration structure is needed, pDevIns->pDevReg points to it.
3806 * @param iInstance Instance number. Use this to figure out which registers and such to use.
3807 * The device number is also found in pDevIns->iInstance, but since it's
3808 * likely to be freqently used PDM passes it as parameter.
3809 * @param pCfgHandle Configuration node handle for the device. Use this to obtain the configuration
3810 * of the device instance. It's also found in pDevIns->pCfgHandle, but like
3811 * iInstance it's expected to be used a bit in this function.
3812 */
3813static DECLCALLBACK(int) pcnetConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfgHandle)
3814{
3815 PCNetState *pData = PDMINS2DATA(pDevIns, PCNetState *);
3816 PPDMIBASE pBase;
3817 char szTmp[128];
3818 int rc;
3819
3820 /* up to four instances are supported */
3821 Assert((iInstance >= 0) && (iInstance < 4));
3822
3823 Assert(RT_ELEMENTS(pData->aBCR) == BCR_MAX_RAP);
3824 Assert(RT_ELEMENTS(pData->aMII) == MII_MAX_REG);
3825 Assert(sizeof(pData->abFrameBuf) == RT_ALIGN_Z(sizeof(pData->abFrameBuf), 16));
3826
3827 /*
3828 * Validate configuration.
3829 */
3830 if (!CFGMR3AreValuesValid(pCfgHandle, "MAC\0CableConnected\0Am79C973\0GCEnabled\0R0Enabled\0"))
3831 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
3832 N_("Invalid configuraton for pcnet device"));
3833
3834 /*
3835 * Read the configuration.
3836 */
3837 rc = CFGMR3QueryBytes(pCfgHandle, "MAC", &pData->MacConfigured, sizeof(pData->MacConfigured));
3838 if (VBOX_FAILURE(rc))
3839 return PDMDEV_SET_ERROR(pDevIns, rc,
3840 N_("Configuration error: Failed to get the \"MAC\" value"));
3841 rc = CFGMR3QueryBool(pCfgHandle, "CableConnected", &pData->fLinkUp);
3842 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
3843 pData->fLinkUp = true;
3844 else if (VBOX_FAILURE(rc))
3845 return PDMDEV_SET_ERROR(pDevIns, rc,
3846 N_("Configuration error: Failed to get the \"CableConnected\" value"));
3847
3848 rc = CFGMR3QueryBool(pCfgHandle, "Am79C973", &pData->fAm79C973);
3849 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
3850 pData->fAm79C973 = false;
3851 else if (VBOX_FAILURE(rc))
3852 return PDMDEV_SET_ERROR(pDevIns, rc,
3853 N_("Configuration error: Failed to get the \"Am79C973\" value"));
3854
3855#ifdef PCNET_GC_ENABLED
3856 rc = CFGMR3QueryBool(pCfgHandle, "GCEnabled", &pData->fGCEnabled);
3857 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
3858 pData->fGCEnabled = true;
3859 else if (VBOX_FAILURE(rc))
3860 return PDMDEV_SET_ERROR(pDevIns, rc,
3861 N_("Configuration error: Failed to get the \"GCEnabled\" value"));
3862
3863 rc = CFGMR3QueryBool(pCfgHandle, "R0Enabled", &pData->fR0Enabled);
3864 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
3865 pData->fR0Enabled = true;
3866 else if (VBOX_FAILURE(rc))
3867 return PDMDEV_SET_ERROR(pDevIns, rc,
3868 N_("Configuration error: Failed to get the \"R0Enabled\" value"));
3869
3870#else /* !PCNET_GC_ENABLED */
3871 pData->fGCEnabled = false;
3872 pData->fR0Enabled = false;
3873#endif /* !PCNET_GC_ENABLED */
3874
3875
3876 /*
3877 * Initialize data (most of it anyway).
3878 */
3879 pData->pDevInsHC = pDevIns;
3880 pData->pDevInsGC = PDMDEVINS_2_GCPTR(pDevIns);
3881 pData->Led.u32Magic = PDMLED_MAGIC;
3882 /* IBase */
3883 pData->IBase.pfnQueryInterface = pcnetQueryInterface;
3884 /* INeworkPort */
3885 pData->INetworkPort.pfnCanReceive = pcnetCanReceive;
3886 pData->INetworkPort.pfnReceive = pcnetReceive;
3887 /* INetworkConfig */
3888 pData->INetworkConfig.pfnGetMac = pcnetGetMac;
3889 pData->INetworkConfig.pfnGetLinkState = pcnetGetLinkState;
3890 pData->INetworkConfig.pfnSetLinkState = pcnetSetLinkState;
3891 /* ILeds */
3892 pData->ILeds.pfnQueryStatusLed = pcnetQueryStatusLed;
3893
3894 /* PCI Device */
3895 pData->PciDev.config[0x00] = 0x22; /* vendor id */
3896 pData->PciDev.config[0x01] = 0x10;
3897 pData->PciDev.config[0x02] = 0x00; /* device id */
3898 pData->PciDev.config[0x03] = 0x20;
3899 pData->PciDev.config[0x04] = 0x07; /* command */
3900 pData->PciDev.config[0x05] = 0x00;
3901 pData->PciDev.config[0x06] = 0x80; /* status */
3902 pData->PciDev.config[0x07] = 0x02;
3903 pData->PciDev.config[0x08] = pData->fAm79C973 ? 0x30 : 0x10; /* revision */
3904 pData->PciDev.config[0x09] = 0x00;
3905 pData->PciDev.config[0x0a] = 0x00; /* ethernet network controller */
3906 pData->PciDev.config[0x0b] = 0x02;
3907 pData->PciDev.config[0x0e] = 0x00; /* header_type */
3908
3909 pData->PciDev.config[0x10] = 0x01; /* IO Base */
3910 pData->PciDev.config[0x11] = 0x00;
3911 pData->PciDev.config[0x12] = 0x00;
3912 pData->PciDev.config[0x13] = 0x00;
3913 pData->PciDev.config[0x14] = 0x00; /* MMIO Base */
3914 pData->PciDev.config[0x15] = 0x00;
3915 pData->PciDev.config[0x16] = 0x00;
3916 pData->PciDev.config[0x17] = 0x00;
3917
3918 /* subsystem and subvendor IDs */
3919 pData->PciDev.config[0x2c] = 0x22; /* subsystem vendor id */
3920 pData->PciDev.config[0x2d] = 0x10;
3921 pData->PciDev.config[0x2e] = 0x00; /* subsystem id */
3922 pData->PciDev.config[0x2f] = 0x20;
3923 pData->PciDev.config[0x3d] = 1; /* interrupt pin 0 */
3924 pData->PciDev.config[0x3e] = 0x06;
3925 pData->PciDev.config[0x3f] = 0xff;
3926
3927 /*
3928 * Register the PCI device, its I/O regions, the timer and the saved state item.
3929 */
3930 rc = PDMDevHlpPCIRegister(pDevIns, &pData->PciDev);
3931 if (VBOX_FAILURE(rc))
3932 return rc;
3933 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0, PCNET_IOPORT_SIZE,
3934 PCI_ADDRESS_SPACE_IO, pcnetIOPortMap);
3935 if (VBOX_FAILURE(rc))
3936 return rc;
3937 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 1, PCNET_PNPMMIO_SIZE,
3938 PCI_ADDRESS_SPACE_MEM, pcnetMMIOMap);
3939 if (VBOX_FAILURE(rc))
3940 return rc;
3941
3942#ifdef PCNET_NO_POLLING
3943 rc = PDMR3GetSymbolR0Lazy(pDevIns->pDevHlp->pfnGetVM(pDevIns), NULL, "EMInterpretInstruction", (void **)&pData->pfnEMInterpretInstructionR0);
3944 if (VBOX_SUCCESS(rc))
3945 {
3946 /*
3947 * Resolve the GC handler.
3948 */
3949 RTGCPTR pfnHandlerGC;
3950 rc = PDMR3GetSymbolGCLazy(pDevIns->pDevHlp->pfnGetVM(pDevIns), NULL, "EMInterpretInstruction", (RTGCPTR *)&pData->pfnEMInterpretInstructionGC);
3951 }
3952 if (VBOX_FAILURE(rc))
3953 {
3954 AssertMsgFailed(("PDMR3GetSymbolGCLazy -> %Vrc\n", rc));
3955 return rc;
3956 }
3957#else
3958 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, pcnetTimer,
3959 "PCNet Poll Timer", &pData->pTimerPollHC);
3960 if (VBOX_FAILURE(rc))
3961 {
3962 AssertMsgFailed(("pfnTMTimerCreate -> %Vrc\n", rc));
3963 return rc;
3964 }
3965#endif
3966 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, pcnetTimerRestore,
3967 "PCNet Restore Timer", &pData->pTimerRestore);
3968 if (VBOX_FAILURE(rc))
3969 {
3970 AssertMsgFailed(("pfnTMTimerCreate -> %Vrc\n", rc));
3971 return rc;
3972 }
3973/** @todo r=bird: we're not locking down pcnet properly during saving and loading! */
3974 rc = PDMDevHlpSSMRegister(pDevIns, pDevIns->pDevReg->szDeviceName, iInstance,
3975 PCNET_SAVEDSTATE_VERSION, sizeof(*pData),
3976 NULL, pcnetSaveExec, NULL,
3977 NULL, pcnetLoadExec, NULL);
3978 if (VBOX_FAILURE(rc))
3979 return rc;
3980
3981 /*
3982 * Initialize critical section.
3983 * This must of course be done before attaching drivers or anything else which can call us back..
3984 */
3985 char szName[24];
3986 RTStrPrintf(szName, sizeof(szName), "PCNet#%d", iInstance);
3987 rc = PDMDevHlpCritSectInit(pDevIns, &pData->CritSect, szName);
3988 if (VBOX_FAILURE(rc))
3989 return rc;
3990
3991 /*
3992 * Create the transmit queue.
3993 */
3994 rc = PDMDevHlpPDMQueueCreate(pDevIns, sizeof(PDMQUEUEITEMCORE), 1, 0,
3995 pcnetXmitQueueConsumer, true, &pData->pXmitQueueHC);
3996 if (VBOX_FAILURE(rc))
3997 return rc;
3998 pData->pXmitQueueGC = PDMQueueGCPtr(pData->pXmitQueueHC);
3999
4000 /*
4001 * Create the RX notifer signaller.
4002 */
4003 rc = PDMDevHlpPDMQueueCreate(pDevIns, sizeof(PDMQUEUEITEMCORE), 1, 0,
4004 pcnetCanRxQueueConsumer, true, &pData->pCanRxQueueHC);
4005 if (VBOX_FAILURE(rc))
4006 return rc;
4007 pData->pCanRxQueueGC = PDMQueueGCPtr(pData->pCanRxQueueHC);
4008
4009 /*
4010 * Register the info item.
4011 */
4012 RTStrPrintf(szTmp, sizeof(szTmp), "pcnet%d", pDevIns->iInstance);
4013 PDMDevHlpDBGFInfoRegister(pDevIns, szTmp, "PCNET info.", pcnetInfo);
4014
4015 /*
4016 * Attach status driver (optional).
4017 */
4018 rc = PDMDevHlpDriverAttach(pDevIns, PDM_STATUS_LUN, &pData->IBase, &pBase, "Status Port");
4019 if (VBOX_SUCCESS(rc))
4020 pData->pLedsConnector = (PPDMILEDCONNECTORS)
4021 pBase->pfnQueryInterface(pBase, PDMINTERFACE_LED_CONNECTORS);
4022 else if (rc != VERR_PDM_NO_ATTACHED_DRIVER)
4023 {
4024 AssertMsgFailed(("Failed to attach to status driver. rc=%Vrc\n", rc));
4025 return rc;
4026 }
4027
4028 /*
4029 * Attach driver.
4030 */
4031 rc = PDMDevHlpDriverAttach(pDevIns, 0, &pData->IBase, &pData->pDrvBase, "Network Port");
4032 if (VBOX_SUCCESS(rc))
4033 {
4034 pData->pDrv = (PPDMINETWORKCONNECTOR)
4035 pData->pDrvBase->pfnQueryInterface(pData->pDrvBase, PDMINTERFACE_NETWORK_CONNECTOR);
4036 if (!pData->pDrv)
4037 {
4038 AssertMsgFailed(("Failed to obtain the PDMINTERFACE_NETWORK_CONNECTOR interface!\n"));
4039 return VERR_PDM_MISSING_INTERFACE_BELOW;
4040 }
4041 }
4042 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
4043 Log(("No attached driver!\n"));
4044 else
4045 return rc;
4046
4047 /*
4048 * Reset the device state. (Do after attaching.)
4049 */
4050 pcnetHardReset(pData);
4051
4052#ifdef VBOX_WITH_STATISTICS
4053 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatMMIOReadGC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling MMIO reads in GC", "/Devices/PCNet%d/MMIO/ReadGC", iInstance);
4054 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatMMIOReadHC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling MMIO reads in HC", "/Devices/PCNet%d/MMIO/ReadHC", iInstance);
4055 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatMMIOWriteGC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling MMIO writes in GC", "/Devices/PCNet%d/MMIO/WriteGC", iInstance);
4056 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatMMIOWriteHC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling MMIO writes in HC", "/Devices/PCNet%d/MMIO/WriteHC", iInstance);
4057 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatAPROMRead, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling APROM reads", "/Devices/PCNet%d/IO/APROMRead", iInstance);
4058 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatAPROMWrite, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling APROM writes", "/Devices/PCNet%d/IO/APROMWrite", iInstance);
4059 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatIOReadGC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling PCNetIO reads in GC", "/Devices/PCNet%d/IO/ReadGC", iInstance);
4060 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatIOReadHC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling PCNetIO reads in HC", "/Devices/PCNet%d/IO/ReadHC", iInstance);
4061 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatIOWriteGC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling PCNet IO writes in GC", "/Devices/PCNet%d/IO/WriteGC", iInstance);
4062 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatIOWriteHC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling PCNet IO writes in HC", "/Devices/PCNet%d/IO/WriteHC", iInstance);
4063 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatTimer, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling PCNet Timer", "/Devices/PCNet%d/Timer", iInstance);
4064 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatReceive, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling PCNet receive", "/Devices/PCNet%d/Receive", iInstance);
4065 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatTransmitGC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling PCNet transmit in GC", "/Devices/PCNet%d/TransmitGC", iInstance);
4066 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatTransmitHC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling PCNet transmit in HC", "/Devices/PCNet%d/TransmitHC", iInstance);
4067 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatXmitQueue, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling PCNet xmit queue", "/Devices/PCNet%d/XmitQueue", iInstance);
4068 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatXmitQueueFlushGC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling PCNet xmit queue flushes from GC", "/Devices/PCNet%d/XmitQueueFlushGC", iInstance);
4069 unsigned i;
4070 for (i = 0; i < ELEMENTS(pData->aStatFlushCounts); i++)
4071 PDMDevHlpSTAMRegisterF(pDevIns, &pData->aStatFlushCounts[i],STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "", "/Devices/PCNet%d/FlushCounts/Depth-%d", iInstance, i);
4072 Assert(ELEMENTS(pData->aStatFlushCounts) - 1 == ELEMENTS(pData->aFrames));
4073 for (i = 0; i < ELEMENTS(pData->aStatXmitChainCounts) - 1; i++)
4074 PDMDevHlpSTAMRegisterF(pDevIns, &pData->aStatXmitChainCounts[i], STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "", "/Devices/PCNet%d/XmitChainCounts/%d", iInstance, i + 1);
4075 PDMDevHlpSTAMRegisterF(pDevIns, &pData->aStatXmitChainCounts[i], STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "", "/Devices/PCNet%d/XmitChainCounts/%d+", iInstance, i + 1);
4076 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatInterrupt, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling PCNet interrupt checks", "/Devices/PCNet%d/Interrupt", iInstance);
4077 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatPollTimer, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling PCNet poll timer", "/Devices/PCNet%d/PollTimer", iInstance);
4078 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatMIIReads, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of MII reads", "/Devices/PCNet%d/MIIReads", iInstance);
4079# ifdef PCNET_NO_POLLING
4080 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatRCVRingWrite, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of receive ring writes", "/Devices/PCNet%d/Ring/RCVWrites", iInstance);
4081 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatTXRingWrite, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of transmit ring writes", "/Devices/PCNet%d/Ring/TXWrites", iInstance);
4082 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatRingWriteHC, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of monitored ring page writes", "/Devices/PCNet%d/Ring/HC/Writes", iInstance);
4083 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatRingWriteR0, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of monitored ring page writes", "/Devices/PCNet%d/Ring/R0/Writes", iInstance);
4084 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatRingWriteGC, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of monitored ring page writes", "/Devices/PCNet%d/Ring/GC/Writes", iInstance);
4085 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatRingWriteFailedHC, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of failed ring page writes", "/Devices/PCNet%d/Ring/HC/Failed", iInstance);
4086 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatRingWriteFailedR0, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of failed ring page writes", "/Devices/PCNet%d/Ring/R0/Failed", iInstance);
4087 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatRingWriteFailedGC, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of failed ring page writes", "/Devices/PCNet%d/Ring/GC/Failed", iInstance);
4088 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatRingWriteOutsideRangeHC, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of monitored writes outside ring range", "/Devices/PCNet%d/Ring/HC/Outside", iInstance);
4089 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatRingWriteOutsideRangeR0, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of monitored writes outside ring range", "/Devices/PCNet%d/Ring/R0/Outside", iInstance);
4090 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatRingWriteOutsideRangeGC, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of monitored writes outside ring range", "/Devices/PCNet%d/Ring/GC/Outside", iInstance);
4091# endif /* PCNET_NO_POLLING */
4092#endif
4093
4094 return VINF_SUCCESS;
4095}
4096
4097
4098/**
4099 * The device registration structure.
4100 */
4101const PDMDEVREG g_DevicePCNet =
4102{
4103 /* u32Version */
4104 PDM_DEVREG_VERSION,
4105 /* szDeviceName */
4106 "pcnet",
4107 /* szGCMod */
4108#ifdef PCNET_GC_ENABLED
4109 "VBoxDDGC.gc",
4110 "VBoxDDR0.r0",
4111#else
4112 "",
4113 "",
4114#endif
4115 /* pszDescription */
4116 "AMD PC-Net II Ethernet controller.\n",
4117 /* fFlags */
4118#ifdef PCNET_GC_ENABLED
4119 PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GC | PDM_DEVREG_FLAGS_R0,
4120#else
4121 PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_DEFAULT,
4122#endif
4123 /* fClass */
4124 PDM_DEVREG_CLASS_NETWORK,
4125 /* cMaxInstances */
4126 4,
4127 /* cbInstance */
4128 sizeof(PCNetState),
4129 /* pfnConstruct */
4130 pcnetConstruct,
4131 /* pfnDestruct */
4132 pcnetDestruct,
4133 /* pfnRelocate */
4134 pcnetRelocate,
4135 /* pfnIOCtl */
4136 NULL,
4137 /* pfnPowerOn */
4138 NULL,
4139 /* pfnReset */
4140 pcnetReset,
4141 /* pfnSuspend */
4142 NULL,
4143 /* pfnResume */
4144 NULL,
4145 /* pfnAttach */
4146 NULL,
4147 /* pfnDetach */
4148 NULL,
4149 /* pfnQueryInterface. */
4150 NULL
4151};
4152
4153#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