149ab747fSPaolo Bonzini /**
249ab747fSPaolo Bonzini * QEMU RTL8139 emulation
349ab747fSPaolo Bonzini *
449ab747fSPaolo Bonzini * Copyright (c) 2006 Igor Kovalenko
549ab747fSPaolo Bonzini *
649ab747fSPaolo Bonzini * Permission is hereby granted, free of charge, to any person obtaining a copy
749ab747fSPaolo Bonzini * of this software and associated documentation files (the "Software"), to deal
849ab747fSPaolo Bonzini * in the Software without restriction, including without limitation the rights
949ab747fSPaolo Bonzini * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1049ab747fSPaolo Bonzini * copies of the Software, and to permit persons to whom the Software is
1149ab747fSPaolo Bonzini * furnished to do so, subject to the following conditions:
1249ab747fSPaolo Bonzini *
1349ab747fSPaolo Bonzini * The above copyright notice and this permission notice shall be included in
1449ab747fSPaolo Bonzini * all copies or substantial portions of the Software.
1549ab747fSPaolo Bonzini *
1649ab747fSPaolo Bonzini * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1749ab747fSPaolo Bonzini * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1849ab747fSPaolo Bonzini * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
1949ab747fSPaolo Bonzini * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2049ab747fSPaolo Bonzini * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2149ab747fSPaolo Bonzini * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2249ab747fSPaolo Bonzini * THE SOFTWARE.
2349ab747fSPaolo Bonzini
2449ab747fSPaolo Bonzini * Modifications:
2549ab747fSPaolo Bonzini * 2006-Jan-28 Mark Malakanov : TSAD and CSCR implementation (for Windows driver)
2649ab747fSPaolo Bonzini *
2749ab747fSPaolo Bonzini * 2006-Apr-28 Juergen Lock : EEPROM emulation changes for FreeBSD driver
2849ab747fSPaolo Bonzini * HW revision ID changes for FreeBSD driver
2949ab747fSPaolo Bonzini *
3049ab747fSPaolo Bonzini * 2006-Jul-01 Igor Kovalenko : Implemented loopback mode for FreeBSD driver
3149ab747fSPaolo Bonzini * Corrected packet transfer reassembly routine for 8139C+ mode
3249ab747fSPaolo Bonzini * Rearranged debugging print statements
3349ab747fSPaolo Bonzini * Implemented PCI timer interrupt (disabled by default)
3449ab747fSPaolo Bonzini * Implemented Tally Counters, increased VM load/save version
3549ab747fSPaolo Bonzini * Implemented IP/TCP/UDP checksum task offloading
3649ab747fSPaolo Bonzini *
3749ab747fSPaolo Bonzini * 2006-Jul-04 Igor Kovalenko : Implemented TCP segmentation offloading
3849ab747fSPaolo Bonzini * Fixed MTU=1500 for produced ethernet frames
3949ab747fSPaolo Bonzini *
4049ab747fSPaolo Bonzini * 2006-Jul-09 Igor Kovalenko : Fixed TCP header length calculation while processing
4149ab747fSPaolo Bonzini * segmentation offloading
4249ab747fSPaolo Bonzini * Removed slirp.h dependency
4349ab747fSPaolo Bonzini * Added rx/tx buffer reset when enabling rx/tx operation
4449ab747fSPaolo Bonzini *
4549ab747fSPaolo Bonzini * 2010-Feb-04 Frediano Ziglio: Rewrote timer support using QEMU timer only
46b6af0975SDaniel P. Berrange * when strictly needed (required for
4749ab747fSPaolo Bonzini * Darwin)
4849ab747fSPaolo Bonzini * 2011-Mar-22 Benjamin Poirier: Implemented VLAN offloading
4949ab747fSPaolo Bonzini */
5049ab747fSPaolo Bonzini
51e8d40465SPeter Maydell #include "qemu/osdep.h"
52*5691f477SMichael Tokarev #include <zlib.h> /* for crc32 */
5349ab747fSPaolo Bonzini
54edf5ca5dSMarkus Armbruster #include "hw/pci/pci_device.h"
55a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h"
56d6454270SMarkus Armbruster #include "migration/vmstate.h"
5749ab747fSPaolo Bonzini #include "sysemu/dma.h"
580b8fa32fSMarkus Armbruster #include "qemu/module.h"
5949ab747fSPaolo Bonzini #include "qemu/timer.h"
6049ab747fSPaolo Bonzini #include "net/net.h"
615d61721aSStefan Hajnoczi #include "net/eth.h"
6249ab747fSPaolo Bonzini #include "sysemu/sysemu.h"
63db1015e9SEduardo Habkost #include "qom/object.h"
6449ab747fSPaolo Bonzini
6549ab747fSPaolo Bonzini /* debug RTL8139 card */
6649ab747fSPaolo Bonzini //#define DEBUG_RTL8139 1
6749ab747fSPaolo Bonzini
6837b9ab92SLaurent Vivier #define PCI_PERIOD 30 /* 30 ns period = 33.333333 Mhz frequency */
6949ab747fSPaolo Bonzini
7049ab747fSPaolo Bonzini #define SET_MASKED(input, mask, curr) \
7149ab747fSPaolo Bonzini ( ( (input) & ~(mask) ) | ( (curr) & (mask) ) )
7249ab747fSPaolo Bonzini
7349ab747fSPaolo Bonzini /* arg % size for size which is a power of 2 */
7449ab747fSPaolo Bonzini #define MOD2(input, size) \
7549ab747fSPaolo Bonzini ( ( input ) & ( size - 1 ) )
7649ab747fSPaolo Bonzini
7749ab747fSPaolo Bonzini #define ETHER_TYPE_LEN 2
7849ab747fSPaolo Bonzini
7949ab747fSPaolo Bonzini #define VLAN_TCI_LEN 2
8049ab747fSPaolo Bonzini #define VLAN_HLEN (ETHER_TYPE_LEN + VLAN_TCI_LEN)
8149ab747fSPaolo Bonzini
8249ab747fSPaolo Bonzini #if defined (DEBUG_RTL8139)
8349ab747fSPaolo Bonzini # define DPRINTF(fmt, ...) \
8449ab747fSPaolo Bonzini do { fprintf(stderr, "RTL8139: " fmt, ## __VA_ARGS__); } while (0)
8549ab747fSPaolo Bonzini #else
DPRINTF(const char * fmt,...)869edc6313SMarc-André Lureau static inline G_GNUC_PRINTF(1, 2) int DPRINTF(const char *fmt, ...)
8749ab747fSPaolo Bonzini {
8849ab747fSPaolo Bonzini return 0;
8949ab747fSPaolo Bonzini }
9049ab747fSPaolo Bonzini #endif
9149ab747fSPaolo Bonzini
9239257515SPeter Crosthwaite #define TYPE_RTL8139 "rtl8139"
9339257515SPeter Crosthwaite
948063396bSEduardo Habkost OBJECT_DECLARE_SIMPLE_TYPE(RTL8139State, RTL8139)
9539257515SPeter Crosthwaite
9649ab747fSPaolo Bonzini /* Symbolic offsets to registers. */
9749ab747fSPaolo Bonzini enum RTL8139_registers {
9849ab747fSPaolo Bonzini MAC0 = 0, /* Ethernet hardware address. */
9949ab747fSPaolo Bonzini MAR0 = 8, /* Multicast filter. */
10049ab747fSPaolo Bonzini TxStatus0 = 0x10,/* Transmit status (Four 32bit registers). C mode only */
1012431f4f1SMichael Tokarev /* Dump Tally Counter control register(64bit). C+ mode only */
10249ab747fSPaolo Bonzini TxAddr0 = 0x20, /* Tx descriptors (also four 32bit). */
10349ab747fSPaolo Bonzini RxBuf = 0x30,
10449ab747fSPaolo Bonzini ChipCmd = 0x37,
10549ab747fSPaolo Bonzini RxBufPtr = 0x38,
10649ab747fSPaolo Bonzini RxBufAddr = 0x3A,
10749ab747fSPaolo Bonzini IntrMask = 0x3C,
10849ab747fSPaolo Bonzini IntrStatus = 0x3E,
10949ab747fSPaolo Bonzini TxConfig = 0x40,
11049ab747fSPaolo Bonzini RxConfig = 0x44,
11149ab747fSPaolo Bonzini Timer = 0x48, /* A general-purpose counter. */
11249ab747fSPaolo Bonzini RxMissed = 0x4C, /* 24 bits valid, write clears. */
11349ab747fSPaolo Bonzini Cfg9346 = 0x50,
11449ab747fSPaolo Bonzini Config0 = 0x51,
11549ab747fSPaolo Bonzini Config1 = 0x52,
11649ab747fSPaolo Bonzini FlashReg = 0x54,
11749ab747fSPaolo Bonzini MediaStatus = 0x58,
11849ab747fSPaolo Bonzini Config3 = 0x59,
11949ab747fSPaolo Bonzini Config4 = 0x5A, /* absent on RTL-8139A */
12049ab747fSPaolo Bonzini HltClk = 0x5B,
12149ab747fSPaolo Bonzini MultiIntr = 0x5C,
12249ab747fSPaolo Bonzini PCIRevisionID = 0x5E,
12349ab747fSPaolo Bonzini TxSummary = 0x60, /* TSAD register. Transmit Status of All Descriptors*/
12449ab747fSPaolo Bonzini BasicModeCtrl = 0x62,
12549ab747fSPaolo Bonzini BasicModeStatus = 0x64,
12649ab747fSPaolo Bonzini NWayAdvert = 0x66,
12749ab747fSPaolo Bonzini NWayLPAR = 0x68,
12849ab747fSPaolo Bonzini NWayExpansion = 0x6A,
12949ab747fSPaolo Bonzini /* Undocumented registers, but required for proper operation. */
13049ab747fSPaolo Bonzini FIFOTMS = 0x70, /* FIFO Control and test. */
13149ab747fSPaolo Bonzini CSCR = 0x74, /* Chip Status and Configuration Register. */
13249ab747fSPaolo Bonzini PARA78 = 0x78,
13349ab747fSPaolo Bonzini PARA7c = 0x7c, /* Magic transceiver parameter register. */
13449ab747fSPaolo Bonzini Config5 = 0xD8, /* absent on RTL-8139A */
13549ab747fSPaolo Bonzini /* C+ mode */
13649ab747fSPaolo Bonzini TxPoll = 0xD9, /* Tell chip to check Tx descriptors for work */
13749ab747fSPaolo Bonzini RxMaxSize = 0xDA, /* Max size of an Rx packet (8169 only) */
13849ab747fSPaolo Bonzini CpCmd = 0xE0, /* C+ Command register (C+ mode only) */
13949ab747fSPaolo Bonzini IntrMitigate = 0xE2, /* rx/tx interrupt mitigation control */
14049ab747fSPaolo Bonzini RxRingAddrLO = 0xE4, /* 64-bit start addr of Rx ring */
14149ab747fSPaolo Bonzini RxRingAddrHI = 0xE8, /* 64-bit start addr of Rx ring */
14249ab747fSPaolo Bonzini TxThresh = 0xEC, /* Early Tx threshold */
14349ab747fSPaolo Bonzini };
14449ab747fSPaolo Bonzini
14549ab747fSPaolo Bonzini enum ClearBitMasks {
14649ab747fSPaolo Bonzini MultiIntrClear = 0xF000,
14749ab747fSPaolo Bonzini ChipCmdClear = 0xE2,
14849ab747fSPaolo Bonzini Config1Clear = (1<<7)|(1<<6)|(1<<3)|(1<<2)|(1<<1),
14949ab747fSPaolo Bonzini };
15049ab747fSPaolo Bonzini
15149ab747fSPaolo Bonzini enum ChipCmdBits {
15249ab747fSPaolo Bonzini CmdReset = 0x10,
15349ab747fSPaolo Bonzini CmdRxEnb = 0x08,
15449ab747fSPaolo Bonzini CmdTxEnb = 0x04,
15549ab747fSPaolo Bonzini RxBufEmpty = 0x01,
15649ab747fSPaolo Bonzini };
15749ab747fSPaolo Bonzini
15849ab747fSPaolo Bonzini /* C+ mode */
15949ab747fSPaolo Bonzini enum CplusCmdBits {
16049ab747fSPaolo Bonzini CPlusRxVLAN = 0x0040, /* enable receive VLAN detagging */
16149ab747fSPaolo Bonzini CPlusRxChkSum = 0x0020, /* enable receive checksum offloading */
16249ab747fSPaolo Bonzini CPlusRxEnb = 0x0002,
16349ab747fSPaolo Bonzini CPlusTxEnb = 0x0001,
16449ab747fSPaolo Bonzini };
16549ab747fSPaolo Bonzini
16649ab747fSPaolo Bonzini /* Interrupt register bits, using my own meaningful names. */
16749ab747fSPaolo Bonzini enum IntrStatusBits {
16849ab747fSPaolo Bonzini PCIErr = 0x8000,
16949ab747fSPaolo Bonzini PCSTimeout = 0x4000,
17049ab747fSPaolo Bonzini RxFIFOOver = 0x40,
17149ab747fSPaolo Bonzini RxUnderrun = 0x20, /* Packet Underrun / Link Change */
17249ab747fSPaolo Bonzini RxOverflow = 0x10,
17349ab747fSPaolo Bonzini TxErr = 0x08,
17449ab747fSPaolo Bonzini TxOK = 0x04,
17549ab747fSPaolo Bonzini RxErr = 0x02,
17649ab747fSPaolo Bonzini RxOK = 0x01,
17749ab747fSPaolo Bonzini
17849ab747fSPaolo Bonzini RxAckBits = RxFIFOOver | RxOverflow | RxOK,
17949ab747fSPaolo Bonzini };
18049ab747fSPaolo Bonzini
18149ab747fSPaolo Bonzini enum TxStatusBits {
18249ab747fSPaolo Bonzini TxHostOwns = 0x2000,
18349ab747fSPaolo Bonzini TxUnderrun = 0x4000,
18449ab747fSPaolo Bonzini TxStatOK = 0x8000,
18549ab747fSPaolo Bonzini TxOutOfWindow = 0x20000000,
18649ab747fSPaolo Bonzini TxAborted = 0x40000000,
18749ab747fSPaolo Bonzini TxCarrierLost = 0x80000000,
18849ab747fSPaolo Bonzini };
18949ab747fSPaolo Bonzini enum RxStatusBits {
19049ab747fSPaolo Bonzini RxMulticast = 0x8000,
19149ab747fSPaolo Bonzini RxPhysical = 0x4000,
19249ab747fSPaolo Bonzini RxBroadcast = 0x2000,
19349ab747fSPaolo Bonzini RxBadSymbol = 0x0020,
19449ab747fSPaolo Bonzini RxRunt = 0x0010,
19549ab747fSPaolo Bonzini RxTooLong = 0x0008,
19649ab747fSPaolo Bonzini RxCRCErr = 0x0004,
19749ab747fSPaolo Bonzini RxBadAlign = 0x0002,
19849ab747fSPaolo Bonzini RxStatusOK = 0x0001,
19949ab747fSPaolo Bonzini };
20049ab747fSPaolo Bonzini
20149ab747fSPaolo Bonzini /* Bits in RxConfig. */
20249ab747fSPaolo Bonzini enum rx_mode_bits {
20349ab747fSPaolo Bonzini AcceptErr = 0x20,
20449ab747fSPaolo Bonzini AcceptRunt = 0x10,
20549ab747fSPaolo Bonzini AcceptBroadcast = 0x08,
20649ab747fSPaolo Bonzini AcceptMulticast = 0x04,
20749ab747fSPaolo Bonzini AcceptMyPhys = 0x02,
20849ab747fSPaolo Bonzini AcceptAllPhys = 0x01,
20949ab747fSPaolo Bonzini };
21049ab747fSPaolo Bonzini
21149ab747fSPaolo Bonzini /* Bits in TxConfig. */
21249ab747fSPaolo Bonzini enum tx_config_bits {
21349ab747fSPaolo Bonzini
21449ab747fSPaolo Bonzini /* Interframe Gap Time. Only TxIFG96 doesn't violate IEEE 802.3 */
21549ab747fSPaolo Bonzini TxIFGShift = 24,
21649ab747fSPaolo Bonzini TxIFG84 = (0 << TxIFGShift), /* 8.4us / 840ns (10 / 100Mbps) */
21749ab747fSPaolo Bonzini TxIFG88 = (1 << TxIFGShift), /* 8.8us / 880ns (10 / 100Mbps) */
21849ab747fSPaolo Bonzini TxIFG92 = (2 << TxIFGShift), /* 9.2us / 920ns (10 / 100Mbps) */
21949ab747fSPaolo Bonzini TxIFG96 = (3 << TxIFGShift), /* 9.6us / 960ns (10 / 100Mbps) */
22049ab747fSPaolo Bonzini
22149ab747fSPaolo Bonzini TxLoopBack = (1 << 18) | (1 << 17), /* enable loopback test mode */
22249ab747fSPaolo Bonzini TxCRC = (1 << 16), /* DISABLE appending CRC to end of Tx packets */
22349ab747fSPaolo Bonzini TxClearAbt = (1 << 0), /* Clear abort (WO) */
22449ab747fSPaolo Bonzini TxDMAShift = 8, /* DMA burst value (0-7) is shifted this many bits */
22549ab747fSPaolo Bonzini TxRetryShift = 4, /* TXRR value (0-15) is shifted this many bits */
22649ab747fSPaolo Bonzini
22749ab747fSPaolo Bonzini TxVersionMask = 0x7C800000, /* mask out version bits 30-26, 23 */
22849ab747fSPaolo Bonzini };
22949ab747fSPaolo Bonzini
23049ab747fSPaolo Bonzini
23149ab747fSPaolo Bonzini /* Transmit Status of All Descriptors (TSAD) Register */
23249ab747fSPaolo Bonzini enum TSAD_bits {
23349ab747fSPaolo Bonzini TSAD_TOK3 = 1<<15, // TOK bit of Descriptor 3
23449ab747fSPaolo Bonzini TSAD_TOK2 = 1<<14, // TOK bit of Descriptor 2
23549ab747fSPaolo Bonzini TSAD_TOK1 = 1<<13, // TOK bit of Descriptor 1
23649ab747fSPaolo Bonzini TSAD_TOK0 = 1<<12, // TOK bit of Descriptor 0
23749ab747fSPaolo Bonzini TSAD_TUN3 = 1<<11, // TUN bit of Descriptor 3
23849ab747fSPaolo Bonzini TSAD_TUN2 = 1<<10, // TUN bit of Descriptor 2
23949ab747fSPaolo Bonzini TSAD_TUN1 = 1<<9, // TUN bit of Descriptor 1
24049ab747fSPaolo Bonzini TSAD_TUN0 = 1<<8, // TUN bit of Descriptor 0
24149ab747fSPaolo Bonzini TSAD_TABT3 = 1<<07, // TABT bit of Descriptor 3
24249ab747fSPaolo Bonzini TSAD_TABT2 = 1<<06, // TABT bit of Descriptor 2
24349ab747fSPaolo Bonzini TSAD_TABT1 = 1<<05, // TABT bit of Descriptor 1
24449ab747fSPaolo Bonzini TSAD_TABT0 = 1<<04, // TABT bit of Descriptor 0
24549ab747fSPaolo Bonzini TSAD_OWN3 = 1<<03, // OWN bit of Descriptor 3
24649ab747fSPaolo Bonzini TSAD_OWN2 = 1<<02, // OWN bit of Descriptor 2
24749ab747fSPaolo Bonzini TSAD_OWN1 = 1<<01, // OWN bit of Descriptor 1
24849ab747fSPaolo Bonzini TSAD_OWN0 = 1<<00, // OWN bit of Descriptor 0
24949ab747fSPaolo Bonzini };
25049ab747fSPaolo Bonzini
25149ab747fSPaolo Bonzini
25249ab747fSPaolo Bonzini /* Bits in Config1 */
25349ab747fSPaolo Bonzini enum Config1Bits {
25449ab747fSPaolo Bonzini Cfg1_PM_Enable = 0x01,
25549ab747fSPaolo Bonzini Cfg1_VPD_Enable = 0x02,
25649ab747fSPaolo Bonzini Cfg1_PIO = 0x04,
25749ab747fSPaolo Bonzini Cfg1_MMIO = 0x08,
25849ab747fSPaolo Bonzini LWAKE = 0x10, /* not on 8139, 8139A */
25949ab747fSPaolo Bonzini Cfg1_Driver_Load = 0x20,
26049ab747fSPaolo Bonzini Cfg1_LED0 = 0x40,
26149ab747fSPaolo Bonzini Cfg1_LED1 = 0x80,
26249ab747fSPaolo Bonzini SLEEP = (1 << 1), /* only on 8139, 8139A */
26349ab747fSPaolo Bonzini PWRDN = (1 << 0), /* only on 8139, 8139A */
26449ab747fSPaolo Bonzini };
26549ab747fSPaolo Bonzini
26649ab747fSPaolo Bonzini /* Bits in Config3 */
26749ab747fSPaolo Bonzini enum Config3Bits {
26849ab747fSPaolo Bonzini Cfg3_FBtBEn = (1 << 0), /* 1 = Fast Back to Back */
26949ab747fSPaolo Bonzini Cfg3_FuncRegEn = (1 << 1), /* 1 = enable CardBus Function registers */
27049ab747fSPaolo Bonzini Cfg3_CLKRUN_En = (1 << 2), /* 1 = enable CLKRUN */
27149ab747fSPaolo Bonzini Cfg3_CardB_En = (1 << 3), /* 1 = enable CardBus registers */
27249ab747fSPaolo Bonzini Cfg3_LinkUp = (1 << 4), /* 1 = wake up on link up */
27349ab747fSPaolo Bonzini Cfg3_Magic = (1 << 5), /* 1 = wake up on Magic Packet (tm) */
27449ab747fSPaolo Bonzini Cfg3_PARM_En = (1 << 6), /* 0 = software can set twister parameters */
27549ab747fSPaolo Bonzini Cfg3_GNTSel = (1 << 7), /* 1 = delay 1 clock from PCI GNT signal */
27649ab747fSPaolo Bonzini };
27749ab747fSPaolo Bonzini
27849ab747fSPaolo Bonzini /* Bits in Config4 */
27949ab747fSPaolo Bonzini enum Config4Bits {
28049ab747fSPaolo Bonzini LWPTN = (1 << 2), /* not on 8139, 8139A */
28149ab747fSPaolo Bonzini };
28249ab747fSPaolo Bonzini
28349ab747fSPaolo Bonzini /* Bits in Config5 */
28449ab747fSPaolo Bonzini enum Config5Bits {
28549ab747fSPaolo Bonzini Cfg5_PME_STS = (1 << 0), /* 1 = PCI reset resets PME_Status */
28649ab747fSPaolo Bonzini Cfg5_LANWake = (1 << 1), /* 1 = enable LANWake signal */
28749ab747fSPaolo Bonzini Cfg5_LDPS = (1 << 2), /* 0 = save power when link is down */
28849ab747fSPaolo Bonzini Cfg5_FIFOAddrPtr = (1 << 3), /* Realtek internal SRAM testing */
28949ab747fSPaolo Bonzini Cfg5_UWF = (1 << 4), /* 1 = accept unicast wakeup frame */
29049ab747fSPaolo Bonzini Cfg5_MWF = (1 << 5), /* 1 = accept multicast wakeup frame */
29149ab747fSPaolo Bonzini Cfg5_BWF = (1 << 6), /* 1 = accept broadcast wakeup frame */
29249ab747fSPaolo Bonzini };
29349ab747fSPaolo Bonzini
29449ab747fSPaolo Bonzini enum RxConfigBits {
29549ab747fSPaolo Bonzini /* rx fifo threshold */
29649ab747fSPaolo Bonzini RxCfgFIFOShift = 13,
29749ab747fSPaolo Bonzini RxCfgFIFONone = (7 << RxCfgFIFOShift),
29849ab747fSPaolo Bonzini
29949ab747fSPaolo Bonzini /* Max DMA burst */
30049ab747fSPaolo Bonzini RxCfgDMAShift = 8,
30149ab747fSPaolo Bonzini RxCfgDMAUnlimited = (7 << RxCfgDMAShift),
30249ab747fSPaolo Bonzini
30349ab747fSPaolo Bonzini /* rx ring buffer length */
30449ab747fSPaolo Bonzini RxCfgRcv8K = 0,
30549ab747fSPaolo Bonzini RxCfgRcv16K = (1 << 11),
30649ab747fSPaolo Bonzini RxCfgRcv32K = (1 << 12),
30749ab747fSPaolo Bonzini RxCfgRcv64K = (1 << 11) | (1 << 12),
30849ab747fSPaolo Bonzini
30949ab747fSPaolo Bonzini /* Disable packet wrap at end of Rx buffer. (not possible with 64k) */
31049ab747fSPaolo Bonzini RxNoWrap = (1 << 7),
31149ab747fSPaolo Bonzini };
31249ab747fSPaolo Bonzini
31349ab747fSPaolo Bonzini /* Twister tuning parameters from RealTek.
31449ab747fSPaolo Bonzini Completely undocumented, but required to tune bad links on some boards. */
31549ab747fSPaolo Bonzini /*
31649ab747fSPaolo Bonzini enum CSCRBits {
31749ab747fSPaolo Bonzini CSCR_LinkOKBit = 0x0400,
31849ab747fSPaolo Bonzini CSCR_LinkChangeBit = 0x0800,
31949ab747fSPaolo Bonzini CSCR_LinkStatusBits = 0x0f000,
32049ab747fSPaolo Bonzini CSCR_LinkDownOffCmd = 0x003c0,
32149ab747fSPaolo Bonzini CSCR_LinkDownCmd = 0x0f3c0,
32249ab747fSPaolo Bonzini */
32349ab747fSPaolo Bonzini enum CSCRBits {
32449ab747fSPaolo Bonzini CSCR_Testfun = 1<<15, /* 1 = Auto-neg speeds up internal timer, WO, def 0 */
32549ab747fSPaolo Bonzini CSCR_LD = 1<<9, /* Active low TPI link disable signal. When low, TPI still transmits link pulses and TPI stays in good link state. def 1*/
32649ab747fSPaolo Bonzini CSCR_HEART_BIT = 1<<8, /* 1 = HEART BEAT enable, 0 = HEART BEAT disable. HEART BEAT function is only valid in 10Mbps mode. def 1*/
32749ab747fSPaolo Bonzini CSCR_JBEN = 1<<7, /* 1 = enable jabber function. 0 = disable jabber function, def 1*/
32849ab747fSPaolo Bonzini CSCR_F_LINK_100 = 1<<6, /* Used to login force good link in 100Mbps for diagnostic purposes. 1 = DISABLE, 0 = ENABLE. def 1*/
32949ab747fSPaolo Bonzini CSCR_F_Connect = 1<<5, /* Assertion of this bit forces the disconnect function to be bypassed. def 0*/
33049ab747fSPaolo Bonzini CSCR_Con_status = 1<<3, /* This bit indicates the status of the connection. 1 = valid connected link detected; 0 = disconnected link detected. RO def 0*/
33149ab747fSPaolo Bonzini CSCR_Con_status_En = 1<<2, /* Assertion of this bit configures LED1 pin to indicate connection status. def 0*/
33249ab747fSPaolo Bonzini CSCR_PASS_SCR = 1<<0, /* Bypass Scramble, def 0*/
33349ab747fSPaolo Bonzini };
33449ab747fSPaolo Bonzini
33549ab747fSPaolo Bonzini enum Cfg9346Bits {
33649ab747fSPaolo Bonzini Cfg9346_Normal = 0x00,
33749ab747fSPaolo Bonzini Cfg9346_Autoload = 0x40,
33849ab747fSPaolo Bonzini Cfg9346_Programming = 0x80,
33949ab747fSPaolo Bonzini Cfg9346_ConfigWrite = 0xC0,
34049ab747fSPaolo Bonzini };
34149ab747fSPaolo Bonzini
34249ab747fSPaolo Bonzini typedef enum {
34349ab747fSPaolo Bonzini CH_8139 = 0,
34449ab747fSPaolo Bonzini CH_8139_K,
34549ab747fSPaolo Bonzini CH_8139A,
34649ab747fSPaolo Bonzini CH_8139A_G,
34749ab747fSPaolo Bonzini CH_8139B,
34849ab747fSPaolo Bonzini CH_8130,
34949ab747fSPaolo Bonzini CH_8139C,
35049ab747fSPaolo Bonzini CH_8100,
35149ab747fSPaolo Bonzini CH_8100B_8139D,
35249ab747fSPaolo Bonzini CH_8101,
35349ab747fSPaolo Bonzini } chip_t;
35449ab747fSPaolo Bonzini
35549ab747fSPaolo Bonzini enum chip_flags {
35649ab747fSPaolo Bonzini HasHltClk = (1 << 0),
35749ab747fSPaolo Bonzini HasLWake = (1 << 1),
35849ab747fSPaolo Bonzini };
35949ab747fSPaolo Bonzini
36049ab747fSPaolo Bonzini #define HW_REVID(b30, b29, b28, b27, b26, b23, b22) \
36149ab747fSPaolo Bonzini (b30<<30 | b29<<29 | b28<<28 | b27<<27 | b26<<26 | b23<<23 | b22<<22)
36249ab747fSPaolo Bonzini #define HW_REVID_MASK HW_REVID(1, 1, 1, 1, 1, 1, 1)
36349ab747fSPaolo Bonzini
36449ab747fSPaolo Bonzini #define RTL8139_PCI_REVID_8139 0x10
36549ab747fSPaolo Bonzini #define RTL8139_PCI_REVID_8139CPLUS 0x20
36649ab747fSPaolo Bonzini
36749ab747fSPaolo Bonzini #define RTL8139_PCI_REVID RTL8139_PCI_REVID_8139CPLUS
36849ab747fSPaolo Bonzini
36949ab747fSPaolo Bonzini /* Size is 64 * 16bit words */
37049ab747fSPaolo Bonzini #define EEPROM_9346_ADDR_BITS 6
37149ab747fSPaolo Bonzini #define EEPROM_9346_SIZE (1 << EEPROM_9346_ADDR_BITS)
37249ab747fSPaolo Bonzini #define EEPROM_9346_ADDR_MASK (EEPROM_9346_SIZE - 1)
37349ab747fSPaolo Bonzini
37449ab747fSPaolo Bonzini enum Chip9346Operation
37549ab747fSPaolo Bonzini {
37649ab747fSPaolo Bonzini Chip9346_op_mask = 0xc0, /* 10 zzzzzz */
37749ab747fSPaolo Bonzini Chip9346_op_read = 0x80, /* 10 AAAAAA */
37849ab747fSPaolo Bonzini Chip9346_op_write = 0x40, /* 01 AAAAAA D(15)..D(0) */
37949ab747fSPaolo Bonzini Chip9346_op_ext_mask = 0xf0, /* 11 zzzzzz */
38049ab747fSPaolo Bonzini Chip9346_op_write_enable = 0x30, /* 00 11zzzz */
38149ab747fSPaolo Bonzini Chip9346_op_write_all = 0x10, /* 00 01zzzz */
38249ab747fSPaolo Bonzini Chip9346_op_write_disable = 0x00, /* 00 00zzzz */
38349ab747fSPaolo Bonzini };
38449ab747fSPaolo Bonzini
38549ab747fSPaolo Bonzini enum Chip9346Mode
38649ab747fSPaolo Bonzini {
38749ab747fSPaolo Bonzini Chip9346_none = 0,
38849ab747fSPaolo Bonzini Chip9346_enter_command_mode,
38949ab747fSPaolo Bonzini Chip9346_read_command,
39049ab747fSPaolo Bonzini Chip9346_data_read, /* from output register */
39149ab747fSPaolo Bonzini Chip9346_data_write, /* to input register, then to contents at specified address */
39249ab747fSPaolo Bonzini Chip9346_data_write_all, /* to input register, then filling contents */
39349ab747fSPaolo Bonzini };
39449ab747fSPaolo Bonzini
39549ab747fSPaolo Bonzini typedef struct EEprom9346
39649ab747fSPaolo Bonzini {
39749ab747fSPaolo Bonzini uint16_t contents[EEPROM_9346_SIZE];
39849ab747fSPaolo Bonzini int mode;
39949ab747fSPaolo Bonzini uint32_t tick;
40049ab747fSPaolo Bonzini uint8_t address;
40149ab747fSPaolo Bonzini uint16_t input;
40249ab747fSPaolo Bonzini uint16_t output;
40349ab747fSPaolo Bonzini
40449ab747fSPaolo Bonzini uint8_t eecs;
40549ab747fSPaolo Bonzini uint8_t eesk;
40649ab747fSPaolo Bonzini uint8_t eedi;
40749ab747fSPaolo Bonzini uint8_t eedo;
40849ab747fSPaolo Bonzini } EEprom9346;
40949ab747fSPaolo Bonzini
41049ab747fSPaolo Bonzini typedef struct RTL8139TallyCounters
41149ab747fSPaolo Bonzini {
41249ab747fSPaolo Bonzini /* Tally counters */
41349ab747fSPaolo Bonzini uint64_t TxOk;
41449ab747fSPaolo Bonzini uint64_t RxOk;
41549ab747fSPaolo Bonzini uint64_t TxERR;
41649ab747fSPaolo Bonzini uint32_t RxERR;
41749ab747fSPaolo Bonzini uint16_t MissPkt;
41849ab747fSPaolo Bonzini uint16_t FAE;
41949ab747fSPaolo Bonzini uint32_t Tx1Col;
42049ab747fSPaolo Bonzini uint32_t TxMCol;
42149ab747fSPaolo Bonzini uint64_t RxOkPhy;
42249ab747fSPaolo Bonzini uint64_t RxOkBrd;
42349ab747fSPaolo Bonzini uint32_t RxOkMul;
42449ab747fSPaolo Bonzini uint16_t TxAbt;
42549ab747fSPaolo Bonzini uint16_t TxUndrn;
42649ab747fSPaolo Bonzini } RTL8139TallyCounters;
42749ab747fSPaolo Bonzini
42849ab747fSPaolo Bonzini /* Clears all tally counters */
42949ab747fSPaolo Bonzini static void RTL8139TallyCounters_clear(RTL8139TallyCounters* counters);
43049ab747fSPaolo Bonzini
431db1015e9SEduardo Habkost struct RTL8139State {
43288a411a8SAndreas Färber /*< private >*/
43388a411a8SAndreas Färber PCIDevice parent_obj;
43488a411a8SAndreas Färber /*< public >*/
43588a411a8SAndreas Färber
43649ab747fSPaolo Bonzini uint8_t phys[8]; /* mac address */
43749ab747fSPaolo Bonzini uint8_t mult[8]; /* multicast mask array */
43849ab747fSPaolo Bonzini
43949ab747fSPaolo Bonzini uint32_t TxStatus[4]; /* TxStatus0 in C mode*/ /* also DTCCR[0] and DTCCR[1] in C+ mode */
44049ab747fSPaolo Bonzini uint32_t TxAddr[4]; /* TxAddr0 */
44149ab747fSPaolo Bonzini uint32_t RxBuf; /* Receive buffer */
44249ab747fSPaolo Bonzini uint32_t RxBufferSize;/* internal variable, receive ring buffer size in C mode */
44349ab747fSPaolo Bonzini uint32_t RxBufPtr;
44449ab747fSPaolo Bonzini uint32_t RxBufAddr;
44549ab747fSPaolo Bonzini
44649ab747fSPaolo Bonzini uint16_t IntrStatus;
44749ab747fSPaolo Bonzini uint16_t IntrMask;
44849ab747fSPaolo Bonzini
44949ab747fSPaolo Bonzini uint32_t TxConfig;
45049ab747fSPaolo Bonzini uint32_t RxConfig;
45149ab747fSPaolo Bonzini uint32_t RxMissed;
45249ab747fSPaolo Bonzini
45349ab747fSPaolo Bonzini uint16_t CSCR;
45449ab747fSPaolo Bonzini
45549ab747fSPaolo Bonzini uint8_t Cfg9346;
45649ab747fSPaolo Bonzini uint8_t Config0;
45749ab747fSPaolo Bonzini uint8_t Config1;
45849ab747fSPaolo Bonzini uint8_t Config3;
45949ab747fSPaolo Bonzini uint8_t Config4;
46049ab747fSPaolo Bonzini uint8_t Config5;
46149ab747fSPaolo Bonzini
46249ab747fSPaolo Bonzini uint8_t clock_enabled;
46349ab747fSPaolo Bonzini uint8_t bChipCmdState;
46449ab747fSPaolo Bonzini
46549ab747fSPaolo Bonzini uint16_t MultiIntr;
46649ab747fSPaolo Bonzini
46749ab747fSPaolo Bonzini uint16_t BasicModeCtrl;
46849ab747fSPaolo Bonzini uint16_t BasicModeStatus;
46949ab747fSPaolo Bonzini uint16_t NWayAdvert;
47049ab747fSPaolo Bonzini uint16_t NWayLPAR;
47149ab747fSPaolo Bonzini uint16_t NWayExpansion;
47249ab747fSPaolo Bonzini
47349ab747fSPaolo Bonzini uint16_t CpCmd;
47449ab747fSPaolo Bonzini uint8_t TxThresh;
47549ab747fSPaolo Bonzini
47649ab747fSPaolo Bonzini NICState *nic;
47749ab747fSPaolo Bonzini NICConf conf;
47849ab747fSPaolo Bonzini
47949ab747fSPaolo Bonzini /* C ring mode */
48049ab747fSPaolo Bonzini uint32_t currTxDesc;
48149ab747fSPaolo Bonzini
48249ab747fSPaolo Bonzini /* C+ mode */
48349ab747fSPaolo Bonzini uint32_t cplus_enabled;
48449ab747fSPaolo Bonzini
48549ab747fSPaolo Bonzini uint32_t currCPlusRxDesc;
48649ab747fSPaolo Bonzini uint32_t currCPlusTxDesc;
48749ab747fSPaolo Bonzini
48849ab747fSPaolo Bonzini uint32_t RxRingAddrLO;
48949ab747fSPaolo Bonzini uint32_t RxRingAddrHI;
49049ab747fSPaolo Bonzini
49149ab747fSPaolo Bonzini EEprom9346 eeprom;
49249ab747fSPaolo Bonzini
49349ab747fSPaolo Bonzini uint32_t TCTR;
49449ab747fSPaolo Bonzini uint32_t TimerInt;
49549ab747fSPaolo Bonzini int64_t TCTR_base;
49649ab747fSPaolo Bonzini
49749ab747fSPaolo Bonzini /* Tally counters */
49849ab747fSPaolo Bonzini RTL8139TallyCounters tally_counters;
49949ab747fSPaolo Bonzini
50049ab747fSPaolo Bonzini /* Non-persistent data */
50149ab747fSPaolo Bonzini uint8_t *cplus_txbuffer;
50249ab747fSPaolo Bonzini int cplus_txbuffer_len;
50349ab747fSPaolo Bonzini int cplus_txbuffer_offset;
50449ab747fSPaolo Bonzini
50549ab747fSPaolo Bonzini /* PCI interrupt timer */
50649ab747fSPaolo Bonzini QEMUTimer *timer;
50749ab747fSPaolo Bonzini
50849ab747fSPaolo Bonzini MemoryRegion bar_io;
50949ab747fSPaolo Bonzini MemoryRegion bar_mem;
51049ab747fSPaolo Bonzini
51149ab747fSPaolo Bonzini /* Support migration to/from old versions */
51249ab747fSPaolo Bonzini int rtl8139_mmio_io_addr_dummy;
513db1015e9SEduardo Habkost };
51449ab747fSPaolo Bonzini
51549ab747fSPaolo Bonzini /* Writes tally counters to memory via DMA */
51649ab747fSPaolo Bonzini static void RTL8139TallyCounters_dma_write(RTL8139State *s, dma_addr_t tc_addr);
51749ab747fSPaolo Bonzini
518237c255cSPaolo Bonzini static void rtl8139_set_next_tctr_time(RTL8139State *s);
51949ab747fSPaolo Bonzini
prom9346_decode_command(EEprom9346 * eeprom,uint8_t command)52049ab747fSPaolo Bonzini static void prom9346_decode_command(EEprom9346 *eeprom, uint8_t command)
52149ab747fSPaolo Bonzini {
52249ab747fSPaolo Bonzini DPRINTF("eeprom command 0x%02x\n", command);
52349ab747fSPaolo Bonzini
52449ab747fSPaolo Bonzini switch (command & Chip9346_op_mask)
52549ab747fSPaolo Bonzini {
52649ab747fSPaolo Bonzini case Chip9346_op_read:
52749ab747fSPaolo Bonzini {
52849ab747fSPaolo Bonzini eeprom->address = command & EEPROM_9346_ADDR_MASK;
52949ab747fSPaolo Bonzini eeprom->output = eeprom->contents[eeprom->address];
53049ab747fSPaolo Bonzini eeprom->eedo = 0;
53149ab747fSPaolo Bonzini eeprom->tick = 0;
53249ab747fSPaolo Bonzini eeprom->mode = Chip9346_data_read;
53349ab747fSPaolo Bonzini DPRINTF("eeprom read from address 0x%02x data=0x%04x\n",
53449ab747fSPaolo Bonzini eeprom->address, eeprom->output);
53549ab747fSPaolo Bonzini }
53649ab747fSPaolo Bonzini break;
53749ab747fSPaolo Bonzini
53849ab747fSPaolo Bonzini case Chip9346_op_write:
53949ab747fSPaolo Bonzini {
54049ab747fSPaolo Bonzini eeprom->address = command & EEPROM_9346_ADDR_MASK;
54149ab747fSPaolo Bonzini eeprom->input = 0;
54249ab747fSPaolo Bonzini eeprom->tick = 0;
54349ab747fSPaolo Bonzini eeprom->mode = Chip9346_none; /* Chip9346_data_write */
54449ab747fSPaolo Bonzini DPRINTF("eeprom begin write to address 0x%02x\n",
54549ab747fSPaolo Bonzini eeprom->address);
54649ab747fSPaolo Bonzini }
54749ab747fSPaolo Bonzini break;
54849ab747fSPaolo Bonzini default:
54949ab747fSPaolo Bonzini eeprom->mode = Chip9346_none;
55049ab747fSPaolo Bonzini switch (command & Chip9346_op_ext_mask)
55149ab747fSPaolo Bonzini {
55249ab747fSPaolo Bonzini case Chip9346_op_write_enable:
55349ab747fSPaolo Bonzini DPRINTF("eeprom write enabled\n");
55449ab747fSPaolo Bonzini break;
55549ab747fSPaolo Bonzini case Chip9346_op_write_all:
55649ab747fSPaolo Bonzini DPRINTF("eeprom begin write all\n");
55749ab747fSPaolo Bonzini break;
55849ab747fSPaolo Bonzini case Chip9346_op_write_disable:
55949ab747fSPaolo Bonzini DPRINTF("eeprom write disabled\n");
56049ab747fSPaolo Bonzini break;
56149ab747fSPaolo Bonzini }
56249ab747fSPaolo Bonzini break;
56349ab747fSPaolo Bonzini }
56449ab747fSPaolo Bonzini }
56549ab747fSPaolo Bonzini
prom9346_shift_clock(EEprom9346 * eeprom)56649ab747fSPaolo Bonzini static void prom9346_shift_clock(EEprom9346 *eeprom)
56749ab747fSPaolo Bonzini {
56849ab747fSPaolo Bonzini int bit = eeprom->eedi?1:0;
56949ab747fSPaolo Bonzini
57049ab747fSPaolo Bonzini ++ eeprom->tick;
57149ab747fSPaolo Bonzini
57249ab747fSPaolo Bonzini DPRINTF("eeprom: tick %d eedi=%d eedo=%d\n", eeprom->tick, eeprom->eedi,
57349ab747fSPaolo Bonzini eeprom->eedo);
57449ab747fSPaolo Bonzini
57549ab747fSPaolo Bonzini switch (eeprom->mode)
57649ab747fSPaolo Bonzini {
57749ab747fSPaolo Bonzini case Chip9346_enter_command_mode:
57849ab747fSPaolo Bonzini if (bit)
57949ab747fSPaolo Bonzini {
58049ab747fSPaolo Bonzini eeprom->mode = Chip9346_read_command;
58149ab747fSPaolo Bonzini eeprom->tick = 0;
58249ab747fSPaolo Bonzini eeprom->input = 0;
58349ab747fSPaolo Bonzini DPRINTF("eeprom: +++ synchronized, begin command read\n");
58449ab747fSPaolo Bonzini }
58549ab747fSPaolo Bonzini break;
58649ab747fSPaolo Bonzini
58749ab747fSPaolo Bonzini case Chip9346_read_command:
58849ab747fSPaolo Bonzini eeprom->input = (eeprom->input << 1) | (bit & 1);
58949ab747fSPaolo Bonzini if (eeprom->tick == 8)
59049ab747fSPaolo Bonzini {
59149ab747fSPaolo Bonzini prom9346_decode_command(eeprom, eeprom->input & 0xff);
59249ab747fSPaolo Bonzini }
59349ab747fSPaolo Bonzini break;
59449ab747fSPaolo Bonzini
59549ab747fSPaolo Bonzini case Chip9346_data_read:
59649ab747fSPaolo Bonzini eeprom->eedo = (eeprom->output & 0x8000)?1:0;
59749ab747fSPaolo Bonzini eeprom->output <<= 1;
59849ab747fSPaolo Bonzini if (eeprom->tick == 16)
59949ab747fSPaolo Bonzini {
60049ab747fSPaolo Bonzini #if 1
60149ab747fSPaolo Bonzini // the FreeBSD drivers (rl and re) don't explicitly toggle
60249ab747fSPaolo Bonzini // CS between reads (or does setting Cfg9346 to 0 count too?),
60349ab747fSPaolo Bonzini // so we need to enter wait-for-command state here
60449ab747fSPaolo Bonzini eeprom->mode = Chip9346_enter_command_mode;
60549ab747fSPaolo Bonzini eeprom->input = 0;
60649ab747fSPaolo Bonzini eeprom->tick = 0;
60749ab747fSPaolo Bonzini
60849ab747fSPaolo Bonzini DPRINTF("eeprom: +++ end of read, awaiting next command\n");
60949ab747fSPaolo Bonzini #else
61049ab747fSPaolo Bonzini // original behaviour
61149ab747fSPaolo Bonzini ++eeprom->address;
61249ab747fSPaolo Bonzini eeprom->address &= EEPROM_9346_ADDR_MASK;
61349ab747fSPaolo Bonzini eeprom->output = eeprom->contents[eeprom->address];
61449ab747fSPaolo Bonzini eeprom->tick = 0;
61549ab747fSPaolo Bonzini
61649ab747fSPaolo Bonzini DPRINTF("eeprom: +++ read next address 0x%02x data=0x%04x\n",
61749ab747fSPaolo Bonzini eeprom->address, eeprom->output);
61849ab747fSPaolo Bonzini #endif
61949ab747fSPaolo Bonzini }
62049ab747fSPaolo Bonzini break;
62149ab747fSPaolo Bonzini
62249ab747fSPaolo Bonzini case Chip9346_data_write:
62349ab747fSPaolo Bonzini eeprom->input = (eeprom->input << 1) | (bit & 1);
62449ab747fSPaolo Bonzini if (eeprom->tick == 16)
62549ab747fSPaolo Bonzini {
62649ab747fSPaolo Bonzini DPRINTF("eeprom write to address 0x%02x data=0x%04x\n",
62749ab747fSPaolo Bonzini eeprom->address, eeprom->input);
62849ab747fSPaolo Bonzini
62949ab747fSPaolo Bonzini eeprom->contents[eeprom->address] = eeprom->input;
63049ab747fSPaolo Bonzini eeprom->mode = Chip9346_none; /* waiting for next command after CS cycle */
63149ab747fSPaolo Bonzini eeprom->tick = 0;
63249ab747fSPaolo Bonzini eeprom->input = 0;
63349ab747fSPaolo Bonzini }
63449ab747fSPaolo Bonzini break;
63549ab747fSPaolo Bonzini
63649ab747fSPaolo Bonzini case Chip9346_data_write_all:
63749ab747fSPaolo Bonzini eeprom->input = (eeprom->input << 1) | (bit & 1);
63849ab747fSPaolo Bonzini if (eeprom->tick == 16)
63949ab747fSPaolo Bonzini {
64049ab747fSPaolo Bonzini int i;
64149ab747fSPaolo Bonzini for (i = 0; i < EEPROM_9346_SIZE; i++)
64249ab747fSPaolo Bonzini {
64349ab747fSPaolo Bonzini eeprom->contents[i] = eeprom->input;
64449ab747fSPaolo Bonzini }
64549ab747fSPaolo Bonzini DPRINTF("eeprom filled with data=0x%04x\n", eeprom->input);
64649ab747fSPaolo Bonzini
64749ab747fSPaolo Bonzini eeprom->mode = Chip9346_enter_command_mode;
64849ab747fSPaolo Bonzini eeprom->tick = 0;
64949ab747fSPaolo Bonzini eeprom->input = 0;
65049ab747fSPaolo Bonzini }
65149ab747fSPaolo Bonzini break;
65249ab747fSPaolo Bonzini
65349ab747fSPaolo Bonzini default:
65449ab747fSPaolo Bonzini break;
65549ab747fSPaolo Bonzini }
65649ab747fSPaolo Bonzini }
65749ab747fSPaolo Bonzini
prom9346_get_wire(RTL8139State * s)65849ab747fSPaolo Bonzini static int prom9346_get_wire(RTL8139State *s)
65949ab747fSPaolo Bonzini {
66049ab747fSPaolo Bonzini EEprom9346 *eeprom = &s->eeprom;
66149ab747fSPaolo Bonzini if (!eeprom->eecs)
66249ab747fSPaolo Bonzini return 0;
66349ab747fSPaolo Bonzini
66449ab747fSPaolo Bonzini return eeprom->eedo;
66549ab747fSPaolo Bonzini }
66649ab747fSPaolo Bonzini
66749ab747fSPaolo Bonzini /* FIXME: This should be merged into/replaced by eeprom93xx.c. */
prom9346_set_wire(RTL8139State * s,int eecs,int eesk,int eedi)66849ab747fSPaolo Bonzini static void prom9346_set_wire(RTL8139State *s, int eecs, int eesk, int eedi)
66949ab747fSPaolo Bonzini {
67049ab747fSPaolo Bonzini EEprom9346 *eeprom = &s->eeprom;
67149ab747fSPaolo Bonzini uint8_t old_eecs = eeprom->eecs;
67249ab747fSPaolo Bonzini uint8_t old_eesk = eeprom->eesk;
67349ab747fSPaolo Bonzini
67449ab747fSPaolo Bonzini eeprom->eecs = eecs;
67549ab747fSPaolo Bonzini eeprom->eesk = eesk;
67649ab747fSPaolo Bonzini eeprom->eedi = eedi;
67749ab747fSPaolo Bonzini
67849ab747fSPaolo Bonzini DPRINTF("eeprom: +++ wires CS=%d SK=%d DI=%d DO=%d\n", eeprom->eecs,
67949ab747fSPaolo Bonzini eeprom->eesk, eeprom->eedi, eeprom->eedo);
68049ab747fSPaolo Bonzini
68149ab747fSPaolo Bonzini if (!old_eecs && eecs)
68249ab747fSPaolo Bonzini {
68349ab747fSPaolo Bonzini /* Synchronize start */
68449ab747fSPaolo Bonzini eeprom->tick = 0;
68549ab747fSPaolo Bonzini eeprom->input = 0;
68649ab747fSPaolo Bonzini eeprom->output = 0;
68749ab747fSPaolo Bonzini eeprom->mode = Chip9346_enter_command_mode;
68849ab747fSPaolo Bonzini
68949ab747fSPaolo Bonzini DPRINTF("=== eeprom: begin access, enter command mode\n");
69049ab747fSPaolo Bonzini }
69149ab747fSPaolo Bonzini
69249ab747fSPaolo Bonzini if (!eecs)
69349ab747fSPaolo Bonzini {
69449ab747fSPaolo Bonzini DPRINTF("=== eeprom: end access\n");
69549ab747fSPaolo Bonzini return;
69649ab747fSPaolo Bonzini }
69749ab747fSPaolo Bonzini
69849ab747fSPaolo Bonzini if (!old_eesk && eesk)
69949ab747fSPaolo Bonzini {
70049ab747fSPaolo Bonzini /* SK front rules */
70149ab747fSPaolo Bonzini prom9346_shift_clock(eeprom);
70249ab747fSPaolo Bonzini }
70349ab747fSPaolo Bonzini }
70449ab747fSPaolo Bonzini
rtl8139_update_irq(RTL8139State * s)70549ab747fSPaolo Bonzini static void rtl8139_update_irq(RTL8139State *s)
70649ab747fSPaolo Bonzini {
70788a411a8SAndreas Färber PCIDevice *d = PCI_DEVICE(s);
70849ab747fSPaolo Bonzini int isr;
70949ab747fSPaolo Bonzini isr = (s->IntrStatus & s->IntrMask) & 0xffff;
71049ab747fSPaolo Bonzini
71149ab747fSPaolo Bonzini DPRINTF("Set IRQ to %d (%04x %04x)\n", isr ? 1 : 0, s->IntrStatus,
71249ab747fSPaolo Bonzini s->IntrMask);
71349ab747fSPaolo Bonzini
7149e64f8a3SMarcel Apfelbaum pci_set_irq(d, (isr != 0));
71549ab747fSPaolo Bonzini }
71649ab747fSPaolo Bonzini
rtl8139_RxWrap(RTL8139State * s)71749ab747fSPaolo Bonzini static int rtl8139_RxWrap(RTL8139State *s)
71849ab747fSPaolo Bonzini {
71949ab747fSPaolo Bonzini /* wrapping enabled; assume 1.5k more buffer space if size < 65536 */
72049ab747fSPaolo Bonzini return (s->RxConfig & (1 << 7));
72149ab747fSPaolo Bonzini }
72249ab747fSPaolo Bonzini
rtl8139_receiver_enabled(RTL8139State * s)72349ab747fSPaolo Bonzini static int rtl8139_receiver_enabled(RTL8139State *s)
72449ab747fSPaolo Bonzini {
72549ab747fSPaolo Bonzini return s->bChipCmdState & CmdRxEnb;
72649ab747fSPaolo Bonzini }
72749ab747fSPaolo Bonzini
rtl8139_transmitter_enabled(RTL8139State * s)72849ab747fSPaolo Bonzini static int rtl8139_transmitter_enabled(RTL8139State *s)
72949ab747fSPaolo Bonzini {
73049ab747fSPaolo Bonzini return s->bChipCmdState & CmdTxEnb;
73149ab747fSPaolo Bonzini }
73249ab747fSPaolo Bonzini
rtl8139_cp_receiver_enabled(RTL8139State * s)73349ab747fSPaolo Bonzini static int rtl8139_cp_receiver_enabled(RTL8139State *s)
73449ab747fSPaolo Bonzini {
73549ab747fSPaolo Bonzini return s->CpCmd & CPlusRxEnb;
73649ab747fSPaolo Bonzini }
73749ab747fSPaolo Bonzini
rtl8139_cp_transmitter_enabled(RTL8139State * s)73849ab747fSPaolo Bonzini static int rtl8139_cp_transmitter_enabled(RTL8139State *s)
73949ab747fSPaolo Bonzini {
74049ab747fSPaolo Bonzini return s->CpCmd & CPlusTxEnb;
74149ab747fSPaolo Bonzini }
74249ab747fSPaolo Bonzini
rtl8139_write_buffer(RTL8139State * s,const void * buf,int size)74349ab747fSPaolo Bonzini static void rtl8139_write_buffer(RTL8139State *s, const void *buf, int size)
74449ab747fSPaolo Bonzini {
74588a411a8SAndreas Färber PCIDevice *d = PCI_DEVICE(s);
74688a411a8SAndreas Färber
74749ab747fSPaolo Bonzini if (s->RxBufAddr + size > s->RxBufferSize)
74849ab747fSPaolo Bonzini {
74949ab747fSPaolo Bonzini int wrapped = MOD2(s->RxBufAddr + size, s->RxBufferSize);
75049ab747fSPaolo Bonzini
75149ab747fSPaolo Bonzini /* write packet data */
75249ab747fSPaolo Bonzini if (wrapped && !(s->RxBufferSize < 65536 && rtl8139_RxWrap(s)))
75349ab747fSPaolo Bonzini {
75449ab747fSPaolo Bonzini DPRINTF(">>> rx packet wrapped in buffer at %d\n", size - wrapped);
75549ab747fSPaolo Bonzini
75649ab747fSPaolo Bonzini if (size > wrapped)
75749ab747fSPaolo Bonzini {
75888a411a8SAndreas Färber pci_dma_write(d, s->RxBuf + s->RxBufAddr,
75949ab747fSPaolo Bonzini buf, size-wrapped);
76049ab747fSPaolo Bonzini }
76149ab747fSPaolo Bonzini
76249ab747fSPaolo Bonzini /* reset buffer pointer */
76349ab747fSPaolo Bonzini s->RxBufAddr = 0;
76449ab747fSPaolo Bonzini
76588a411a8SAndreas Färber pci_dma_write(d, s->RxBuf + s->RxBufAddr,
76649ab747fSPaolo Bonzini buf + (size-wrapped), wrapped);
76749ab747fSPaolo Bonzini
76849ab747fSPaolo Bonzini s->RxBufAddr = wrapped;
76949ab747fSPaolo Bonzini
77049ab747fSPaolo Bonzini return;
77149ab747fSPaolo Bonzini }
77249ab747fSPaolo Bonzini }
77349ab747fSPaolo Bonzini
77449ab747fSPaolo Bonzini /* non-wrapping path or overwrapping enabled */
77588a411a8SAndreas Färber pci_dma_write(d, s->RxBuf + s->RxBufAddr, buf, size);
77649ab747fSPaolo Bonzini
77749ab747fSPaolo Bonzini s->RxBufAddr += size;
77849ab747fSPaolo Bonzini }
77949ab747fSPaolo Bonzini
78049ab747fSPaolo Bonzini #define MIN_BUF_SIZE 60
rtl8139_addr64(uint32_t low,uint32_t high)78149ab747fSPaolo Bonzini static inline dma_addr_t rtl8139_addr64(uint32_t low, uint32_t high)
78249ab747fSPaolo Bonzini {
78349ab747fSPaolo Bonzini return low | ((uint64_t)high << 32);
78449ab747fSPaolo Bonzini }
78549ab747fSPaolo Bonzini
78649ab747fSPaolo Bonzini /* Workaround for buggy guest driver such as linux who allocates rx
78749ab747fSPaolo Bonzini * rings after the receiver were enabled. */
rtl8139_cp_rx_valid(RTL8139State * s)78849ab747fSPaolo Bonzini static bool rtl8139_cp_rx_valid(RTL8139State *s)
78949ab747fSPaolo Bonzini {
79049ab747fSPaolo Bonzini return !(s->RxRingAddrLO == 0 && s->RxRingAddrHI == 0);
79149ab747fSPaolo Bonzini }
79249ab747fSPaolo Bonzini
rtl8139_can_receive(NetClientState * nc)793b8c4b67eSPhilippe Mathieu-Daudé static bool rtl8139_can_receive(NetClientState *nc)
79449ab747fSPaolo Bonzini {
79549ab747fSPaolo Bonzini RTL8139State *s = qemu_get_nic_opaque(nc);
79649ab747fSPaolo Bonzini int avail;
79749ab747fSPaolo Bonzini
79849ab747fSPaolo Bonzini /* Receive (drop) packets if card is disabled. */
7993317db74SPhilippe Mathieu-Daudé if (!s->clock_enabled) {
800b8c4b67eSPhilippe Mathieu-Daudé return true;
8013317db74SPhilippe Mathieu-Daudé }
8023317db74SPhilippe Mathieu-Daudé if (!rtl8139_receiver_enabled(s)) {
803b8c4b67eSPhilippe Mathieu-Daudé return true;
8043317db74SPhilippe Mathieu-Daudé }
80549ab747fSPaolo Bonzini
80649ab747fSPaolo Bonzini if (rtl8139_cp_receiver_enabled(s) && rtl8139_cp_rx_valid(s)) {
80749ab747fSPaolo Bonzini /* ??? Flow control not implemented in c+ mode.
80849ab747fSPaolo Bonzini This is a hack to work around slirp deficiencies anyway. */
809b8c4b67eSPhilippe Mathieu-Daudé return true;
8102fa3d2d4SPhilippe Mathieu-Daudé }
8112fa3d2d4SPhilippe Mathieu-Daudé
81249ab747fSPaolo Bonzini avail = MOD2(s->RxBufferSize + s->RxBufPtr - s->RxBufAddr,
81349ab747fSPaolo Bonzini s->RxBufferSize);
8142fa3d2d4SPhilippe Mathieu-Daudé return avail == 0 || avail >= 1514 || (s->IntrMask & RxOverflow);
81549ab747fSPaolo Bonzini }
81649ab747fSPaolo Bonzini
rtl8139_do_receive(NetClientState * nc,const uint8_t * buf,size_t size_,int do_interrupt)81749ab747fSPaolo Bonzini static ssize_t rtl8139_do_receive(NetClientState *nc, const uint8_t *buf, size_t size_, int do_interrupt)
81849ab747fSPaolo Bonzini {
81949ab747fSPaolo Bonzini RTL8139State *s = qemu_get_nic_opaque(nc);
82088a411a8SAndreas Färber PCIDevice *d = PCI_DEVICE(s);
82149ab747fSPaolo Bonzini /* size is the length of the buffer passed to the driver */
8221a326646SJason Wang size_t size = size_;
82349ab747fSPaolo Bonzini const uint8_t *dot1q_buf = NULL;
82449ab747fSPaolo Bonzini
82549ab747fSPaolo Bonzini uint32_t packet_header = 0;
82649ab747fSPaolo Bonzini
82749ab747fSPaolo Bonzini static const uint8_t broadcast_macaddr[6] =
82849ab747fSPaolo Bonzini { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
82949ab747fSPaolo Bonzini
8301a326646SJason Wang DPRINTF(">>> received len=%zu\n", size);
83149ab747fSPaolo Bonzini
83249ab747fSPaolo Bonzini /* test if board clock is stopped */
83349ab747fSPaolo Bonzini if (!s->clock_enabled)
83449ab747fSPaolo Bonzini {
83549ab747fSPaolo Bonzini DPRINTF("stopped ==========================\n");
83649ab747fSPaolo Bonzini return -1;
83749ab747fSPaolo Bonzini }
83849ab747fSPaolo Bonzini
83949ab747fSPaolo Bonzini /* first check if receiver is enabled */
84049ab747fSPaolo Bonzini
84149ab747fSPaolo Bonzini if (!rtl8139_receiver_enabled(s))
84249ab747fSPaolo Bonzini {
84349ab747fSPaolo Bonzini DPRINTF("receiver disabled ================\n");
84449ab747fSPaolo Bonzini return -1;
84549ab747fSPaolo Bonzini }
84649ab747fSPaolo Bonzini
84749ab747fSPaolo Bonzini /* XXX: check this */
84849ab747fSPaolo Bonzini if (s->RxConfig & AcceptAllPhys) {
84949ab747fSPaolo Bonzini /* promiscuous: receive all */
85049ab747fSPaolo Bonzini DPRINTF(">>> packet received in promiscuous mode\n");
85149ab747fSPaolo Bonzini
85249ab747fSPaolo Bonzini } else {
85349ab747fSPaolo Bonzini if (!memcmp(buf, broadcast_macaddr, 6)) {
85449ab747fSPaolo Bonzini /* broadcast address */
85549ab747fSPaolo Bonzini if (!(s->RxConfig & AcceptBroadcast))
85649ab747fSPaolo Bonzini {
85749ab747fSPaolo Bonzini DPRINTF(">>> broadcast packet rejected\n");
85849ab747fSPaolo Bonzini
85949ab747fSPaolo Bonzini /* update tally counter */
86049ab747fSPaolo Bonzini ++s->tally_counters.RxERR;
86149ab747fSPaolo Bonzini
86249ab747fSPaolo Bonzini return size;
86349ab747fSPaolo Bonzini }
86449ab747fSPaolo Bonzini
86549ab747fSPaolo Bonzini packet_header |= RxBroadcast;
86649ab747fSPaolo Bonzini
86749ab747fSPaolo Bonzini DPRINTF(">>> broadcast packet received\n");
86849ab747fSPaolo Bonzini
86949ab747fSPaolo Bonzini /* update tally counter */
87049ab747fSPaolo Bonzini ++s->tally_counters.RxOkBrd;
87149ab747fSPaolo Bonzini
87249ab747fSPaolo Bonzini } else if (buf[0] & 0x01) {
87349ab747fSPaolo Bonzini /* multicast */
87449ab747fSPaolo Bonzini if (!(s->RxConfig & AcceptMulticast))
87549ab747fSPaolo Bonzini {
87649ab747fSPaolo Bonzini DPRINTF(">>> multicast packet rejected\n");
87749ab747fSPaolo Bonzini
87849ab747fSPaolo Bonzini /* update tally counter */
87949ab747fSPaolo Bonzini ++s->tally_counters.RxERR;
88049ab747fSPaolo Bonzini
88149ab747fSPaolo Bonzini return size;
88249ab747fSPaolo Bonzini }
88349ab747fSPaolo Bonzini
884e7a58fc7SMark Cave-Ayland int mcast_idx = net_crc32(buf, ETH_ALEN) >> 26;
88549ab747fSPaolo Bonzini
88649ab747fSPaolo Bonzini if (!(s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7))))
88749ab747fSPaolo Bonzini {
88849ab747fSPaolo Bonzini DPRINTF(">>> multicast address mismatch\n");
88949ab747fSPaolo Bonzini
89049ab747fSPaolo Bonzini /* update tally counter */
89149ab747fSPaolo Bonzini ++s->tally_counters.RxERR;
89249ab747fSPaolo Bonzini
89349ab747fSPaolo Bonzini return size;
89449ab747fSPaolo Bonzini }
89549ab747fSPaolo Bonzini
89649ab747fSPaolo Bonzini packet_header |= RxMulticast;
89749ab747fSPaolo Bonzini
89849ab747fSPaolo Bonzini DPRINTF(">>> multicast packet received\n");
89949ab747fSPaolo Bonzini
90049ab747fSPaolo Bonzini /* update tally counter */
90149ab747fSPaolo Bonzini ++s->tally_counters.RxOkMul;
90249ab747fSPaolo Bonzini
90349ab747fSPaolo Bonzini } else if (s->phys[0] == buf[0] &&
90449ab747fSPaolo Bonzini s->phys[1] == buf[1] &&
90549ab747fSPaolo Bonzini s->phys[2] == buf[2] &&
90649ab747fSPaolo Bonzini s->phys[3] == buf[3] &&
90749ab747fSPaolo Bonzini s->phys[4] == buf[4] &&
90849ab747fSPaolo Bonzini s->phys[5] == buf[5]) {
90949ab747fSPaolo Bonzini /* match */
91049ab747fSPaolo Bonzini if (!(s->RxConfig & AcceptMyPhys))
91149ab747fSPaolo Bonzini {
91249ab747fSPaolo Bonzini DPRINTF(">>> rejecting physical address matching packet\n");
91349ab747fSPaolo Bonzini
91449ab747fSPaolo Bonzini /* update tally counter */
91549ab747fSPaolo Bonzini ++s->tally_counters.RxERR;
91649ab747fSPaolo Bonzini
91749ab747fSPaolo Bonzini return size;
91849ab747fSPaolo Bonzini }
91949ab747fSPaolo Bonzini
92049ab747fSPaolo Bonzini packet_header |= RxPhysical;
92149ab747fSPaolo Bonzini
92249ab747fSPaolo Bonzini DPRINTF(">>> physical address matching packet received\n");
92349ab747fSPaolo Bonzini
92449ab747fSPaolo Bonzini /* update tally counter */
92549ab747fSPaolo Bonzini ++s->tally_counters.RxOkPhy;
92649ab747fSPaolo Bonzini
92749ab747fSPaolo Bonzini } else {
92849ab747fSPaolo Bonzini
92949ab747fSPaolo Bonzini DPRINTF(">>> unknown packet\n");
93049ab747fSPaolo Bonzini
93149ab747fSPaolo Bonzini /* update tally counter */
93249ab747fSPaolo Bonzini ++s->tally_counters.RxERR;
93349ab747fSPaolo Bonzini
93449ab747fSPaolo Bonzini return size;
93549ab747fSPaolo Bonzini }
93649ab747fSPaolo Bonzini }
93749ab747fSPaolo Bonzini
93849ab747fSPaolo Bonzini if (rtl8139_cp_receiver_enabled(s))
93949ab747fSPaolo Bonzini {
94049ab747fSPaolo Bonzini if (!rtl8139_cp_rx_valid(s)) {
94149ab747fSPaolo Bonzini return size;
94249ab747fSPaolo Bonzini }
94349ab747fSPaolo Bonzini
94449ab747fSPaolo Bonzini DPRINTF("in C+ Rx mode ================\n");
94549ab747fSPaolo Bonzini
94649ab747fSPaolo Bonzini /* begin C+ receiver mode */
94749ab747fSPaolo Bonzini
94849ab747fSPaolo Bonzini /* w0 ownership flag */
94949ab747fSPaolo Bonzini #define CP_RX_OWN (1<<31)
95049ab747fSPaolo Bonzini /* w0 end of ring flag */
95149ab747fSPaolo Bonzini #define CP_RX_EOR (1<<30)
95249ab747fSPaolo Bonzini /* w0 bits 0...12 : buffer size */
95349ab747fSPaolo Bonzini #define CP_RX_BUFFER_SIZE_MASK ((1<<13) - 1)
95449ab747fSPaolo Bonzini /* w1 tag available flag */
95549ab747fSPaolo Bonzini #define CP_RX_TAVA (1<<16)
95649ab747fSPaolo Bonzini /* w1 bits 0...15 : VLAN tag */
95749ab747fSPaolo Bonzini #define CP_RX_VLAN_TAG_MASK ((1<<16) - 1)
95849ab747fSPaolo Bonzini /* w2 low 32bit of Rx buffer ptr */
95949ab747fSPaolo Bonzini /* w3 high 32bit of Rx buffer ptr */
96049ab747fSPaolo Bonzini
96149ab747fSPaolo Bonzini int descriptor = s->currCPlusRxDesc;
96249ab747fSPaolo Bonzini dma_addr_t cplus_rx_ring_desc;
96349ab747fSPaolo Bonzini
96449ab747fSPaolo Bonzini cplus_rx_ring_desc = rtl8139_addr64(s->RxRingAddrLO, s->RxRingAddrHI);
96549ab747fSPaolo Bonzini cplus_rx_ring_desc += 16 * descriptor;
96649ab747fSPaolo Bonzini
96749ab747fSPaolo Bonzini DPRINTF("+++ C+ mode reading RX descriptor %d from host memory at "
96849ab747fSPaolo Bonzini "%08x %08x = "DMA_ADDR_FMT"\n", descriptor, s->RxRingAddrHI,
96949ab747fSPaolo Bonzini s->RxRingAddrLO, cplus_rx_ring_desc);
97049ab747fSPaolo Bonzini
97149ab747fSPaolo Bonzini uint32_t val, rxdw0,rxdw1,rxbufLO,rxbufHI;
97249ab747fSPaolo Bonzini
97388a411a8SAndreas Färber pci_dma_read(d, cplus_rx_ring_desc, &val, 4);
97449ab747fSPaolo Bonzini rxdw0 = le32_to_cpu(val);
97588a411a8SAndreas Färber pci_dma_read(d, cplus_rx_ring_desc+4, &val, 4);
97649ab747fSPaolo Bonzini rxdw1 = le32_to_cpu(val);
97788a411a8SAndreas Färber pci_dma_read(d, cplus_rx_ring_desc+8, &val, 4);
97849ab747fSPaolo Bonzini rxbufLO = le32_to_cpu(val);
97988a411a8SAndreas Färber pci_dma_read(d, cplus_rx_ring_desc+12, &val, 4);
98049ab747fSPaolo Bonzini rxbufHI = le32_to_cpu(val);
98149ab747fSPaolo Bonzini
98249ab747fSPaolo Bonzini DPRINTF("+++ C+ mode RX descriptor %d %08x %08x %08x %08x\n",
98349ab747fSPaolo Bonzini descriptor, rxdw0, rxdw1, rxbufLO, rxbufHI);
98449ab747fSPaolo Bonzini
98549ab747fSPaolo Bonzini if (!(rxdw0 & CP_RX_OWN))
98649ab747fSPaolo Bonzini {
98749ab747fSPaolo Bonzini DPRINTF("C+ Rx mode : descriptor %d is owned by host\n",
98849ab747fSPaolo Bonzini descriptor);
98949ab747fSPaolo Bonzini
99049ab747fSPaolo Bonzini s->IntrStatus |= RxOverflow;
99149ab747fSPaolo Bonzini ++s->RxMissed;
99249ab747fSPaolo Bonzini
99349ab747fSPaolo Bonzini /* update tally counter */
99449ab747fSPaolo Bonzini ++s->tally_counters.RxERR;
99549ab747fSPaolo Bonzini ++s->tally_counters.MissPkt;
99649ab747fSPaolo Bonzini
99749ab747fSPaolo Bonzini rtl8139_update_irq(s);
99849ab747fSPaolo Bonzini return size_;
99949ab747fSPaolo Bonzini }
100049ab747fSPaolo Bonzini
100149ab747fSPaolo Bonzini uint32_t rx_space = rxdw0 & CP_RX_BUFFER_SIZE_MASK;
100249ab747fSPaolo Bonzini
100349ab747fSPaolo Bonzini /* write VLAN info to descriptor variables. */
10046960bfcaSPeter Maydell if (s->CpCmd & CPlusRxVLAN &&
10056960bfcaSPeter Maydell lduw_be_p(&buf[ETH_ALEN * 2]) == ETH_P_VLAN) {
10061bf11332SStefan Hajnoczi dot1q_buf = &buf[ETH_ALEN * 2];
100749ab747fSPaolo Bonzini size -= VLAN_HLEN;
100849ab747fSPaolo Bonzini /* if too small buffer, use the tailroom added duing expansion */
100949ab747fSPaolo Bonzini if (size < MIN_BUF_SIZE) {
101049ab747fSPaolo Bonzini size = MIN_BUF_SIZE;
101149ab747fSPaolo Bonzini }
101249ab747fSPaolo Bonzini
101349ab747fSPaolo Bonzini rxdw1 &= ~CP_RX_VLAN_TAG_MASK;
101449ab747fSPaolo Bonzini /* BE + ~le_to_cpu()~ + cpu_to_le() = BE */
10156960bfcaSPeter Maydell rxdw1 |= CP_RX_TAVA | lduw_le_p(&dot1q_buf[ETHER_TYPE_LEN]);
101649ab747fSPaolo Bonzini
101749ab747fSPaolo Bonzini DPRINTF("C+ Rx mode : extracted vlan tag with tci: ""%u\n",
10186960bfcaSPeter Maydell lduw_be_p(&dot1q_buf[ETHER_TYPE_LEN]));
101949ab747fSPaolo Bonzini } else {
102049ab747fSPaolo Bonzini /* reset VLAN tag flag */
102149ab747fSPaolo Bonzini rxdw1 &= ~CP_RX_TAVA;
102249ab747fSPaolo Bonzini }
102349ab747fSPaolo Bonzini
102449ab747fSPaolo Bonzini /* TODO: scatter the packet over available receive ring descriptors space */
102549ab747fSPaolo Bonzini
102649ab747fSPaolo Bonzini if (size+4 > rx_space)
102749ab747fSPaolo Bonzini {
10281a326646SJason Wang DPRINTF("C+ Rx mode : descriptor %d size %d received %zu + 4\n",
102949ab747fSPaolo Bonzini descriptor, rx_space, size);
103049ab747fSPaolo Bonzini
103149ab747fSPaolo Bonzini s->IntrStatus |= RxOverflow;
103249ab747fSPaolo Bonzini ++s->RxMissed;
103349ab747fSPaolo Bonzini
103449ab747fSPaolo Bonzini /* update tally counter */
103549ab747fSPaolo Bonzini ++s->tally_counters.RxERR;
103649ab747fSPaolo Bonzini ++s->tally_counters.MissPkt;
103749ab747fSPaolo Bonzini
103849ab747fSPaolo Bonzini rtl8139_update_irq(s);
103949ab747fSPaolo Bonzini return size_;
104049ab747fSPaolo Bonzini }
104149ab747fSPaolo Bonzini
104249ab747fSPaolo Bonzini dma_addr_t rx_addr = rtl8139_addr64(rxbufLO, rxbufHI);
104349ab747fSPaolo Bonzini
104449ab747fSPaolo Bonzini /* receive/copy to target memory */
104549ab747fSPaolo Bonzini if (dot1q_buf) {
10461bf11332SStefan Hajnoczi pci_dma_write(d, rx_addr, buf, 2 * ETH_ALEN);
10471bf11332SStefan Hajnoczi pci_dma_write(d, rx_addr + 2 * ETH_ALEN,
10481bf11332SStefan Hajnoczi buf + 2 * ETH_ALEN + VLAN_HLEN,
10491bf11332SStefan Hajnoczi size - 2 * ETH_ALEN);
105049ab747fSPaolo Bonzini } else {
105188a411a8SAndreas Färber pci_dma_write(d, rx_addr, buf, size);
105249ab747fSPaolo Bonzini }
105349ab747fSPaolo Bonzini
105449ab747fSPaolo Bonzini if (s->CpCmd & CPlusRxChkSum)
105549ab747fSPaolo Bonzini {
105649ab747fSPaolo Bonzini /* do some packet checksumming */
105749ab747fSPaolo Bonzini }
105849ab747fSPaolo Bonzini
105949ab747fSPaolo Bonzini /* write checksum */
106049ab747fSPaolo Bonzini val = cpu_to_le32(crc32(0, buf, size_));
106188a411a8SAndreas Färber pci_dma_write(d, rx_addr+size, (uint8_t *)&val, 4);
106249ab747fSPaolo Bonzini
106349ab747fSPaolo Bonzini /* first segment of received packet flag */
106449ab747fSPaolo Bonzini #define CP_RX_STATUS_FS (1<<29)
106549ab747fSPaolo Bonzini /* last segment of received packet flag */
106649ab747fSPaolo Bonzini #define CP_RX_STATUS_LS (1<<28)
106749ab747fSPaolo Bonzini /* multicast packet flag */
106849ab747fSPaolo Bonzini #define CP_RX_STATUS_MAR (1<<26)
106949ab747fSPaolo Bonzini /* physical-matching packet flag */
107049ab747fSPaolo Bonzini #define CP_RX_STATUS_PAM (1<<25)
107149ab747fSPaolo Bonzini /* broadcast packet flag */
107249ab747fSPaolo Bonzini #define CP_RX_STATUS_BAR (1<<24)
107349ab747fSPaolo Bonzini /* runt packet flag */
107449ab747fSPaolo Bonzini #define CP_RX_STATUS_RUNT (1<<19)
107549ab747fSPaolo Bonzini /* crc error flag */
107649ab747fSPaolo Bonzini #define CP_RX_STATUS_CRC (1<<18)
107749ab747fSPaolo Bonzini /* IP checksum error flag */
107849ab747fSPaolo Bonzini #define CP_RX_STATUS_IPF (1<<15)
107949ab747fSPaolo Bonzini /* UDP checksum error flag */
108049ab747fSPaolo Bonzini #define CP_RX_STATUS_UDPF (1<<14)
108149ab747fSPaolo Bonzini /* TCP checksum error flag */
108249ab747fSPaolo Bonzini #define CP_RX_STATUS_TCPF (1<<13)
108349ab747fSPaolo Bonzini
108449ab747fSPaolo Bonzini /* transfer ownership to target */
108549ab747fSPaolo Bonzini rxdw0 &= ~CP_RX_OWN;
108649ab747fSPaolo Bonzini
108749ab747fSPaolo Bonzini /* set first segment bit */
108849ab747fSPaolo Bonzini rxdw0 |= CP_RX_STATUS_FS;
108949ab747fSPaolo Bonzini
109049ab747fSPaolo Bonzini /* set last segment bit */
109149ab747fSPaolo Bonzini rxdw0 |= CP_RX_STATUS_LS;
109249ab747fSPaolo Bonzini
109349ab747fSPaolo Bonzini /* set received packet type flags */
109449ab747fSPaolo Bonzini if (packet_header & RxBroadcast)
109549ab747fSPaolo Bonzini rxdw0 |= CP_RX_STATUS_BAR;
109649ab747fSPaolo Bonzini if (packet_header & RxMulticast)
109749ab747fSPaolo Bonzini rxdw0 |= CP_RX_STATUS_MAR;
109849ab747fSPaolo Bonzini if (packet_header & RxPhysical)
109949ab747fSPaolo Bonzini rxdw0 |= CP_RX_STATUS_PAM;
110049ab747fSPaolo Bonzini
110149ab747fSPaolo Bonzini /* set received size */
110249ab747fSPaolo Bonzini rxdw0 &= ~CP_RX_BUFFER_SIZE_MASK;
110349ab747fSPaolo Bonzini rxdw0 |= (size+4);
110449ab747fSPaolo Bonzini
110549ab747fSPaolo Bonzini /* update ring data */
110649ab747fSPaolo Bonzini val = cpu_to_le32(rxdw0);
110788a411a8SAndreas Färber pci_dma_write(d, cplus_rx_ring_desc, (uint8_t *)&val, 4);
110849ab747fSPaolo Bonzini val = cpu_to_le32(rxdw1);
110988a411a8SAndreas Färber pci_dma_write(d, cplus_rx_ring_desc+4, (uint8_t *)&val, 4);
111049ab747fSPaolo Bonzini
111149ab747fSPaolo Bonzini /* update tally counter */
111249ab747fSPaolo Bonzini ++s->tally_counters.RxOk;
111349ab747fSPaolo Bonzini
111449ab747fSPaolo Bonzini /* seek to next Rx descriptor */
111549ab747fSPaolo Bonzini if (rxdw0 & CP_RX_EOR)
111649ab747fSPaolo Bonzini {
111749ab747fSPaolo Bonzini s->currCPlusRxDesc = 0;
111849ab747fSPaolo Bonzini }
111949ab747fSPaolo Bonzini else
112049ab747fSPaolo Bonzini {
112149ab747fSPaolo Bonzini ++s->currCPlusRxDesc;
112249ab747fSPaolo Bonzini }
112349ab747fSPaolo Bonzini
112449ab747fSPaolo Bonzini DPRINTF("done C+ Rx mode ----------------\n");
112549ab747fSPaolo Bonzini
112649ab747fSPaolo Bonzini }
112749ab747fSPaolo Bonzini else
112849ab747fSPaolo Bonzini {
112949ab747fSPaolo Bonzini DPRINTF("in ring Rx mode ================\n");
113049ab747fSPaolo Bonzini
113149ab747fSPaolo Bonzini /* begin ring receiver mode */
113249ab747fSPaolo Bonzini int avail = MOD2(s->RxBufferSize + s->RxBufPtr - s->RxBufAddr, s->RxBufferSize);
113349ab747fSPaolo Bonzini
113449ab747fSPaolo Bonzini /* if receiver buffer is empty then avail == 0 */
113549ab747fSPaolo Bonzini
1136fabdcd33SVladislav Yasevich #define RX_ALIGN(x) (((x) + 3) & ~0x3)
1137fabdcd33SVladislav Yasevich
1138fabdcd33SVladislav Yasevich if (avail != 0 && RX_ALIGN(size + 8) >= avail)
113949ab747fSPaolo Bonzini {
114049ab747fSPaolo Bonzini DPRINTF("rx overflow: rx buffer length %d head 0x%04x "
11411a326646SJason Wang "read 0x%04x === available 0x%04x need 0x%04zx\n",
114249ab747fSPaolo Bonzini s->RxBufferSize, s->RxBufAddr, s->RxBufPtr, avail, size + 8);
114349ab747fSPaolo Bonzini
114449ab747fSPaolo Bonzini s->IntrStatus |= RxOverflow;
114549ab747fSPaolo Bonzini ++s->RxMissed;
114649ab747fSPaolo Bonzini rtl8139_update_irq(s);
114726c4e7caSVladislav Yasevich return 0;
114849ab747fSPaolo Bonzini }
114949ab747fSPaolo Bonzini
115049ab747fSPaolo Bonzini packet_header |= RxStatusOK;
115149ab747fSPaolo Bonzini
115249ab747fSPaolo Bonzini packet_header |= (((size+4) << 16) & 0xffff0000);
115349ab747fSPaolo Bonzini
115449ab747fSPaolo Bonzini /* write header */
115549ab747fSPaolo Bonzini uint32_t val = cpu_to_le32(packet_header);
115649ab747fSPaolo Bonzini
115749ab747fSPaolo Bonzini rtl8139_write_buffer(s, (uint8_t *)&val, 4);
115849ab747fSPaolo Bonzini
115949ab747fSPaolo Bonzini rtl8139_write_buffer(s, buf, size);
116049ab747fSPaolo Bonzini
116149ab747fSPaolo Bonzini /* write checksum */
116249ab747fSPaolo Bonzini val = cpu_to_le32(crc32(0, buf, size));
116349ab747fSPaolo Bonzini rtl8139_write_buffer(s, (uint8_t *)&val, 4);
116449ab747fSPaolo Bonzini
116549ab747fSPaolo Bonzini /* correct buffer write pointer */
1166fabdcd33SVladislav Yasevich s->RxBufAddr = MOD2(RX_ALIGN(s->RxBufAddr), s->RxBufferSize);
116749ab747fSPaolo Bonzini
116849ab747fSPaolo Bonzini /* now we can signal we have received something */
116949ab747fSPaolo Bonzini
117049ab747fSPaolo Bonzini DPRINTF("received: rx buffer length %d head 0x%04x read 0x%04x\n",
117149ab747fSPaolo Bonzini s->RxBufferSize, s->RxBufAddr, s->RxBufPtr);
117249ab747fSPaolo Bonzini }
117349ab747fSPaolo Bonzini
117449ab747fSPaolo Bonzini s->IntrStatus |= RxOK;
117549ab747fSPaolo Bonzini
117649ab747fSPaolo Bonzini if (do_interrupt)
117749ab747fSPaolo Bonzini {
117849ab747fSPaolo Bonzini rtl8139_update_irq(s);
117949ab747fSPaolo Bonzini }
118049ab747fSPaolo Bonzini
118149ab747fSPaolo Bonzini return size_;
118249ab747fSPaolo Bonzini }
118349ab747fSPaolo Bonzini
rtl8139_receive(NetClientState * nc,const uint8_t * buf,size_t size)118449ab747fSPaolo Bonzini static ssize_t rtl8139_receive(NetClientState *nc, const uint8_t *buf, size_t size)
118549ab747fSPaolo Bonzini {
118649ab747fSPaolo Bonzini return rtl8139_do_receive(nc, buf, size, 1);
118749ab747fSPaolo Bonzini }
118849ab747fSPaolo Bonzini
rtl8139_reset_rxring(RTL8139State * s,uint32_t bufferSize)118949ab747fSPaolo Bonzini static void rtl8139_reset_rxring(RTL8139State *s, uint32_t bufferSize)
119049ab747fSPaolo Bonzini {
119149ab747fSPaolo Bonzini s->RxBufferSize = bufferSize;
119249ab747fSPaolo Bonzini s->RxBufPtr = 0;
119349ab747fSPaolo Bonzini s->RxBufAddr = 0;
119449ab747fSPaolo Bonzini }
119549ab747fSPaolo Bonzini
rtl8139_reset_phy(RTL8139State * s)119630a3e701SHervé Poussineau static void rtl8139_reset_phy(RTL8139State *s)
119730a3e701SHervé Poussineau {
119830a3e701SHervé Poussineau s->BasicModeStatus = 0x7809;
119930a3e701SHervé Poussineau s->BasicModeStatus |= 0x0020; /* autonegotiation completed */
120030a3e701SHervé Poussineau /* preserve link state */
120130a3e701SHervé Poussineau s->BasicModeStatus |= qemu_get_queue(s->nic)->link_down ? 0 : 0x04;
120230a3e701SHervé Poussineau
120330a3e701SHervé Poussineau s->NWayAdvert = 0x05e1; /* all modes, full duplex */
120430a3e701SHervé Poussineau s->NWayLPAR = 0x05e1; /* all modes, full duplex */
120530a3e701SHervé Poussineau s->NWayExpansion = 0x0001; /* autonegotiation supported */
120630a3e701SHervé Poussineau
120730a3e701SHervé Poussineau s->CSCR = CSCR_F_LINK_100 | CSCR_HEART_BIT | CSCR_LD;
120830a3e701SHervé Poussineau }
120930a3e701SHervé Poussineau
rtl8139_reset(DeviceState * d)121049ab747fSPaolo Bonzini static void rtl8139_reset(DeviceState *d)
121149ab747fSPaolo Bonzini {
121239257515SPeter Crosthwaite RTL8139State *s = RTL8139(d);
121349ab747fSPaolo Bonzini int i;
121449ab747fSPaolo Bonzini
121549ab747fSPaolo Bonzini /* restore MAC address */
121649ab747fSPaolo Bonzini memcpy(s->phys, s->conf.macaddr.a, 6);
1217655d3b63SAmos Kong qemu_format_nic_info_str(qemu_get_queue(s->nic), s->phys);
121849ab747fSPaolo Bonzini
121949ab747fSPaolo Bonzini /* reset interrupt mask */
122049ab747fSPaolo Bonzini s->IntrStatus = 0;
122149ab747fSPaolo Bonzini s->IntrMask = 0;
122249ab747fSPaolo Bonzini
122349ab747fSPaolo Bonzini rtl8139_update_irq(s);
122449ab747fSPaolo Bonzini
122549ab747fSPaolo Bonzini /* mark all status registers as owned by host */
122649ab747fSPaolo Bonzini for (i = 0; i < 4; ++i)
122749ab747fSPaolo Bonzini {
122849ab747fSPaolo Bonzini s->TxStatus[i] = TxHostOwns;
122949ab747fSPaolo Bonzini }
123049ab747fSPaolo Bonzini
123149ab747fSPaolo Bonzini s->currTxDesc = 0;
123249ab747fSPaolo Bonzini s->currCPlusRxDesc = 0;
123349ab747fSPaolo Bonzini s->currCPlusTxDesc = 0;
123449ab747fSPaolo Bonzini
123549ab747fSPaolo Bonzini s->RxRingAddrLO = 0;
123649ab747fSPaolo Bonzini s->RxRingAddrHI = 0;
123749ab747fSPaolo Bonzini
123849ab747fSPaolo Bonzini s->RxBuf = 0;
123949ab747fSPaolo Bonzini
124049ab747fSPaolo Bonzini rtl8139_reset_rxring(s, 8192);
124149ab747fSPaolo Bonzini
124249ab747fSPaolo Bonzini /* ACK the reset */
124349ab747fSPaolo Bonzini s->TxConfig = 0;
124449ab747fSPaolo Bonzini
124549ab747fSPaolo Bonzini #if 0
124649ab747fSPaolo Bonzini // s->TxConfig |= HW_REVID(1, 0, 0, 0, 0, 0, 0); // RTL-8139 HasHltClk
124749ab747fSPaolo Bonzini s->clock_enabled = 0;
124849ab747fSPaolo Bonzini #else
124949ab747fSPaolo Bonzini s->TxConfig |= HW_REVID(1, 1, 1, 0, 1, 1, 0); // RTL-8139C+ HasLWake
125049ab747fSPaolo Bonzini s->clock_enabled = 1;
125149ab747fSPaolo Bonzini #endif
125249ab747fSPaolo Bonzini
125349ab747fSPaolo Bonzini s->bChipCmdState = CmdReset; /* RxBufEmpty bit is calculated on read from ChipCmd */;
125449ab747fSPaolo Bonzini
125549ab747fSPaolo Bonzini /* set initial state data */
125649ab747fSPaolo Bonzini s->Config0 = 0x0; /* No boot ROM */
125749ab747fSPaolo Bonzini s->Config1 = 0xC; /* IO mapped and MEM mapped registers available */
125849ab747fSPaolo Bonzini s->Config3 = 0x1; /* fast back-to-back compatible */
125949ab747fSPaolo Bonzini s->Config5 = 0x0;
126049ab747fSPaolo Bonzini
126149ab747fSPaolo Bonzini s->CpCmd = 0x0; /* reset C+ mode */
126249ab747fSPaolo Bonzini s->cplus_enabled = 0;
126349ab747fSPaolo Bonzini
126449ab747fSPaolo Bonzini // s->BasicModeCtrl = 0x3100; // 100Mbps, full duplex, autonegotiation
126549ab747fSPaolo Bonzini // s->BasicModeCtrl = 0x2100; // 100Mbps, full duplex
126649ab747fSPaolo Bonzini s->BasicModeCtrl = 0x1000; // autonegotiation
126749ab747fSPaolo Bonzini
126830a3e701SHervé Poussineau rtl8139_reset_phy(s);
126949ab747fSPaolo Bonzini
127049ab747fSPaolo Bonzini /* also reset timer and disable timer interrupt */
127149ab747fSPaolo Bonzini s->TCTR = 0;
127249ab747fSPaolo Bonzini s->TimerInt = 0;
127349ab747fSPaolo Bonzini s->TCTR_base = 0;
1274237c255cSPaolo Bonzini rtl8139_set_next_tctr_time(s);
127549ab747fSPaolo Bonzini
127649ab747fSPaolo Bonzini /* reset tally counters */
127749ab747fSPaolo Bonzini RTL8139TallyCounters_clear(&s->tally_counters);
127849ab747fSPaolo Bonzini }
127949ab747fSPaolo Bonzini
RTL8139TallyCounters_clear(RTL8139TallyCounters * counters)128049ab747fSPaolo Bonzini static void RTL8139TallyCounters_clear(RTL8139TallyCounters* counters)
128149ab747fSPaolo Bonzini {
128249ab747fSPaolo Bonzini counters->TxOk = 0;
128349ab747fSPaolo Bonzini counters->RxOk = 0;
128449ab747fSPaolo Bonzini counters->TxERR = 0;
128549ab747fSPaolo Bonzini counters->RxERR = 0;
128649ab747fSPaolo Bonzini counters->MissPkt = 0;
128749ab747fSPaolo Bonzini counters->FAE = 0;
128849ab747fSPaolo Bonzini counters->Tx1Col = 0;
128949ab747fSPaolo Bonzini counters->TxMCol = 0;
129049ab747fSPaolo Bonzini counters->RxOkPhy = 0;
129149ab747fSPaolo Bonzini counters->RxOkBrd = 0;
129249ab747fSPaolo Bonzini counters->RxOkMul = 0;
129349ab747fSPaolo Bonzini counters->TxAbt = 0;
129449ab747fSPaolo Bonzini counters->TxUndrn = 0;
129549ab747fSPaolo Bonzini }
129649ab747fSPaolo Bonzini
RTL8139TallyCounters_dma_write(RTL8139State * s,dma_addr_t tc_addr)129749ab747fSPaolo Bonzini static void RTL8139TallyCounters_dma_write(RTL8139State *s, dma_addr_t tc_addr)
129849ab747fSPaolo Bonzini {
129988a411a8SAndreas Färber PCIDevice *d = PCI_DEVICE(s);
130049ab747fSPaolo Bonzini RTL8139TallyCounters *tally_counters = &s->tally_counters;
130149ab747fSPaolo Bonzini uint16_t val16;
130249ab747fSPaolo Bonzini uint32_t val32;
130349ab747fSPaolo Bonzini uint64_t val64;
130449ab747fSPaolo Bonzini
130549ab747fSPaolo Bonzini val64 = cpu_to_le64(tally_counters->TxOk);
130688a411a8SAndreas Färber pci_dma_write(d, tc_addr + 0, (uint8_t *)&val64, 8);
130749ab747fSPaolo Bonzini
130849ab747fSPaolo Bonzini val64 = cpu_to_le64(tally_counters->RxOk);
130988a411a8SAndreas Färber pci_dma_write(d, tc_addr + 8, (uint8_t *)&val64, 8);
131049ab747fSPaolo Bonzini
131149ab747fSPaolo Bonzini val64 = cpu_to_le64(tally_counters->TxERR);
131288a411a8SAndreas Färber pci_dma_write(d, tc_addr + 16, (uint8_t *)&val64, 8);
131349ab747fSPaolo Bonzini
131449ab747fSPaolo Bonzini val32 = cpu_to_le32(tally_counters->RxERR);
131588a411a8SAndreas Färber pci_dma_write(d, tc_addr + 24, (uint8_t *)&val32, 4);
131649ab747fSPaolo Bonzini
131749ab747fSPaolo Bonzini val16 = cpu_to_le16(tally_counters->MissPkt);
131888a411a8SAndreas Färber pci_dma_write(d, tc_addr + 28, (uint8_t *)&val16, 2);
131949ab747fSPaolo Bonzini
132049ab747fSPaolo Bonzini val16 = cpu_to_le16(tally_counters->FAE);
132188a411a8SAndreas Färber pci_dma_write(d, tc_addr + 30, (uint8_t *)&val16, 2);
132249ab747fSPaolo Bonzini
132349ab747fSPaolo Bonzini val32 = cpu_to_le32(tally_counters->Tx1Col);
132488a411a8SAndreas Färber pci_dma_write(d, tc_addr + 32, (uint8_t *)&val32, 4);
132549ab747fSPaolo Bonzini
132649ab747fSPaolo Bonzini val32 = cpu_to_le32(tally_counters->TxMCol);
132788a411a8SAndreas Färber pci_dma_write(d, tc_addr + 36, (uint8_t *)&val32, 4);
132849ab747fSPaolo Bonzini
132949ab747fSPaolo Bonzini val64 = cpu_to_le64(tally_counters->RxOkPhy);
133088a411a8SAndreas Färber pci_dma_write(d, tc_addr + 40, (uint8_t *)&val64, 8);
133149ab747fSPaolo Bonzini
133249ab747fSPaolo Bonzini val64 = cpu_to_le64(tally_counters->RxOkBrd);
133388a411a8SAndreas Färber pci_dma_write(d, tc_addr + 48, (uint8_t *)&val64, 8);
133449ab747fSPaolo Bonzini
133549ab747fSPaolo Bonzini val32 = cpu_to_le32(tally_counters->RxOkMul);
133688a411a8SAndreas Färber pci_dma_write(d, tc_addr + 56, (uint8_t *)&val32, 4);
133749ab747fSPaolo Bonzini
133849ab747fSPaolo Bonzini val16 = cpu_to_le16(tally_counters->TxAbt);
133988a411a8SAndreas Färber pci_dma_write(d, tc_addr + 60, (uint8_t *)&val16, 2);
134049ab747fSPaolo Bonzini
134149ab747fSPaolo Bonzini val16 = cpu_to_le16(tally_counters->TxUndrn);
134288a411a8SAndreas Färber pci_dma_write(d, tc_addr + 62, (uint8_t *)&val16, 2);
134349ab747fSPaolo Bonzini }
134449ab747fSPaolo Bonzini
rtl8139_ChipCmd_write(RTL8139State * s,uint32_t val)134549ab747fSPaolo Bonzini static void rtl8139_ChipCmd_write(RTL8139State *s, uint32_t val)
134649ab747fSPaolo Bonzini {
134739257515SPeter Crosthwaite DeviceState *d = DEVICE(s);
134839257515SPeter Crosthwaite
134949ab747fSPaolo Bonzini val &= 0xff;
135049ab747fSPaolo Bonzini
135149ab747fSPaolo Bonzini DPRINTF("ChipCmd write val=0x%08x\n", val);
135249ab747fSPaolo Bonzini
135349ab747fSPaolo Bonzini if (val & CmdReset)
135449ab747fSPaolo Bonzini {
135549ab747fSPaolo Bonzini DPRINTF("ChipCmd reset\n");
135639257515SPeter Crosthwaite rtl8139_reset(d);
135749ab747fSPaolo Bonzini }
135849ab747fSPaolo Bonzini if (val & CmdRxEnb)
135949ab747fSPaolo Bonzini {
136049ab747fSPaolo Bonzini DPRINTF("ChipCmd enable receiver\n");
136149ab747fSPaolo Bonzini
136249ab747fSPaolo Bonzini s->currCPlusRxDesc = 0;
136349ab747fSPaolo Bonzini }
136449ab747fSPaolo Bonzini if (val & CmdTxEnb)
136549ab747fSPaolo Bonzini {
136649ab747fSPaolo Bonzini DPRINTF("ChipCmd enable transmitter\n");
136749ab747fSPaolo Bonzini
136849ab747fSPaolo Bonzini s->currCPlusTxDesc = 0;
136949ab747fSPaolo Bonzini }
137049ab747fSPaolo Bonzini
137149ab747fSPaolo Bonzini /* mask unwritable bits */
137249ab747fSPaolo Bonzini val = SET_MASKED(val, 0xe3, s->bChipCmdState);
137349ab747fSPaolo Bonzini
137449ab747fSPaolo Bonzini /* Deassert reset pin before next read */
137549ab747fSPaolo Bonzini val &= ~CmdReset;
137649ab747fSPaolo Bonzini
137749ab747fSPaolo Bonzini s->bChipCmdState = val;
137849ab747fSPaolo Bonzini }
137949ab747fSPaolo Bonzini
rtl8139_RxBufferEmpty(RTL8139State * s)138049ab747fSPaolo Bonzini static int rtl8139_RxBufferEmpty(RTL8139State *s)
138149ab747fSPaolo Bonzini {
138249ab747fSPaolo Bonzini int unread = MOD2(s->RxBufferSize + s->RxBufAddr - s->RxBufPtr, s->RxBufferSize);
138349ab747fSPaolo Bonzini
138449ab747fSPaolo Bonzini if (unread != 0)
138549ab747fSPaolo Bonzini {
138649ab747fSPaolo Bonzini DPRINTF("receiver buffer data available 0x%04x\n", unread);
138749ab747fSPaolo Bonzini return 0;
138849ab747fSPaolo Bonzini }
138949ab747fSPaolo Bonzini
139049ab747fSPaolo Bonzini DPRINTF("receiver buffer is empty\n");
139149ab747fSPaolo Bonzini
139249ab747fSPaolo Bonzini return 1;
139349ab747fSPaolo Bonzini }
139449ab747fSPaolo Bonzini
rtl8139_ChipCmd_read(RTL8139State * s)139549ab747fSPaolo Bonzini static uint32_t rtl8139_ChipCmd_read(RTL8139State *s)
139649ab747fSPaolo Bonzini {
139749ab747fSPaolo Bonzini uint32_t ret = s->bChipCmdState;
139849ab747fSPaolo Bonzini
139949ab747fSPaolo Bonzini if (rtl8139_RxBufferEmpty(s))
140049ab747fSPaolo Bonzini ret |= RxBufEmpty;
140149ab747fSPaolo Bonzini
140249ab747fSPaolo Bonzini DPRINTF("ChipCmd read val=0x%04x\n", ret);
140349ab747fSPaolo Bonzini
140449ab747fSPaolo Bonzini return ret;
140549ab747fSPaolo Bonzini }
140649ab747fSPaolo Bonzini
rtl8139_CpCmd_write(RTL8139State * s,uint32_t val)140749ab747fSPaolo Bonzini static void rtl8139_CpCmd_write(RTL8139State *s, uint32_t val)
140849ab747fSPaolo Bonzini {
140949ab747fSPaolo Bonzini val &= 0xffff;
141049ab747fSPaolo Bonzini
141149ab747fSPaolo Bonzini DPRINTF("C+ command register write(w) val=0x%04x\n", val);
141249ab747fSPaolo Bonzini
141349ab747fSPaolo Bonzini s->cplus_enabled = 1;
141449ab747fSPaolo Bonzini
141549ab747fSPaolo Bonzini /* mask unwritable bits */
141649ab747fSPaolo Bonzini val = SET_MASKED(val, 0xff84, s->CpCmd);
141749ab747fSPaolo Bonzini
141849ab747fSPaolo Bonzini s->CpCmd = val;
141949ab747fSPaolo Bonzini }
142049ab747fSPaolo Bonzini
rtl8139_CpCmd_read(RTL8139State * s)142149ab747fSPaolo Bonzini static uint32_t rtl8139_CpCmd_read(RTL8139State *s)
142249ab747fSPaolo Bonzini {
142349ab747fSPaolo Bonzini uint32_t ret = s->CpCmd;
142449ab747fSPaolo Bonzini
142549ab747fSPaolo Bonzini DPRINTF("C+ command register read(w) val=0x%04x\n", ret);
142649ab747fSPaolo Bonzini
142749ab747fSPaolo Bonzini return ret;
142849ab747fSPaolo Bonzini }
142949ab747fSPaolo Bonzini
rtl8139_IntrMitigate_write(RTL8139State * s,uint32_t val)143049ab747fSPaolo Bonzini static void rtl8139_IntrMitigate_write(RTL8139State *s, uint32_t val)
143149ab747fSPaolo Bonzini {
143249ab747fSPaolo Bonzini DPRINTF("C+ IntrMitigate register write(w) val=0x%04x\n", val);
143349ab747fSPaolo Bonzini }
143449ab747fSPaolo Bonzini
rtl8139_IntrMitigate_read(RTL8139State * s)143549ab747fSPaolo Bonzini static uint32_t rtl8139_IntrMitigate_read(RTL8139State *s)
143649ab747fSPaolo Bonzini {
143749ab747fSPaolo Bonzini uint32_t ret = 0;
143849ab747fSPaolo Bonzini
143949ab747fSPaolo Bonzini DPRINTF("C+ IntrMitigate register read(w) val=0x%04x\n", ret);
144049ab747fSPaolo Bonzini
144149ab747fSPaolo Bonzini return ret;
144249ab747fSPaolo Bonzini }
144349ab747fSPaolo Bonzini
rtl8139_config_writable(RTL8139State * s)144449ab747fSPaolo Bonzini static int rtl8139_config_writable(RTL8139State *s)
144549ab747fSPaolo Bonzini {
144649ab747fSPaolo Bonzini if ((s->Cfg9346 & Chip9346_op_mask) == Cfg9346_ConfigWrite)
144749ab747fSPaolo Bonzini {
144849ab747fSPaolo Bonzini return 1;
144949ab747fSPaolo Bonzini }
145049ab747fSPaolo Bonzini
145149ab747fSPaolo Bonzini DPRINTF("Configuration registers are write-protected\n");
145249ab747fSPaolo Bonzini
145349ab747fSPaolo Bonzini return 0;
145449ab747fSPaolo Bonzini }
145549ab747fSPaolo Bonzini
rtl8139_BasicModeCtrl_write(RTL8139State * s,uint32_t val)145649ab747fSPaolo Bonzini static void rtl8139_BasicModeCtrl_write(RTL8139State *s, uint32_t val)
145749ab747fSPaolo Bonzini {
145849ab747fSPaolo Bonzini val &= 0xffff;
145949ab747fSPaolo Bonzini
146049ab747fSPaolo Bonzini DPRINTF("BasicModeCtrl register write(w) val=0x%04x\n", val);
146149ab747fSPaolo Bonzini
146249ab747fSPaolo Bonzini /* mask unwritable bits */
146330a3e701SHervé Poussineau uint32_t mask = 0xccff;
146449ab747fSPaolo Bonzini
146549ab747fSPaolo Bonzini if (1 || !rtl8139_config_writable(s))
146649ab747fSPaolo Bonzini {
146749ab747fSPaolo Bonzini /* Speed setting and autonegotiation enable bits are read-only */
146849ab747fSPaolo Bonzini mask |= 0x3000;
146949ab747fSPaolo Bonzini /* Duplex mode setting is read-only */
147049ab747fSPaolo Bonzini mask |= 0x0100;
147149ab747fSPaolo Bonzini }
147249ab747fSPaolo Bonzini
147330a3e701SHervé Poussineau if (val & 0x8000) {
147430a3e701SHervé Poussineau /* Reset PHY */
147530a3e701SHervé Poussineau rtl8139_reset_phy(s);
147630a3e701SHervé Poussineau }
147730a3e701SHervé Poussineau
147849ab747fSPaolo Bonzini val = SET_MASKED(val, mask, s->BasicModeCtrl);
147949ab747fSPaolo Bonzini
148049ab747fSPaolo Bonzini s->BasicModeCtrl = val;
148149ab747fSPaolo Bonzini }
148249ab747fSPaolo Bonzini
rtl8139_BasicModeCtrl_read(RTL8139State * s)148349ab747fSPaolo Bonzini static uint32_t rtl8139_BasicModeCtrl_read(RTL8139State *s)
148449ab747fSPaolo Bonzini {
148549ab747fSPaolo Bonzini uint32_t ret = s->BasicModeCtrl;
148649ab747fSPaolo Bonzini
148749ab747fSPaolo Bonzini DPRINTF("BasicModeCtrl register read(w) val=0x%04x\n", ret);
148849ab747fSPaolo Bonzini
148949ab747fSPaolo Bonzini return ret;
149049ab747fSPaolo Bonzini }
149149ab747fSPaolo Bonzini
rtl8139_BasicModeStatus_write(RTL8139State * s,uint32_t val)149249ab747fSPaolo Bonzini static void rtl8139_BasicModeStatus_write(RTL8139State *s, uint32_t val)
149349ab747fSPaolo Bonzini {
149449ab747fSPaolo Bonzini val &= 0xffff;
149549ab747fSPaolo Bonzini
149649ab747fSPaolo Bonzini DPRINTF("BasicModeStatus register write(w) val=0x%04x\n", val);
149749ab747fSPaolo Bonzini
149849ab747fSPaolo Bonzini /* mask unwritable bits */
149949ab747fSPaolo Bonzini val = SET_MASKED(val, 0xff3f, s->BasicModeStatus);
150049ab747fSPaolo Bonzini
150149ab747fSPaolo Bonzini s->BasicModeStatus = val;
150249ab747fSPaolo Bonzini }
150349ab747fSPaolo Bonzini
rtl8139_BasicModeStatus_read(RTL8139State * s)150449ab747fSPaolo Bonzini static uint32_t rtl8139_BasicModeStatus_read(RTL8139State *s)
150549ab747fSPaolo Bonzini {
150649ab747fSPaolo Bonzini uint32_t ret = s->BasicModeStatus;
150749ab747fSPaolo Bonzini
150849ab747fSPaolo Bonzini DPRINTF("BasicModeStatus register read(w) val=0x%04x\n", ret);
150949ab747fSPaolo Bonzini
151049ab747fSPaolo Bonzini return ret;
151149ab747fSPaolo Bonzini }
151249ab747fSPaolo Bonzini
rtl8139_Cfg9346_write(RTL8139State * s,uint32_t val)151349ab747fSPaolo Bonzini static void rtl8139_Cfg9346_write(RTL8139State *s, uint32_t val)
151449ab747fSPaolo Bonzini {
151539257515SPeter Crosthwaite DeviceState *d = DEVICE(s);
151639257515SPeter Crosthwaite
151749ab747fSPaolo Bonzini val &= 0xff;
151849ab747fSPaolo Bonzini
151949ab747fSPaolo Bonzini DPRINTF("Cfg9346 write val=0x%02x\n", val);
152049ab747fSPaolo Bonzini
152149ab747fSPaolo Bonzini /* mask unwritable bits */
152249ab747fSPaolo Bonzini val = SET_MASKED(val, 0x31, s->Cfg9346);
152349ab747fSPaolo Bonzini
152449ab747fSPaolo Bonzini uint32_t opmode = val & 0xc0;
152549ab747fSPaolo Bonzini uint32_t eeprom_val = val & 0xf;
152649ab747fSPaolo Bonzini
152749ab747fSPaolo Bonzini if (opmode == 0x80) {
152849ab747fSPaolo Bonzini /* eeprom access */
152949ab747fSPaolo Bonzini int eecs = (eeprom_val & 0x08)?1:0;
153049ab747fSPaolo Bonzini int eesk = (eeprom_val & 0x04)?1:0;
153149ab747fSPaolo Bonzini int eedi = (eeprom_val & 0x02)?1:0;
153249ab747fSPaolo Bonzini prom9346_set_wire(s, eecs, eesk, eedi);
153349ab747fSPaolo Bonzini } else if (opmode == 0x40) {
153449ab747fSPaolo Bonzini /* Reset. */
153549ab747fSPaolo Bonzini val = 0;
153639257515SPeter Crosthwaite rtl8139_reset(d);
153749ab747fSPaolo Bonzini }
153849ab747fSPaolo Bonzini
153949ab747fSPaolo Bonzini s->Cfg9346 = val;
154049ab747fSPaolo Bonzini }
154149ab747fSPaolo Bonzini
rtl8139_Cfg9346_read(RTL8139State * s)154249ab747fSPaolo Bonzini static uint32_t rtl8139_Cfg9346_read(RTL8139State *s)
154349ab747fSPaolo Bonzini {
154449ab747fSPaolo Bonzini uint32_t ret = s->Cfg9346;
154549ab747fSPaolo Bonzini
154649ab747fSPaolo Bonzini uint32_t opmode = ret & 0xc0;
154749ab747fSPaolo Bonzini
154849ab747fSPaolo Bonzini if (opmode == 0x80)
154949ab747fSPaolo Bonzini {
155049ab747fSPaolo Bonzini /* eeprom access */
155149ab747fSPaolo Bonzini int eedo = prom9346_get_wire(s);
155249ab747fSPaolo Bonzini if (eedo)
155349ab747fSPaolo Bonzini {
155449ab747fSPaolo Bonzini ret |= 0x01;
155549ab747fSPaolo Bonzini }
155649ab747fSPaolo Bonzini else
155749ab747fSPaolo Bonzini {
155849ab747fSPaolo Bonzini ret &= ~0x01;
155949ab747fSPaolo Bonzini }
156049ab747fSPaolo Bonzini }
156149ab747fSPaolo Bonzini
156249ab747fSPaolo Bonzini DPRINTF("Cfg9346 read val=0x%02x\n", ret);
156349ab747fSPaolo Bonzini
156449ab747fSPaolo Bonzini return ret;
156549ab747fSPaolo Bonzini }
156649ab747fSPaolo Bonzini
rtl8139_Config0_write(RTL8139State * s,uint32_t val)156749ab747fSPaolo Bonzini static void rtl8139_Config0_write(RTL8139State *s, uint32_t val)
156849ab747fSPaolo Bonzini {
156949ab747fSPaolo Bonzini val &= 0xff;
157049ab747fSPaolo Bonzini
157149ab747fSPaolo Bonzini DPRINTF("Config0 write val=0x%02x\n", val);
157249ab747fSPaolo Bonzini
157349ab747fSPaolo Bonzini if (!rtl8139_config_writable(s)) {
157449ab747fSPaolo Bonzini return;
157549ab747fSPaolo Bonzini }
157649ab747fSPaolo Bonzini
157749ab747fSPaolo Bonzini /* mask unwritable bits */
157849ab747fSPaolo Bonzini val = SET_MASKED(val, 0xf8, s->Config0);
157949ab747fSPaolo Bonzini
158049ab747fSPaolo Bonzini s->Config0 = val;
158149ab747fSPaolo Bonzini }
158249ab747fSPaolo Bonzini
rtl8139_Config0_read(RTL8139State * s)158349ab747fSPaolo Bonzini static uint32_t rtl8139_Config0_read(RTL8139State *s)
158449ab747fSPaolo Bonzini {
158549ab747fSPaolo Bonzini uint32_t ret = s->Config0;
158649ab747fSPaolo Bonzini
158749ab747fSPaolo Bonzini DPRINTF("Config0 read val=0x%02x\n", ret);
158849ab747fSPaolo Bonzini
158949ab747fSPaolo Bonzini return ret;
159049ab747fSPaolo Bonzini }
159149ab747fSPaolo Bonzini
rtl8139_Config1_write(RTL8139State * s,uint32_t val)159249ab747fSPaolo Bonzini static void rtl8139_Config1_write(RTL8139State *s, uint32_t val)
159349ab747fSPaolo Bonzini {
159449ab747fSPaolo Bonzini val &= 0xff;
159549ab747fSPaolo Bonzini
159649ab747fSPaolo Bonzini DPRINTF("Config1 write val=0x%02x\n", val);
159749ab747fSPaolo Bonzini
159849ab747fSPaolo Bonzini if (!rtl8139_config_writable(s)) {
159949ab747fSPaolo Bonzini return;
160049ab747fSPaolo Bonzini }
160149ab747fSPaolo Bonzini
160249ab747fSPaolo Bonzini /* mask unwritable bits */
160349ab747fSPaolo Bonzini val = SET_MASKED(val, 0xC, s->Config1);
160449ab747fSPaolo Bonzini
160549ab747fSPaolo Bonzini s->Config1 = val;
160649ab747fSPaolo Bonzini }
160749ab747fSPaolo Bonzini
rtl8139_Config1_read(RTL8139State * s)160849ab747fSPaolo Bonzini static uint32_t rtl8139_Config1_read(RTL8139State *s)
160949ab747fSPaolo Bonzini {
161049ab747fSPaolo Bonzini uint32_t ret = s->Config1;
161149ab747fSPaolo Bonzini
161249ab747fSPaolo Bonzini DPRINTF("Config1 read val=0x%02x\n", ret);
161349ab747fSPaolo Bonzini
161449ab747fSPaolo Bonzini return ret;
161549ab747fSPaolo Bonzini }
161649ab747fSPaolo Bonzini
rtl8139_Config3_write(RTL8139State * s,uint32_t val)161749ab747fSPaolo Bonzini static void rtl8139_Config3_write(RTL8139State *s, uint32_t val)
161849ab747fSPaolo Bonzini {
161949ab747fSPaolo Bonzini val &= 0xff;
162049ab747fSPaolo Bonzini
162149ab747fSPaolo Bonzini DPRINTF("Config3 write val=0x%02x\n", val);
162249ab747fSPaolo Bonzini
162349ab747fSPaolo Bonzini if (!rtl8139_config_writable(s)) {
162449ab747fSPaolo Bonzini return;
162549ab747fSPaolo Bonzini }
162649ab747fSPaolo Bonzini
162749ab747fSPaolo Bonzini /* mask unwritable bits */
162849ab747fSPaolo Bonzini val = SET_MASKED(val, 0x8F, s->Config3);
162949ab747fSPaolo Bonzini
163049ab747fSPaolo Bonzini s->Config3 = val;
163149ab747fSPaolo Bonzini }
163249ab747fSPaolo Bonzini
rtl8139_Config3_read(RTL8139State * s)163349ab747fSPaolo Bonzini static uint32_t rtl8139_Config3_read(RTL8139State *s)
163449ab747fSPaolo Bonzini {
163549ab747fSPaolo Bonzini uint32_t ret = s->Config3;
163649ab747fSPaolo Bonzini
163749ab747fSPaolo Bonzini DPRINTF("Config3 read val=0x%02x\n", ret);
163849ab747fSPaolo Bonzini
163949ab747fSPaolo Bonzini return ret;
164049ab747fSPaolo Bonzini }
164149ab747fSPaolo Bonzini
rtl8139_Config4_write(RTL8139State * s,uint32_t val)164249ab747fSPaolo Bonzini static void rtl8139_Config4_write(RTL8139State *s, uint32_t val)
164349ab747fSPaolo Bonzini {
164449ab747fSPaolo Bonzini val &= 0xff;
164549ab747fSPaolo Bonzini
164649ab747fSPaolo Bonzini DPRINTF("Config4 write val=0x%02x\n", val);
164749ab747fSPaolo Bonzini
164849ab747fSPaolo Bonzini if (!rtl8139_config_writable(s)) {
164949ab747fSPaolo Bonzini return;
165049ab747fSPaolo Bonzini }
165149ab747fSPaolo Bonzini
165249ab747fSPaolo Bonzini /* mask unwritable bits */
165349ab747fSPaolo Bonzini val = SET_MASKED(val, 0x0a, s->Config4);
165449ab747fSPaolo Bonzini
165549ab747fSPaolo Bonzini s->Config4 = val;
165649ab747fSPaolo Bonzini }
165749ab747fSPaolo Bonzini
rtl8139_Config4_read(RTL8139State * s)165849ab747fSPaolo Bonzini static uint32_t rtl8139_Config4_read(RTL8139State *s)
165949ab747fSPaolo Bonzini {
166049ab747fSPaolo Bonzini uint32_t ret = s->Config4;
166149ab747fSPaolo Bonzini
166249ab747fSPaolo Bonzini DPRINTF("Config4 read val=0x%02x\n", ret);
166349ab747fSPaolo Bonzini
166449ab747fSPaolo Bonzini return ret;
166549ab747fSPaolo Bonzini }
166649ab747fSPaolo Bonzini
rtl8139_Config5_write(RTL8139State * s,uint32_t val)166749ab747fSPaolo Bonzini static void rtl8139_Config5_write(RTL8139State *s, uint32_t val)
166849ab747fSPaolo Bonzini {
166949ab747fSPaolo Bonzini val &= 0xff;
167049ab747fSPaolo Bonzini
167149ab747fSPaolo Bonzini DPRINTF("Config5 write val=0x%02x\n", val);
167249ab747fSPaolo Bonzini
167349ab747fSPaolo Bonzini /* mask unwritable bits */
167449ab747fSPaolo Bonzini val = SET_MASKED(val, 0x80, s->Config5);
167549ab747fSPaolo Bonzini
167649ab747fSPaolo Bonzini s->Config5 = val;
167749ab747fSPaolo Bonzini }
167849ab747fSPaolo Bonzini
rtl8139_Config5_read(RTL8139State * s)167949ab747fSPaolo Bonzini static uint32_t rtl8139_Config5_read(RTL8139State *s)
168049ab747fSPaolo Bonzini {
168149ab747fSPaolo Bonzini uint32_t ret = s->Config5;
168249ab747fSPaolo Bonzini
168349ab747fSPaolo Bonzini DPRINTF("Config5 read val=0x%02x\n", ret);
168449ab747fSPaolo Bonzini
168549ab747fSPaolo Bonzini return ret;
168649ab747fSPaolo Bonzini }
168749ab747fSPaolo Bonzini
rtl8139_TxConfig_write(RTL8139State * s,uint32_t val)168849ab747fSPaolo Bonzini static void rtl8139_TxConfig_write(RTL8139State *s, uint32_t val)
168949ab747fSPaolo Bonzini {
169049ab747fSPaolo Bonzini if (!rtl8139_transmitter_enabled(s))
169149ab747fSPaolo Bonzini {
169249ab747fSPaolo Bonzini DPRINTF("transmitter disabled; no TxConfig write val=0x%08x\n", val);
169349ab747fSPaolo Bonzini return;
169449ab747fSPaolo Bonzini }
169549ab747fSPaolo Bonzini
169649ab747fSPaolo Bonzini DPRINTF("TxConfig write val=0x%08x\n", val);
169749ab747fSPaolo Bonzini
169849ab747fSPaolo Bonzini val = SET_MASKED(val, TxVersionMask | 0x8070f80f, s->TxConfig);
169949ab747fSPaolo Bonzini
170049ab747fSPaolo Bonzini s->TxConfig = val;
170149ab747fSPaolo Bonzini }
170249ab747fSPaolo Bonzini
rtl8139_TxConfig_writeb(RTL8139State * s,uint32_t val)170349ab747fSPaolo Bonzini static void rtl8139_TxConfig_writeb(RTL8139State *s, uint32_t val)
170449ab747fSPaolo Bonzini {
170549ab747fSPaolo Bonzini DPRINTF("RTL8139C TxConfig via write(b) val=0x%02x\n", val);
170649ab747fSPaolo Bonzini
170749ab747fSPaolo Bonzini uint32_t tc = s->TxConfig;
170849ab747fSPaolo Bonzini tc &= 0xFFFFFF00;
170949ab747fSPaolo Bonzini tc |= (val & 0x000000FF);
171049ab747fSPaolo Bonzini rtl8139_TxConfig_write(s, tc);
171149ab747fSPaolo Bonzini }
171249ab747fSPaolo Bonzini
rtl8139_TxConfig_read(RTL8139State * s)171349ab747fSPaolo Bonzini static uint32_t rtl8139_TxConfig_read(RTL8139State *s)
171449ab747fSPaolo Bonzini {
171549ab747fSPaolo Bonzini uint32_t ret = s->TxConfig;
171649ab747fSPaolo Bonzini
171749ab747fSPaolo Bonzini DPRINTF("TxConfig read val=0x%04x\n", ret);
171849ab747fSPaolo Bonzini
171949ab747fSPaolo Bonzini return ret;
172049ab747fSPaolo Bonzini }
172149ab747fSPaolo Bonzini
rtl8139_RxConfig_write(RTL8139State * s,uint32_t val)172249ab747fSPaolo Bonzini static void rtl8139_RxConfig_write(RTL8139State *s, uint32_t val)
172349ab747fSPaolo Bonzini {
172449ab747fSPaolo Bonzini DPRINTF("RxConfig write val=0x%08x\n", val);
172549ab747fSPaolo Bonzini
172649ab747fSPaolo Bonzini /* mask unwritable bits */
172749ab747fSPaolo Bonzini val = SET_MASKED(val, 0xf0fc0040, s->RxConfig);
172849ab747fSPaolo Bonzini
172949ab747fSPaolo Bonzini s->RxConfig = val;
173049ab747fSPaolo Bonzini
173149ab747fSPaolo Bonzini /* reset buffer size and read/write pointers */
173249ab747fSPaolo Bonzini rtl8139_reset_rxring(s, 8192 << ((s->RxConfig >> 11) & 0x3));
173349ab747fSPaolo Bonzini
173449ab747fSPaolo Bonzini DPRINTF("RxConfig write reset buffer size to %d\n", s->RxBufferSize);
173549ab747fSPaolo Bonzini }
173649ab747fSPaolo Bonzini
rtl8139_RxConfig_read(RTL8139State * s)173749ab747fSPaolo Bonzini static uint32_t rtl8139_RxConfig_read(RTL8139State *s)
173849ab747fSPaolo Bonzini {
173949ab747fSPaolo Bonzini uint32_t ret = s->RxConfig;
174049ab747fSPaolo Bonzini
174149ab747fSPaolo Bonzini DPRINTF("RxConfig read val=0x%08x\n", ret);
174249ab747fSPaolo Bonzini
174349ab747fSPaolo Bonzini return ret;
174449ab747fSPaolo Bonzini }
174549ab747fSPaolo Bonzini
rtl8139_transfer_frame(RTL8139State * s,uint8_t * buf,int size,int do_interrupt,const uint8_t * dot1q_buf)174649ab747fSPaolo Bonzini static void rtl8139_transfer_frame(RTL8139State *s, uint8_t *buf, int size,
174749ab747fSPaolo Bonzini int do_interrupt, const uint8_t *dot1q_buf)
174849ab747fSPaolo Bonzini {
174949ab747fSPaolo Bonzini struct iovec *iov = NULL;
1750b0af8440SGonglei struct iovec vlan_iov[3];
175149ab747fSPaolo Bonzini
175249ab747fSPaolo Bonzini if (!size)
175349ab747fSPaolo Bonzini {
175449ab747fSPaolo Bonzini DPRINTF("+++ empty ethernet frame\n");
175549ab747fSPaolo Bonzini return;
175649ab747fSPaolo Bonzini }
175749ab747fSPaolo Bonzini
17581bf11332SStefan Hajnoczi if (dot1q_buf && size >= ETH_ALEN * 2) {
175949ab747fSPaolo Bonzini iov = (struct iovec[3]) {
17601bf11332SStefan Hajnoczi { .iov_base = buf, .iov_len = ETH_ALEN * 2 },
176149ab747fSPaolo Bonzini { .iov_base = (void *) dot1q_buf, .iov_len = VLAN_HLEN },
17621bf11332SStefan Hajnoczi { .iov_base = buf + ETH_ALEN * 2,
17631bf11332SStefan Hajnoczi .iov_len = size - ETH_ALEN * 2 },
176449ab747fSPaolo Bonzini };
1765b0af8440SGonglei
1766b0af8440SGonglei memcpy(vlan_iov, iov, sizeof(vlan_iov));
1767b0af8440SGonglei iov = vlan_iov;
176849ab747fSPaolo Bonzini }
176949ab747fSPaolo Bonzini
177049ab747fSPaolo Bonzini if (TxLoopBack == (s->TxConfig & TxLoopBack))
177149ab747fSPaolo Bonzini {
177249ab747fSPaolo Bonzini size_t buf2_size;
177349ab747fSPaolo Bonzini uint8_t *buf2;
177449ab747fSPaolo Bonzini
177549ab747fSPaolo Bonzini if (iov) {
177649ab747fSPaolo Bonzini buf2_size = iov_size(iov, 3);
177749ab747fSPaolo Bonzini buf2 = g_malloc(buf2_size);
177849ab747fSPaolo Bonzini iov_to_buf(iov, 3, 0, buf2, buf2_size);
177949ab747fSPaolo Bonzini buf = buf2;
178049ab747fSPaolo Bonzini }
178149ab747fSPaolo Bonzini
178249ab747fSPaolo Bonzini DPRINTF("+++ transmit loopback mode\n");
17835311fb80SAlexander Bulekov qemu_receive_packet(qemu_get_queue(s->nic), buf, size);
178449ab747fSPaolo Bonzini
178549ab747fSPaolo Bonzini if (iov) {
178649ab747fSPaolo Bonzini g_free(buf2);
178749ab747fSPaolo Bonzini }
178849ab747fSPaolo Bonzini }
178949ab747fSPaolo Bonzini else
179049ab747fSPaolo Bonzini {
179149ab747fSPaolo Bonzini if (iov) {
179249ab747fSPaolo Bonzini qemu_sendv_packet(qemu_get_queue(s->nic), iov, 3);
179349ab747fSPaolo Bonzini } else {
179449ab747fSPaolo Bonzini qemu_send_packet(qemu_get_queue(s->nic), buf, size);
179549ab747fSPaolo Bonzini }
179649ab747fSPaolo Bonzini }
179749ab747fSPaolo Bonzini }
179849ab747fSPaolo Bonzini
rtl8139_transmit_one(RTL8139State * s,int descriptor)179949ab747fSPaolo Bonzini static int rtl8139_transmit_one(RTL8139State *s, int descriptor)
180049ab747fSPaolo Bonzini {
180149ab747fSPaolo Bonzini if (!rtl8139_transmitter_enabled(s))
180249ab747fSPaolo Bonzini {
180349ab747fSPaolo Bonzini DPRINTF("+++ cannot transmit from descriptor %d: transmitter "
180449ab747fSPaolo Bonzini "disabled\n", descriptor);
180549ab747fSPaolo Bonzini return 0;
180649ab747fSPaolo Bonzini }
180749ab747fSPaolo Bonzini
180849ab747fSPaolo Bonzini if (s->TxStatus[descriptor] & TxHostOwns)
180949ab747fSPaolo Bonzini {
181049ab747fSPaolo Bonzini DPRINTF("+++ cannot transmit from descriptor %d: owned by host "
181149ab747fSPaolo Bonzini "(%08x)\n", descriptor, s->TxStatus[descriptor]);
181249ab747fSPaolo Bonzini return 0;
181349ab747fSPaolo Bonzini }
181449ab747fSPaolo Bonzini
181549ab747fSPaolo Bonzini DPRINTF("+++ transmitting from descriptor %d\n", descriptor);
181649ab747fSPaolo Bonzini
181788a411a8SAndreas Färber PCIDevice *d = PCI_DEVICE(s);
181849ab747fSPaolo Bonzini int txsize = s->TxStatus[descriptor] & 0x1fff;
181949ab747fSPaolo Bonzini uint8_t txbuffer[0x2000];
182049ab747fSPaolo Bonzini
182149ab747fSPaolo Bonzini DPRINTF("+++ transmit reading %d bytes from host memory at 0x%08x\n",
182249ab747fSPaolo Bonzini txsize, s->TxAddr[descriptor]);
182349ab747fSPaolo Bonzini
182488a411a8SAndreas Färber pci_dma_read(d, s->TxAddr[descriptor], txbuffer, txsize);
182549ab747fSPaolo Bonzini
182649ab747fSPaolo Bonzini /* Mark descriptor as transferred */
182749ab747fSPaolo Bonzini s->TxStatus[descriptor] |= TxHostOwns;
182849ab747fSPaolo Bonzini s->TxStatus[descriptor] |= TxStatOK;
182949ab747fSPaolo Bonzini
183049ab747fSPaolo Bonzini rtl8139_transfer_frame(s, txbuffer, txsize, 0, NULL);
183149ab747fSPaolo Bonzini
183249ab747fSPaolo Bonzini DPRINTF("+++ transmitted %d bytes from descriptor %d\n", txsize,
183349ab747fSPaolo Bonzini descriptor);
183449ab747fSPaolo Bonzini
183549ab747fSPaolo Bonzini /* update interrupt */
183649ab747fSPaolo Bonzini s->IntrStatus |= TxOK;
183749ab747fSPaolo Bonzini rtl8139_update_irq(s);
183849ab747fSPaolo Bonzini
183949ab747fSPaolo Bonzini return 1;
184049ab747fSPaolo Bonzini }
184149ab747fSPaolo Bonzini
184249ab747fSPaolo Bonzini #define TCP_HEADER_CLEAR_FLAGS(tcp, off) ((tcp)->th_offset_flags &= cpu_to_be16(~TCP_FLAGS_ONLY(off)))
184349ab747fSPaolo Bonzini
184449ab747fSPaolo Bonzini /* produces ones' complement sum of data */
ones_complement_sum(uint8_t * data,size_t len)184549ab747fSPaolo Bonzini static uint16_t ones_complement_sum(uint8_t *data, size_t len)
184649ab747fSPaolo Bonzini {
184749ab747fSPaolo Bonzini uint32_t result = 0;
184849ab747fSPaolo Bonzini
184949ab747fSPaolo Bonzini for (; len > 1; data+=2, len-=2)
185049ab747fSPaolo Bonzini {
185149ab747fSPaolo Bonzini result += *(uint16_t*)data;
185249ab747fSPaolo Bonzini }
185349ab747fSPaolo Bonzini
185449ab747fSPaolo Bonzini /* add the remainder byte */
185549ab747fSPaolo Bonzini if (len)
185649ab747fSPaolo Bonzini {
185749ab747fSPaolo Bonzini uint8_t odd[2] = {*data, 0};
185849ab747fSPaolo Bonzini result += *(uint16_t*)odd;
185949ab747fSPaolo Bonzini }
186049ab747fSPaolo Bonzini
186149ab747fSPaolo Bonzini while (result>>16)
186249ab747fSPaolo Bonzini result = (result & 0xffff) + (result >> 16);
186349ab747fSPaolo Bonzini
186449ab747fSPaolo Bonzini return result;
186549ab747fSPaolo Bonzini }
186649ab747fSPaolo Bonzini
ip_checksum(void * data,size_t len)186749ab747fSPaolo Bonzini static uint16_t ip_checksum(void *data, size_t len)
186849ab747fSPaolo Bonzini {
186949ab747fSPaolo Bonzini return ~ones_complement_sum((uint8_t*)data, len);
187049ab747fSPaolo Bonzini }
187149ab747fSPaolo Bonzini
rtl8139_cplus_transmit_one(RTL8139State * s)187249ab747fSPaolo Bonzini static int rtl8139_cplus_transmit_one(RTL8139State *s)
187349ab747fSPaolo Bonzini {
187449ab747fSPaolo Bonzini if (!rtl8139_transmitter_enabled(s))
187549ab747fSPaolo Bonzini {
187649ab747fSPaolo Bonzini DPRINTF("+++ C+ mode: transmitter disabled\n");
187749ab747fSPaolo Bonzini return 0;
187849ab747fSPaolo Bonzini }
187949ab747fSPaolo Bonzini
188049ab747fSPaolo Bonzini if (!rtl8139_cp_transmitter_enabled(s))
188149ab747fSPaolo Bonzini {
188249ab747fSPaolo Bonzini DPRINTF("+++ C+ mode: C+ transmitter disabled\n");
188349ab747fSPaolo Bonzini return 0 ;
188449ab747fSPaolo Bonzini }
188549ab747fSPaolo Bonzini
188688a411a8SAndreas Färber PCIDevice *d = PCI_DEVICE(s);
188749ab747fSPaolo Bonzini int descriptor = s->currCPlusTxDesc;
188849ab747fSPaolo Bonzini
188949ab747fSPaolo Bonzini dma_addr_t cplus_tx_ring_desc = rtl8139_addr64(s->TxAddr[0], s->TxAddr[1]);
189049ab747fSPaolo Bonzini
189149ab747fSPaolo Bonzini /* Normal priority ring */
189249ab747fSPaolo Bonzini cplus_tx_ring_desc += 16 * descriptor;
189349ab747fSPaolo Bonzini
189449ab747fSPaolo Bonzini DPRINTF("+++ C+ mode reading TX descriptor %d from host memory at "
189549ab747fSPaolo Bonzini "%08x %08x = 0x"DMA_ADDR_FMT"\n", descriptor, s->TxAddr[1],
189649ab747fSPaolo Bonzini s->TxAddr[0], cplus_tx_ring_desc);
189749ab747fSPaolo Bonzini
189849ab747fSPaolo Bonzini uint32_t val, txdw0,txdw1,txbufLO,txbufHI;
189949ab747fSPaolo Bonzini
190088a411a8SAndreas Färber pci_dma_read(d, cplus_tx_ring_desc, (uint8_t *)&val, 4);
190149ab747fSPaolo Bonzini txdw0 = le32_to_cpu(val);
190288a411a8SAndreas Färber pci_dma_read(d, cplus_tx_ring_desc+4, (uint8_t *)&val, 4);
190349ab747fSPaolo Bonzini txdw1 = le32_to_cpu(val);
190488a411a8SAndreas Färber pci_dma_read(d, cplus_tx_ring_desc+8, (uint8_t *)&val, 4);
190549ab747fSPaolo Bonzini txbufLO = le32_to_cpu(val);
190688a411a8SAndreas Färber pci_dma_read(d, cplus_tx_ring_desc+12, (uint8_t *)&val, 4);
190749ab747fSPaolo Bonzini txbufHI = le32_to_cpu(val);
190849ab747fSPaolo Bonzini
190949ab747fSPaolo Bonzini DPRINTF("+++ C+ mode TX descriptor %d %08x %08x %08x %08x\n", descriptor,
191049ab747fSPaolo Bonzini txdw0, txdw1, txbufLO, txbufHI);
191149ab747fSPaolo Bonzini
191249ab747fSPaolo Bonzini /* w0 ownership flag */
191349ab747fSPaolo Bonzini #define CP_TX_OWN (1<<31)
191449ab747fSPaolo Bonzini /* w0 end of ring flag */
191549ab747fSPaolo Bonzini #define CP_TX_EOR (1<<30)
191649ab747fSPaolo Bonzini /* first segment of received packet flag */
191749ab747fSPaolo Bonzini #define CP_TX_FS (1<<29)
191849ab747fSPaolo Bonzini /* last segment of received packet flag */
191949ab747fSPaolo Bonzini #define CP_TX_LS (1<<28)
192049ab747fSPaolo Bonzini /* large send packet flag */
192149ab747fSPaolo Bonzini #define CP_TX_LGSEN (1<<27)
19226d71357aSStefan Hajnoczi /* large send MSS mask, bits 16...26 */
19236d71357aSStefan Hajnoczi #define CP_TC_LGSEN_MSS_SHIFT 16
19246d71357aSStefan Hajnoczi #define CP_TC_LGSEN_MSS_MASK ((1 << 11) - 1)
192549ab747fSPaolo Bonzini
192649ab747fSPaolo Bonzini /* IP checksum offload flag */
192749ab747fSPaolo Bonzini #define CP_TX_IPCS (1<<18)
192849ab747fSPaolo Bonzini /* UDP checksum offload flag */
192949ab747fSPaolo Bonzini #define CP_TX_UDPCS (1<<17)
193049ab747fSPaolo Bonzini /* TCP checksum offload flag */
193149ab747fSPaolo Bonzini #define CP_TX_TCPCS (1<<16)
193249ab747fSPaolo Bonzini
193349ab747fSPaolo Bonzini /* w0 bits 0...15 : buffer size */
193449ab747fSPaolo Bonzini #define CP_TX_BUFFER_SIZE (1<<16)
193549ab747fSPaolo Bonzini #define CP_TX_BUFFER_SIZE_MASK (CP_TX_BUFFER_SIZE - 1)
193649ab747fSPaolo Bonzini /* w1 add tag flag */
193749ab747fSPaolo Bonzini #define CP_TX_TAGC (1<<17)
193849ab747fSPaolo Bonzini /* w1 bits 0...15 : VLAN tag (big endian) */
193949ab747fSPaolo Bonzini #define CP_TX_VLAN_TAG_MASK ((1<<16) - 1)
194049ab747fSPaolo Bonzini /* w2 low 32bit of Rx buffer ptr */
194149ab747fSPaolo Bonzini /* w3 high 32bit of Rx buffer ptr */
194249ab747fSPaolo Bonzini
194349ab747fSPaolo Bonzini /* set after transmission */
194449ab747fSPaolo Bonzini /* FIFO underrun flag */
194549ab747fSPaolo Bonzini #define CP_TX_STATUS_UNF (1<<25)
194649ab747fSPaolo Bonzini /* transmit error summary flag, valid if set any of three below */
194749ab747fSPaolo Bonzini #define CP_TX_STATUS_TES (1<<23)
194849ab747fSPaolo Bonzini /* out-of-window collision flag */
194949ab747fSPaolo Bonzini #define CP_TX_STATUS_OWC (1<<22)
195049ab747fSPaolo Bonzini /* link failure flag */
195149ab747fSPaolo Bonzini #define CP_TX_STATUS_LNKF (1<<21)
195249ab747fSPaolo Bonzini /* excessive collisions flag */
195349ab747fSPaolo Bonzini #define CP_TX_STATUS_EXC (1<<20)
195449ab747fSPaolo Bonzini
195549ab747fSPaolo Bonzini if (!(txdw0 & CP_TX_OWN))
195649ab747fSPaolo Bonzini {
195749ab747fSPaolo Bonzini DPRINTF("C+ Tx mode : descriptor %d is owned by host\n", descriptor);
195849ab747fSPaolo Bonzini return 0 ;
195949ab747fSPaolo Bonzini }
196049ab747fSPaolo Bonzini
196149ab747fSPaolo Bonzini DPRINTF("+++ C+ Tx mode : transmitting from descriptor %d\n", descriptor);
196249ab747fSPaolo Bonzini
196349ab747fSPaolo Bonzini if (txdw0 & CP_TX_FS)
196449ab747fSPaolo Bonzini {
196549ab747fSPaolo Bonzini DPRINTF("+++ C+ Tx mode : descriptor %d is first segment "
196649ab747fSPaolo Bonzini "descriptor\n", descriptor);
196749ab747fSPaolo Bonzini
196849ab747fSPaolo Bonzini /* reset internal buffer offset */
196949ab747fSPaolo Bonzini s->cplus_txbuffer_offset = 0;
197049ab747fSPaolo Bonzini }
197149ab747fSPaolo Bonzini
197249ab747fSPaolo Bonzini int txsize = txdw0 & CP_TX_BUFFER_SIZE_MASK;
197349ab747fSPaolo Bonzini dma_addr_t tx_addr = rtl8139_addr64(txbufLO, txbufHI);
197449ab747fSPaolo Bonzini
197549ab747fSPaolo Bonzini /* make sure we have enough space to assemble the packet */
197649ab747fSPaolo Bonzini if (!s->cplus_txbuffer)
197749ab747fSPaolo Bonzini {
197849ab747fSPaolo Bonzini s->cplus_txbuffer_len = CP_TX_BUFFER_SIZE;
197949ab747fSPaolo Bonzini s->cplus_txbuffer = g_malloc(s->cplus_txbuffer_len);
198049ab747fSPaolo Bonzini s->cplus_txbuffer_offset = 0;
198149ab747fSPaolo Bonzini
198249ab747fSPaolo Bonzini DPRINTF("+++ C+ mode transmission buffer allocated space %d\n",
198349ab747fSPaolo Bonzini s->cplus_txbuffer_len);
198449ab747fSPaolo Bonzini }
198549ab747fSPaolo Bonzini
198649ab747fSPaolo Bonzini if (s->cplus_txbuffer_offset + txsize >= s->cplus_txbuffer_len)
198749ab747fSPaolo Bonzini {
198849ab747fSPaolo Bonzini /* The spec didn't tell the maximum size, stick to CP_TX_BUFFER_SIZE */
198949ab747fSPaolo Bonzini txsize = s->cplus_txbuffer_len - s->cplus_txbuffer_offset;
199049ab747fSPaolo Bonzini DPRINTF("+++ C+ mode transmission buffer overrun, truncated descriptor"
199149ab747fSPaolo Bonzini "length to %d\n", txsize);
199249ab747fSPaolo Bonzini }
199349ab747fSPaolo Bonzini
199449ab747fSPaolo Bonzini /* append more data to the packet */
199549ab747fSPaolo Bonzini
199649ab747fSPaolo Bonzini DPRINTF("+++ C+ mode transmit reading %d bytes from host memory at "
199749ab747fSPaolo Bonzini DMA_ADDR_FMT" to offset %d\n", txsize, tx_addr,
199849ab747fSPaolo Bonzini s->cplus_txbuffer_offset);
199949ab747fSPaolo Bonzini
200088a411a8SAndreas Färber pci_dma_read(d, tx_addr,
200149ab747fSPaolo Bonzini s->cplus_txbuffer + s->cplus_txbuffer_offset, txsize);
200249ab747fSPaolo Bonzini s->cplus_txbuffer_offset += txsize;
200349ab747fSPaolo Bonzini
200449ab747fSPaolo Bonzini /* seek to next Rx descriptor */
200549ab747fSPaolo Bonzini if (txdw0 & CP_TX_EOR)
200649ab747fSPaolo Bonzini {
200749ab747fSPaolo Bonzini s->currCPlusTxDesc = 0;
200849ab747fSPaolo Bonzini }
200949ab747fSPaolo Bonzini else
201049ab747fSPaolo Bonzini {
201149ab747fSPaolo Bonzini ++s->currCPlusTxDesc;
201249ab747fSPaolo Bonzini if (s->currCPlusTxDesc >= 64)
201349ab747fSPaolo Bonzini s->currCPlusTxDesc = 0;
201449ab747fSPaolo Bonzini }
201549ab747fSPaolo Bonzini
2016bd142b23SStefan Hajnoczi /* Build the Tx Status Descriptor */
2017bd142b23SStefan Hajnoczi uint32_t tx_status = txdw0;
2018bd142b23SStefan Hajnoczi
201949ab747fSPaolo Bonzini /* transfer ownership to target */
2020bd142b23SStefan Hajnoczi tx_status &= ~CP_TX_OWN;
202149ab747fSPaolo Bonzini
202249ab747fSPaolo Bonzini /* reset error indicator bits */
2023bd142b23SStefan Hajnoczi tx_status &= ~CP_TX_STATUS_UNF;
2024bd142b23SStefan Hajnoczi tx_status &= ~CP_TX_STATUS_TES;
2025bd142b23SStefan Hajnoczi tx_status &= ~CP_TX_STATUS_OWC;
2026bd142b23SStefan Hajnoczi tx_status &= ~CP_TX_STATUS_LNKF;
2027bd142b23SStefan Hajnoczi tx_status &= ~CP_TX_STATUS_EXC;
202849ab747fSPaolo Bonzini
202949ab747fSPaolo Bonzini /* update ring data */
2030bd142b23SStefan Hajnoczi val = cpu_to_le32(tx_status);
203188a411a8SAndreas Färber pci_dma_write(d, cplus_tx_ring_desc, (uint8_t *)&val, 4);
203249ab747fSPaolo Bonzini
203349ab747fSPaolo Bonzini /* Now decide if descriptor being processed is holding the last segment of packet */
203449ab747fSPaolo Bonzini if (txdw0 & CP_TX_LS)
203549ab747fSPaolo Bonzini {
203649ab747fSPaolo Bonzini uint8_t dot1q_buffer_space[VLAN_HLEN];
203749ab747fSPaolo Bonzini uint16_t *dot1q_buffer;
203849ab747fSPaolo Bonzini
203949ab747fSPaolo Bonzini DPRINTF("+++ C+ Tx mode : descriptor %d is last segment descriptor\n",
204049ab747fSPaolo Bonzini descriptor);
204149ab747fSPaolo Bonzini
204249ab747fSPaolo Bonzini /* can transfer fully assembled packet */
204349ab747fSPaolo Bonzini
204449ab747fSPaolo Bonzini uint8_t *saved_buffer = s->cplus_txbuffer;
204549ab747fSPaolo Bonzini int saved_size = s->cplus_txbuffer_offset;
204649ab747fSPaolo Bonzini int saved_buffer_len = s->cplus_txbuffer_len;
204749ab747fSPaolo Bonzini
204849ab747fSPaolo Bonzini /* create vlan tag */
204949ab747fSPaolo Bonzini if (txdw1 & CP_TX_TAGC) {
205049ab747fSPaolo Bonzini /* the vlan tag is in BE byte order in the descriptor
205149ab747fSPaolo Bonzini * BE + le_to_cpu() + ~swap()~ = cpu */
205249ab747fSPaolo Bonzini DPRINTF("+++ C+ Tx mode : inserting vlan tag with ""tci: %u\n",
205349ab747fSPaolo Bonzini bswap16(txdw1 & CP_TX_VLAN_TAG_MASK));
205449ab747fSPaolo Bonzini
205549ab747fSPaolo Bonzini dot1q_buffer = (uint16_t *) dot1q_buffer_space;
20561bf11332SStefan Hajnoczi dot1q_buffer[0] = cpu_to_be16(ETH_P_VLAN);
205749ab747fSPaolo Bonzini /* BE + le_to_cpu() + ~cpu_to_le()~ = BE */
205849ab747fSPaolo Bonzini dot1q_buffer[1] = cpu_to_le16(txdw1 & CP_TX_VLAN_TAG_MASK);
205949ab747fSPaolo Bonzini } else {
206049ab747fSPaolo Bonzini dot1q_buffer = NULL;
206149ab747fSPaolo Bonzini }
206249ab747fSPaolo Bonzini
206349ab747fSPaolo Bonzini /* reset the card space to protect from recursive call */
206449ab747fSPaolo Bonzini s->cplus_txbuffer = NULL;
206549ab747fSPaolo Bonzini s->cplus_txbuffer_offset = 0;
206649ab747fSPaolo Bonzini s->cplus_txbuffer_len = 0;
206749ab747fSPaolo Bonzini
206849ab747fSPaolo Bonzini if (txdw0 & (CP_TX_IPCS | CP_TX_UDPCS | CP_TX_TCPCS | CP_TX_LGSEN))
206949ab747fSPaolo Bonzini {
207049ab747fSPaolo Bonzini DPRINTF("+++ C+ mode offloaded task checksum\n");
207149ab747fSPaolo Bonzini
2072e1c120a9SStefan Hajnoczi /* Large enough for Ethernet and IP headers? */
20735d61721aSStefan Hajnoczi if (saved_size < ETH_HLEN + sizeof(struct ip_header)) {
2074e1c120a9SStefan Hajnoczi goto skip_offload;
2075e1c120a9SStefan Hajnoczi }
2076e1c120a9SStefan Hajnoczi
207749ab747fSPaolo Bonzini /* ip packet header */
20785d61721aSStefan Hajnoczi struct ip_header *ip = NULL;
207949ab747fSPaolo Bonzini int hlen = 0;
208049ab747fSPaolo Bonzini uint8_t ip_protocol = 0;
208149ab747fSPaolo Bonzini uint16_t ip_data_len = 0;
208249ab747fSPaolo Bonzini
208349ab747fSPaolo Bonzini uint8_t *eth_payload_data = NULL;
208449ab747fSPaolo Bonzini size_t eth_payload_len = 0;
208549ab747fSPaolo Bonzini
208649ab747fSPaolo Bonzini int proto = be16_to_cpu(*(uint16_t *)(saved_buffer + 12));
208739b8e7dcSStefan Hajnoczi if (proto != ETH_P_IP)
208849ab747fSPaolo Bonzini {
208939b8e7dcSStefan Hajnoczi goto skip_offload;
209039b8e7dcSStefan Hajnoczi }
209139b8e7dcSStefan Hajnoczi
209249ab747fSPaolo Bonzini DPRINTF("+++ C+ mode has IP packet\n");
209349ab747fSPaolo Bonzini
209426c0114dSStefan Hajnoczi /* Note on memory alignment: eth_payload_data is 16-bit aligned
209526c0114dSStefan Hajnoczi * since saved_buffer is allocated with g_malloc() and ETH_HLEN is
209626c0114dSStefan Hajnoczi * even. 32-bit accesses must use ldl/stl wrappers to avoid
209726c0114dSStefan Hajnoczi * unaligned accesses.
209826c0114dSStefan Hajnoczi */
209949ab747fSPaolo Bonzini eth_payload_data = saved_buffer + ETH_HLEN;
210049ab747fSPaolo Bonzini eth_payload_len = saved_size - ETH_HLEN;
210149ab747fSPaolo Bonzini
21025d61721aSStefan Hajnoczi ip = (struct ip_header*)eth_payload_data;
210349ab747fSPaolo Bonzini
210449ab747fSPaolo Bonzini if (IP_HEADER_VERSION(ip) != IP_HEADER_VERSION_4) {
210549ab747fSPaolo Bonzini DPRINTF("+++ C+ mode packet has bad IP version %d "
210649ab747fSPaolo Bonzini "expected %d\n", IP_HEADER_VERSION(ip),
210749ab747fSPaolo Bonzini IP_HEADER_VERSION_4);
210839b8e7dcSStefan Hajnoczi goto skip_offload;
210939b8e7dcSStefan Hajnoczi }
211039b8e7dcSStefan Hajnoczi
21111bf11332SStefan Hajnoczi hlen = IP_HDR_GET_LEN(ip);
21125d61721aSStefan Hajnoczi if (hlen < sizeof(struct ip_header) || hlen > eth_payload_len) {
211303247d43SStefan Hajnoczi goto skip_offload;
211403247d43SStefan Hajnoczi }
211503247d43SStefan Hajnoczi
211649ab747fSPaolo Bonzini ip_protocol = ip->ip_p;
2117c6296ea8SStefan Hajnoczi
2118c6296ea8SStefan Hajnoczi ip_data_len = be16_to_cpu(ip->ip_len);
2119c6296ea8SStefan Hajnoczi if (ip_data_len < hlen || ip_data_len > eth_payload_len) {
2120c6296ea8SStefan Hajnoczi goto skip_offload;
2121c6296ea8SStefan Hajnoczi }
2122c6296ea8SStefan Hajnoczi ip_data_len -= hlen;
212349ab747fSPaolo Bonzini
2124c74831a0SStefan Hajnoczi if (!(txdw0 & CP_TX_LGSEN) && (txdw0 & CP_TX_IPCS))
212549ab747fSPaolo Bonzini {
212649ab747fSPaolo Bonzini DPRINTF("+++ C+ mode need IP checksum\n");
212749ab747fSPaolo Bonzini
212849ab747fSPaolo Bonzini ip->ip_sum = 0;
212949ab747fSPaolo Bonzini ip->ip_sum = ip_checksum(ip, hlen);
213049ab747fSPaolo Bonzini DPRINTF("+++ C+ mode IP header len=%d checksum=%04x\n",
213149ab747fSPaolo Bonzini hlen, ip->ip_sum);
213249ab747fSPaolo Bonzini }
213349ab747fSPaolo Bonzini
213449ab747fSPaolo Bonzini if ((txdw0 & CP_TX_LGSEN) && ip_protocol == IP_PROTO_TCP)
213549ab747fSPaolo Bonzini {
21364240be45SStefan Hajnoczi /* Large enough for the TCP header? */
21374240be45SStefan Hajnoczi if (ip_data_len < sizeof(tcp_header)) {
21384240be45SStefan Hajnoczi goto skip_offload;
21394240be45SStefan Hajnoczi }
21404240be45SStefan Hajnoczi
21416d71357aSStefan Hajnoczi int large_send_mss = (txdw0 >> CP_TC_LGSEN_MSS_SHIFT) &
21426d71357aSStefan Hajnoczi CP_TC_LGSEN_MSS_MASK;
2143792676c1SStefan Hajnoczi if (large_send_mss == 0) {
2144792676c1SStefan Hajnoczi goto skip_offload;
2145792676c1SStefan Hajnoczi }
214649ab747fSPaolo Bonzini
21476d71357aSStefan Hajnoczi DPRINTF("+++ C+ mode offloaded task TSO IP data %d "
21486d71357aSStefan Hajnoczi "frame data %d specified MSS=%d\n",
214949ab747fSPaolo Bonzini ip_data_len, saved_size - ETH_HLEN, large_send_mss);
215049ab747fSPaolo Bonzini
215149ab747fSPaolo Bonzini int tcp_send_offset = 0;
215249ab747fSPaolo Bonzini
215349ab747fSPaolo Bonzini /* maximum IP header length is 60 bytes */
215449ab747fSPaolo Bonzini uint8_t saved_ip_header[60];
215549ab747fSPaolo Bonzini
215649ab747fSPaolo Bonzini /* save IP header template; data area is used in tcp checksum calculation */
215749ab747fSPaolo Bonzini memcpy(saved_ip_header, eth_payload_data, hlen);
215849ab747fSPaolo Bonzini
215949ab747fSPaolo Bonzini /* a placeholder for checksum calculation routine in tcp case */
216049ab747fSPaolo Bonzini uint8_t *data_to_checksum = eth_payload_data + hlen - 12;
216149ab747fSPaolo Bonzini // size_t data_to_checksum_len = eth_payload_len - hlen + 12;
216249ab747fSPaolo Bonzini
216349ab747fSPaolo Bonzini /* pointer to TCP header */
216449ab747fSPaolo Bonzini tcp_header *p_tcp_hdr = (tcp_header*)(eth_payload_data + hlen);
216549ab747fSPaolo Bonzini
216649ab747fSPaolo Bonzini int tcp_hlen = TCP_HEADER_DATA_OFFSET(p_tcp_hdr);
216749ab747fSPaolo Bonzini
21688357946bSStefan Hajnoczi /* Invalid TCP data offset? */
21698357946bSStefan Hajnoczi if (tcp_hlen < sizeof(tcp_header) || tcp_hlen > ip_data_len) {
21708357946bSStefan Hajnoczi goto skip_offload;
21718357946bSStefan Hajnoczi }
21728357946bSStefan Hajnoczi
217349ab747fSPaolo Bonzini int tcp_data_len = ip_data_len - tcp_hlen;
217449ab747fSPaolo Bonzini
217549ab747fSPaolo Bonzini DPRINTF("+++ C+ mode TSO IP data len %d TCP hlen %d TCP "
21766d71357aSStefan Hajnoczi "data len %d\n", ip_data_len, tcp_hlen, tcp_data_len);
217749ab747fSPaolo Bonzini
217849ab747fSPaolo Bonzini /* note the cycle below overwrites IP header data,
217949ab747fSPaolo Bonzini but restores it from saved_ip_header before sending packet */
218049ab747fSPaolo Bonzini
218149ab747fSPaolo Bonzini int is_last_frame = 0;
218249ab747fSPaolo Bonzini
21836d71357aSStefan Hajnoczi for (tcp_send_offset = 0; tcp_send_offset < tcp_data_len; tcp_send_offset += large_send_mss)
218449ab747fSPaolo Bonzini {
21856d71357aSStefan Hajnoczi uint16_t chunk_size = large_send_mss;
218649ab747fSPaolo Bonzini
218749ab747fSPaolo Bonzini /* check if this is the last frame */
21886d71357aSStefan Hajnoczi if (tcp_send_offset + large_send_mss >= tcp_data_len)
218949ab747fSPaolo Bonzini {
219049ab747fSPaolo Bonzini is_last_frame = 1;
219149ab747fSPaolo Bonzini chunk_size = tcp_data_len - tcp_send_offset;
219249ab747fSPaolo Bonzini }
219349ab747fSPaolo Bonzini
219449ab747fSPaolo Bonzini DPRINTF("+++ C+ mode TSO TCP seqno %08x\n",
219526c0114dSStefan Hajnoczi ldl_be_p(&p_tcp_hdr->th_seq));
219649ab747fSPaolo Bonzini
219749ab747fSPaolo Bonzini /* add 4 TCP pseudoheader fields */
219849ab747fSPaolo Bonzini /* copy IP source and destination fields */
219949ab747fSPaolo Bonzini memcpy(data_to_checksum, saved_ip_header + 12, 8);
220049ab747fSPaolo Bonzini
220149ab747fSPaolo Bonzini DPRINTF("+++ C+ mode TSO calculating TCP checksum for "
220249ab747fSPaolo Bonzini "packet with %d bytes data\n", tcp_hlen +
220349ab747fSPaolo Bonzini chunk_size);
220449ab747fSPaolo Bonzini
220549ab747fSPaolo Bonzini if (tcp_send_offset)
220649ab747fSPaolo Bonzini {
220749ab747fSPaolo Bonzini memcpy((uint8_t*)p_tcp_hdr + tcp_hlen, (uint8_t*)p_tcp_hdr + tcp_hlen + tcp_send_offset, chunk_size);
220849ab747fSPaolo Bonzini }
220949ab747fSPaolo Bonzini
221049ab747fSPaolo Bonzini /* keep PUSH and FIN flags only for the last frame */
221149ab747fSPaolo Bonzini if (!is_last_frame)
221249ab747fSPaolo Bonzini {
22131bf11332SStefan Hajnoczi TCP_HEADER_CLEAR_FLAGS(p_tcp_hdr, TH_PUSH | TH_FIN);
221449ab747fSPaolo Bonzini }
221549ab747fSPaolo Bonzini
221649ab747fSPaolo Bonzini /* recalculate TCP checksum */
221749ab747fSPaolo Bonzini ip_pseudo_header *p_tcpip_hdr = (ip_pseudo_header *)data_to_checksum;
221849ab747fSPaolo Bonzini p_tcpip_hdr->zeros = 0;
221949ab747fSPaolo Bonzini p_tcpip_hdr->ip_proto = IP_PROTO_TCP;
222049ab747fSPaolo Bonzini p_tcpip_hdr->ip_payload = cpu_to_be16(tcp_hlen + chunk_size);
222149ab747fSPaolo Bonzini
222249ab747fSPaolo Bonzini p_tcp_hdr->th_sum = 0;
222349ab747fSPaolo Bonzini
222449ab747fSPaolo Bonzini int tcp_checksum = ip_checksum(data_to_checksum, tcp_hlen + chunk_size + 12);
222549ab747fSPaolo Bonzini DPRINTF("+++ C+ mode TSO TCP checksum %04x\n",
222649ab747fSPaolo Bonzini tcp_checksum);
222749ab747fSPaolo Bonzini
222849ab747fSPaolo Bonzini p_tcp_hdr->th_sum = tcp_checksum;
222949ab747fSPaolo Bonzini
223049ab747fSPaolo Bonzini /* restore IP header */
223149ab747fSPaolo Bonzini memcpy(eth_payload_data, saved_ip_header, hlen);
223249ab747fSPaolo Bonzini
223349ab747fSPaolo Bonzini /* set IP data length and recalculate IP checksum */
223449ab747fSPaolo Bonzini ip->ip_len = cpu_to_be16(hlen + tcp_hlen + chunk_size);
223549ab747fSPaolo Bonzini
223649ab747fSPaolo Bonzini /* increment IP id for subsequent frames */
22376d71357aSStefan Hajnoczi ip->ip_id = cpu_to_be16(tcp_send_offset/large_send_mss + be16_to_cpu(ip->ip_id));
223849ab747fSPaolo Bonzini
223949ab747fSPaolo Bonzini ip->ip_sum = 0;
224049ab747fSPaolo Bonzini ip->ip_sum = ip_checksum(eth_payload_data, hlen);
224149ab747fSPaolo Bonzini DPRINTF("+++ C+ mode TSO IP header len=%d "
224249ab747fSPaolo Bonzini "checksum=%04x\n", hlen, ip->ip_sum);
224349ab747fSPaolo Bonzini
224449ab747fSPaolo Bonzini int tso_send_size = ETH_HLEN + hlen + tcp_hlen + chunk_size;
224549ab747fSPaolo Bonzini DPRINTF("+++ C+ mode TSO transferring packet size "
224649ab747fSPaolo Bonzini "%d\n", tso_send_size);
224749ab747fSPaolo Bonzini rtl8139_transfer_frame(s, saved_buffer, tso_send_size,
224849ab747fSPaolo Bonzini 0, (uint8_t *) dot1q_buffer);
224949ab747fSPaolo Bonzini
225049ab747fSPaolo Bonzini /* add transferred count to TCP sequence number */
225126c0114dSStefan Hajnoczi stl_be_p(&p_tcp_hdr->th_seq,
225226c0114dSStefan Hajnoczi chunk_size + ldl_be_p(&p_tcp_hdr->th_seq));
225349ab747fSPaolo Bonzini }
225449ab747fSPaolo Bonzini
225549ab747fSPaolo Bonzini /* Stop sending this frame */
225649ab747fSPaolo Bonzini saved_size = 0;
225749ab747fSPaolo Bonzini }
2258c74831a0SStefan Hajnoczi else if (!(txdw0 & CP_TX_LGSEN) && (txdw0 & (CP_TX_TCPCS|CP_TX_UDPCS)))
225949ab747fSPaolo Bonzini {
226049ab747fSPaolo Bonzini DPRINTF("+++ C+ mode need TCP or UDP checksum\n");
226149ab747fSPaolo Bonzini
226249ab747fSPaolo Bonzini /* maximum IP header length is 60 bytes */
226349ab747fSPaolo Bonzini uint8_t saved_ip_header[60];
226449ab747fSPaolo Bonzini memcpy(saved_ip_header, eth_payload_data, hlen);
226549ab747fSPaolo Bonzini
226649ab747fSPaolo Bonzini uint8_t *data_to_checksum = eth_payload_data + hlen - 12;
226749ab747fSPaolo Bonzini // size_t data_to_checksum_len = eth_payload_len - hlen + 12;
226849ab747fSPaolo Bonzini
226949ab747fSPaolo Bonzini /* add 4 TCP pseudoheader fields */
227049ab747fSPaolo Bonzini /* copy IP source and destination fields */
227149ab747fSPaolo Bonzini memcpy(data_to_checksum, saved_ip_header + 12, 8);
227249ab747fSPaolo Bonzini
227349ab747fSPaolo Bonzini if ((txdw0 & CP_TX_TCPCS) && ip_protocol == IP_PROTO_TCP)
227449ab747fSPaolo Bonzini {
227549ab747fSPaolo Bonzini DPRINTF("+++ C+ mode calculating TCP checksum for "
227649ab747fSPaolo Bonzini "packet with %d bytes data\n", ip_data_len);
227749ab747fSPaolo Bonzini
227849ab747fSPaolo Bonzini ip_pseudo_header *p_tcpip_hdr = (ip_pseudo_header *)data_to_checksum;
227949ab747fSPaolo Bonzini p_tcpip_hdr->zeros = 0;
228049ab747fSPaolo Bonzini p_tcpip_hdr->ip_proto = IP_PROTO_TCP;
228149ab747fSPaolo Bonzini p_tcpip_hdr->ip_payload = cpu_to_be16(ip_data_len);
228249ab747fSPaolo Bonzini
228349ab747fSPaolo Bonzini tcp_header* p_tcp_hdr = (tcp_header *) (data_to_checksum+12);
228449ab747fSPaolo Bonzini
228549ab747fSPaolo Bonzini p_tcp_hdr->th_sum = 0;
228649ab747fSPaolo Bonzini
228749ab747fSPaolo Bonzini int tcp_checksum = ip_checksum(data_to_checksum, ip_data_len + 12);
228849ab747fSPaolo Bonzini DPRINTF("+++ C+ mode TCP checksum %04x\n",
228949ab747fSPaolo Bonzini tcp_checksum);
229049ab747fSPaolo Bonzini
229149ab747fSPaolo Bonzini p_tcp_hdr->th_sum = tcp_checksum;
229249ab747fSPaolo Bonzini }
229349ab747fSPaolo Bonzini else if ((txdw0 & CP_TX_UDPCS) && ip_protocol == IP_PROTO_UDP)
229449ab747fSPaolo Bonzini {
229549ab747fSPaolo Bonzini DPRINTF("+++ C+ mode calculating UDP checksum for "
229649ab747fSPaolo Bonzini "packet with %d bytes data\n", ip_data_len);
229749ab747fSPaolo Bonzini
229849ab747fSPaolo Bonzini ip_pseudo_header *p_udpip_hdr = (ip_pseudo_header *)data_to_checksum;
229949ab747fSPaolo Bonzini p_udpip_hdr->zeros = 0;
230049ab747fSPaolo Bonzini p_udpip_hdr->ip_proto = IP_PROTO_UDP;
230149ab747fSPaolo Bonzini p_udpip_hdr->ip_payload = cpu_to_be16(ip_data_len);
230249ab747fSPaolo Bonzini
230349ab747fSPaolo Bonzini udp_header *p_udp_hdr = (udp_header *) (data_to_checksum+12);
230449ab747fSPaolo Bonzini
230549ab747fSPaolo Bonzini p_udp_hdr->uh_sum = 0;
230649ab747fSPaolo Bonzini
230749ab747fSPaolo Bonzini int udp_checksum = ip_checksum(data_to_checksum, ip_data_len + 12);
230849ab747fSPaolo Bonzini DPRINTF("+++ C+ mode UDP checksum %04x\n",
230949ab747fSPaolo Bonzini udp_checksum);
231049ab747fSPaolo Bonzini
231149ab747fSPaolo Bonzini p_udp_hdr->uh_sum = udp_checksum;
231249ab747fSPaolo Bonzini }
231349ab747fSPaolo Bonzini
231449ab747fSPaolo Bonzini /* restore IP header */
231549ab747fSPaolo Bonzini memcpy(eth_payload_data, saved_ip_header, hlen);
231649ab747fSPaolo Bonzini }
231749ab747fSPaolo Bonzini }
231849ab747fSPaolo Bonzini
231939b8e7dcSStefan Hajnoczi skip_offload:
232049ab747fSPaolo Bonzini /* update tally counter */
232149ab747fSPaolo Bonzini ++s->tally_counters.TxOk;
232249ab747fSPaolo Bonzini
232349ab747fSPaolo Bonzini DPRINTF("+++ C+ mode transmitting %d bytes packet\n", saved_size);
232449ab747fSPaolo Bonzini
232549ab747fSPaolo Bonzini rtl8139_transfer_frame(s, saved_buffer, saved_size, 1,
232649ab747fSPaolo Bonzini (uint8_t *) dot1q_buffer);
232749ab747fSPaolo Bonzini
232849ab747fSPaolo Bonzini /* restore card space if there was no recursion and reset offset */
232949ab747fSPaolo Bonzini if (!s->cplus_txbuffer)
233049ab747fSPaolo Bonzini {
233149ab747fSPaolo Bonzini s->cplus_txbuffer = saved_buffer;
233249ab747fSPaolo Bonzini s->cplus_txbuffer_len = saved_buffer_len;
233349ab747fSPaolo Bonzini s->cplus_txbuffer_offset = 0;
233449ab747fSPaolo Bonzini }
233549ab747fSPaolo Bonzini else
233649ab747fSPaolo Bonzini {
233749ab747fSPaolo Bonzini g_free(saved_buffer);
233849ab747fSPaolo Bonzini }
233949ab747fSPaolo Bonzini }
234049ab747fSPaolo Bonzini else
234149ab747fSPaolo Bonzini {
234249ab747fSPaolo Bonzini DPRINTF("+++ C+ mode transmission continue to next descriptor\n");
234349ab747fSPaolo Bonzini }
234449ab747fSPaolo Bonzini
234549ab747fSPaolo Bonzini return 1;
234649ab747fSPaolo Bonzini }
234749ab747fSPaolo Bonzini
rtl8139_cplus_transmit(RTL8139State * s)234849ab747fSPaolo Bonzini static void rtl8139_cplus_transmit(RTL8139State *s)
234949ab747fSPaolo Bonzini {
235049ab747fSPaolo Bonzini int txcount = 0;
235149ab747fSPaolo Bonzini
2352c7c35916SPrasad J Pandit while (txcount < 64 && rtl8139_cplus_transmit_one(s))
235349ab747fSPaolo Bonzini {
235449ab747fSPaolo Bonzini ++txcount;
235549ab747fSPaolo Bonzini }
235649ab747fSPaolo Bonzini
235749ab747fSPaolo Bonzini /* Mark transfer completed */
235849ab747fSPaolo Bonzini if (!txcount)
235949ab747fSPaolo Bonzini {
236049ab747fSPaolo Bonzini DPRINTF("C+ mode : transmitter queue stalled, current TxDesc = %d\n",
236149ab747fSPaolo Bonzini s->currCPlusTxDesc);
236249ab747fSPaolo Bonzini }
236349ab747fSPaolo Bonzini else
236449ab747fSPaolo Bonzini {
236549ab747fSPaolo Bonzini /* update interrupt status */
236649ab747fSPaolo Bonzini s->IntrStatus |= TxOK;
236749ab747fSPaolo Bonzini rtl8139_update_irq(s);
236849ab747fSPaolo Bonzini }
236949ab747fSPaolo Bonzini }
237049ab747fSPaolo Bonzini
rtl8139_transmit(RTL8139State * s)237149ab747fSPaolo Bonzini static void rtl8139_transmit(RTL8139State *s)
237249ab747fSPaolo Bonzini {
237349ab747fSPaolo Bonzini int descriptor = s->currTxDesc, txcount = 0;
237449ab747fSPaolo Bonzini
237549ab747fSPaolo Bonzini /*while*/
237649ab747fSPaolo Bonzini if (rtl8139_transmit_one(s, descriptor))
237749ab747fSPaolo Bonzini {
237849ab747fSPaolo Bonzini ++s->currTxDesc;
237949ab747fSPaolo Bonzini s->currTxDesc %= 4;
238049ab747fSPaolo Bonzini ++txcount;
238149ab747fSPaolo Bonzini }
238249ab747fSPaolo Bonzini
238349ab747fSPaolo Bonzini /* Mark transfer completed */
238449ab747fSPaolo Bonzini if (!txcount)
238549ab747fSPaolo Bonzini {
238649ab747fSPaolo Bonzini DPRINTF("transmitter queue stalled, current TxDesc = %d\n",
238749ab747fSPaolo Bonzini s->currTxDesc);
238849ab747fSPaolo Bonzini }
238949ab747fSPaolo Bonzini }
239049ab747fSPaolo Bonzini
rtl8139_TxStatus_write(RTL8139State * s,uint32_t txRegOffset,uint32_t val)239149ab747fSPaolo Bonzini static void rtl8139_TxStatus_write(RTL8139State *s, uint32_t txRegOffset, uint32_t val)
239249ab747fSPaolo Bonzini {
239349ab747fSPaolo Bonzini
239449ab747fSPaolo Bonzini int descriptor = txRegOffset/4;
239549ab747fSPaolo Bonzini
239649ab747fSPaolo Bonzini /* handle C+ transmit mode register configuration */
239749ab747fSPaolo Bonzini
239849ab747fSPaolo Bonzini if (s->cplus_enabled)
239949ab747fSPaolo Bonzini {
240049ab747fSPaolo Bonzini DPRINTF("RTL8139C+ DTCCR write offset=0x%x val=0x%08x "
240149ab747fSPaolo Bonzini "descriptor=%d\n", txRegOffset, val, descriptor);
240249ab747fSPaolo Bonzini
240349ab747fSPaolo Bonzini /* handle Dump Tally Counters command */
240449ab747fSPaolo Bonzini s->TxStatus[descriptor] = val;
240549ab747fSPaolo Bonzini
240649ab747fSPaolo Bonzini if (descriptor == 0 && (val & 0x8))
240749ab747fSPaolo Bonzini {
240849ab747fSPaolo Bonzini hwaddr tc_addr = rtl8139_addr64(s->TxStatus[0] & ~0x3f, s->TxStatus[1]);
240949ab747fSPaolo Bonzini
241049ab747fSPaolo Bonzini /* dump tally counters to specified memory location */
241149ab747fSPaolo Bonzini RTL8139TallyCounters_dma_write(s, tc_addr);
241249ab747fSPaolo Bonzini
241349ab747fSPaolo Bonzini /* mark dump completed */
241449ab747fSPaolo Bonzini s->TxStatus[0] &= ~0x8;
241549ab747fSPaolo Bonzini }
241649ab747fSPaolo Bonzini
241749ab747fSPaolo Bonzini return;
241849ab747fSPaolo Bonzini }
241949ab747fSPaolo Bonzini
242049ab747fSPaolo Bonzini DPRINTF("TxStatus write offset=0x%x val=0x%08x descriptor=%d\n",
242149ab747fSPaolo Bonzini txRegOffset, val, descriptor);
242249ab747fSPaolo Bonzini
242349ab747fSPaolo Bonzini /* mask only reserved bits */
242449ab747fSPaolo Bonzini val &= ~0xff00c000; /* these bits are reset on write */
242549ab747fSPaolo Bonzini val = SET_MASKED(val, 0x00c00000, s->TxStatus[descriptor]);
242649ab747fSPaolo Bonzini
242749ab747fSPaolo Bonzini s->TxStatus[descriptor] = val;
242849ab747fSPaolo Bonzini
242949ab747fSPaolo Bonzini /* attempt to start transmission */
243049ab747fSPaolo Bonzini rtl8139_transmit(s);
243149ab747fSPaolo Bonzini }
243249ab747fSPaolo Bonzini
rtl8139_TxStatus_TxAddr_read(RTL8139State * s,uint32_t regs[],uint32_t base,uint8_t addr,int size)243349ab747fSPaolo Bonzini static uint32_t rtl8139_TxStatus_TxAddr_read(RTL8139State *s, uint32_t regs[],
243449ab747fSPaolo Bonzini uint32_t base, uint8_t addr,
243549ab747fSPaolo Bonzini int size)
243649ab747fSPaolo Bonzini {
243749ab747fSPaolo Bonzini uint32_t reg = (addr - base) / 4;
243849ab747fSPaolo Bonzini uint32_t offset = addr & 0x3;
243949ab747fSPaolo Bonzini uint32_t ret = 0;
244049ab747fSPaolo Bonzini
244149ab747fSPaolo Bonzini if (addr & (size - 1)) {
244249ab747fSPaolo Bonzini DPRINTF("not implemented read for TxStatus/TxAddr "
244349ab747fSPaolo Bonzini "addr=0x%x size=0x%x\n", addr, size);
244449ab747fSPaolo Bonzini return ret;
244549ab747fSPaolo Bonzini }
244649ab747fSPaolo Bonzini
244749ab747fSPaolo Bonzini switch (size) {
244849ab747fSPaolo Bonzini case 1: /* fall through */
244949ab747fSPaolo Bonzini case 2: /* fall through */
245049ab747fSPaolo Bonzini case 4:
245149ab747fSPaolo Bonzini ret = (regs[reg] >> offset * 8) & (((uint64_t)1 << (size * 8)) - 1);
245249ab747fSPaolo Bonzini DPRINTF("TxStatus/TxAddr[%d] read addr=0x%x size=0x%x val=0x%08x\n",
245349ab747fSPaolo Bonzini reg, addr, size, ret);
245449ab747fSPaolo Bonzini break;
245549ab747fSPaolo Bonzini default:
245649ab747fSPaolo Bonzini DPRINTF("unsupported size 0x%x of TxStatus/TxAddr reading\n", size);
245749ab747fSPaolo Bonzini break;
245849ab747fSPaolo Bonzini }
245949ab747fSPaolo Bonzini
246049ab747fSPaolo Bonzini return ret;
246149ab747fSPaolo Bonzini }
246249ab747fSPaolo Bonzini
rtl8139_TSAD_read(RTL8139State * s)246349ab747fSPaolo Bonzini static uint16_t rtl8139_TSAD_read(RTL8139State *s)
246449ab747fSPaolo Bonzini {
246549ab747fSPaolo Bonzini uint16_t ret = 0;
246649ab747fSPaolo Bonzini
246749ab747fSPaolo Bonzini /* Simulate TSAD, it is read only anyway */
246849ab747fSPaolo Bonzini
246949ab747fSPaolo Bonzini ret = ((s->TxStatus[3] & TxStatOK )?TSAD_TOK3:0)
247049ab747fSPaolo Bonzini |((s->TxStatus[2] & TxStatOK )?TSAD_TOK2:0)
247149ab747fSPaolo Bonzini |((s->TxStatus[1] & TxStatOK )?TSAD_TOK1:0)
247249ab747fSPaolo Bonzini |((s->TxStatus[0] & TxStatOK )?TSAD_TOK0:0)
247349ab747fSPaolo Bonzini
247449ab747fSPaolo Bonzini |((s->TxStatus[3] & TxUnderrun)?TSAD_TUN3:0)
247549ab747fSPaolo Bonzini |((s->TxStatus[2] & TxUnderrun)?TSAD_TUN2:0)
247649ab747fSPaolo Bonzini |((s->TxStatus[1] & TxUnderrun)?TSAD_TUN1:0)
247749ab747fSPaolo Bonzini |((s->TxStatus[0] & TxUnderrun)?TSAD_TUN0:0)
247849ab747fSPaolo Bonzini
247949ab747fSPaolo Bonzini |((s->TxStatus[3] & TxAborted )?TSAD_TABT3:0)
248049ab747fSPaolo Bonzini |((s->TxStatus[2] & TxAborted )?TSAD_TABT2:0)
248149ab747fSPaolo Bonzini |((s->TxStatus[1] & TxAborted )?TSAD_TABT1:0)
248249ab747fSPaolo Bonzini |((s->TxStatus[0] & TxAborted )?TSAD_TABT0:0)
248349ab747fSPaolo Bonzini
248449ab747fSPaolo Bonzini |((s->TxStatus[3] & TxHostOwns )?TSAD_OWN3:0)
248549ab747fSPaolo Bonzini |((s->TxStatus[2] & TxHostOwns )?TSAD_OWN2:0)
248649ab747fSPaolo Bonzini |((s->TxStatus[1] & TxHostOwns )?TSAD_OWN1:0)
248749ab747fSPaolo Bonzini |((s->TxStatus[0] & TxHostOwns )?TSAD_OWN0:0) ;
248849ab747fSPaolo Bonzini
248949ab747fSPaolo Bonzini
249049ab747fSPaolo Bonzini DPRINTF("TSAD read val=0x%04x\n", ret);
249149ab747fSPaolo Bonzini
249249ab747fSPaolo Bonzini return ret;
249349ab747fSPaolo Bonzini }
249449ab747fSPaolo Bonzini
rtl8139_CSCR_read(RTL8139State * s)249549ab747fSPaolo Bonzini static uint16_t rtl8139_CSCR_read(RTL8139State *s)
249649ab747fSPaolo Bonzini {
249749ab747fSPaolo Bonzini uint16_t ret = s->CSCR;
249849ab747fSPaolo Bonzini
249949ab747fSPaolo Bonzini DPRINTF("CSCR read val=0x%04x\n", ret);
250049ab747fSPaolo Bonzini
250149ab747fSPaolo Bonzini return ret;
250249ab747fSPaolo Bonzini }
250349ab747fSPaolo Bonzini
rtl8139_TxAddr_write(RTL8139State * s,uint32_t txAddrOffset,uint32_t val)250449ab747fSPaolo Bonzini static void rtl8139_TxAddr_write(RTL8139State *s, uint32_t txAddrOffset, uint32_t val)
250549ab747fSPaolo Bonzini {
250649ab747fSPaolo Bonzini DPRINTF("TxAddr write offset=0x%x val=0x%08x\n", txAddrOffset, val);
250749ab747fSPaolo Bonzini
250849ab747fSPaolo Bonzini s->TxAddr[txAddrOffset/4] = val;
250949ab747fSPaolo Bonzini }
251049ab747fSPaolo Bonzini
rtl8139_TxAddr_read(RTL8139State * s,uint32_t txAddrOffset)251149ab747fSPaolo Bonzini static uint32_t rtl8139_TxAddr_read(RTL8139State *s, uint32_t txAddrOffset)
251249ab747fSPaolo Bonzini {
251349ab747fSPaolo Bonzini uint32_t ret = s->TxAddr[txAddrOffset/4];
251449ab747fSPaolo Bonzini
251549ab747fSPaolo Bonzini DPRINTF("TxAddr read offset=0x%x val=0x%08x\n", txAddrOffset, ret);
251649ab747fSPaolo Bonzini
251749ab747fSPaolo Bonzini return ret;
251849ab747fSPaolo Bonzini }
251949ab747fSPaolo Bonzini
rtl8139_RxBufPtr_write(RTL8139State * s,uint32_t val)252049ab747fSPaolo Bonzini static void rtl8139_RxBufPtr_write(RTL8139State *s, uint32_t val)
252149ab747fSPaolo Bonzini {
252249ab747fSPaolo Bonzini DPRINTF("RxBufPtr write val=0x%04x\n", val);
252349ab747fSPaolo Bonzini
252449ab747fSPaolo Bonzini /* this value is off by 16 */
252549ab747fSPaolo Bonzini s->RxBufPtr = MOD2(val + 0x10, s->RxBufferSize);
252649ab747fSPaolo Bonzini
252700b7ade8SStefan Hajnoczi /* more buffer space may be available so try to receive */
252800b7ade8SStefan Hajnoczi qemu_flush_queued_packets(qemu_get_queue(s->nic));
252900b7ade8SStefan Hajnoczi
253049ab747fSPaolo Bonzini DPRINTF(" CAPR write: rx buffer length %d head 0x%04x read 0x%04x\n",
253149ab747fSPaolo Bonzini s->RxBufferSize, s->RxBufAddr, s->RxBufPtr);
253249ab747fSPaolo Bonzini }
253349ab747fSPaolo Bonzini
rtl8139_RxBufPtr_read(RTL8139State * s)253449ab747fSPaolo Bonzini static uint32_t rtl8139_RxBufPtr_read(RTL8139State *s)
253549ab747fSPaolo Bonzini {
253649ab747fSPaolo Bonzini /* this value is off by 16 */
253749ab747fSPaolo Bonzini uint32_t ret = s->RxBufPtr - 0x10;
253849ab747fSPaolo Bonzini
253949ab747fSPaolo Bonzini DPRINTF("RxBufPtr read val=0x%04x\n", ret);
254049ab747fSPaolo Bonzini
254149ab747fSPaolo Bonzini return ret;
254249ab747fSPaolo Bonzini }
254349ab747fSPaolo Bonzini
rtl8139_RxBufAddr_read(RTL8139State * s)254449ab747fSPaolo Bonzini static uint32_t rtl8139_RxBufAddr_read(RTL8139State *s)
254549ab747fSPaolo Bonzini {
254649ab747fSPaolo Bonzini /* this value is NOT off by 16 */
254749ab747fSPaolo Bonzini uint32_t ret = s->RxBufAddr;
254849ab747fSPaolo Bonzini
254949ab747fSPaolo Bonzini DPRINTF("RxBufAddr read val=0x%04x\n", ret);
255049ab747fSPaolo Bonzini
255149ab747fSPaolo Bonzini return ret;
255249ab747fSPaolo Bonzini }
255349ab747fSPaolo Bonzini
rtl8139_RxBuf_write(RTL8139State * s,uint32_t val)255449ab747fSPaolo Bonzini static void rtl8139_RxBuf_write(RTL8139State *s, uint32_t val)
255549ab747fSPaolo Bonzini {
255649ab747fSPaolo Bonzini DPRINTF("RxBuf write val=0x%08x\n", val);
255749ab747fSPaolo Bonzini
255849ab747fSPaolo Bonzini s->RxBuf = val;
255949ab747fSPaolo Bonzini
256049ab747fSPaolo Bonzini /* may need to reset rxring here */
256149ab747fSPaolo Bonzini }
256249ab747fSPaolo Bonzini
rtl8139_RxBuf_read(RTL8139State * s)256349ab747fSPaolo Bonzini static uint32_t rtl8139_RxBuf_read(RTL8139State *s)
256449ab747fSPaolo Bonzini {
256549ab747fSPaolo Bonzini uint32_t ret = s->RxBuf;
256649ab747fSPaolo Bonzini
256749ab747fSPaolo Bonzini DPRINTF("RxBuf read val=0x%08x\n", ret);
256849ab747fSPaolo Bonzini
256949ab747fSPaolo Bonzini return ret;
257049ab747fSPaolo Bonzini }
257149ab747fSPaolo Bonzini
rtl8139_IntrMask_write(RTL8139State * s,uint32_t val)257249ab747fSPaolo Bonzini static void rtl8139_IntrMask_write(RTL8139State *s, uint32_t val)
257349ab747fSPaolo Bonzini {
257449ab747fSPaolo Bonzini DPRINTF("IntrMask write(w) val=0x%04x\n", val);
257549ab747fSPaolo Bonzini
257649ab747fSPaolo Bonzini /* mask unwritable bits */
257749ab747fSPaolo Bonzini val = SET_MASKED(val, 0x1e00, s->IntrMask);
257849ab747fSPaolo Bonzini
257949ab747fSPaolo Bonzini s->IntrMask = val;
258049ab747fSPaolo Bonzini
258149ab747fSPaolo Bonzini rtl8139_update_irq(s);
258249ab747fSPaolo Bonzini
258349ab747fSPaolo Bonzini }
258449ab747fSPaolo Bonzini
rtl8139_IntrMask_read(RTL8139State * s)258549ab747fSPaolo Bonzini static uint32_t rtl8139_IntrMask_read(RTL8139State *s)
258649ab747fSPaolo Bonzini {
258749ab747fSPaolo Bonzini uint32_t ret = s->IntrMask;
258849ab747fSPaolo Bonzini
258949ab747fSPaolo Bonzini DPRINTF("IntrMask read(w) val=0x%04x\n", ret);
259049ab747fSPaolo Bonzini
259149ab747fSPaolo Bonzini return ret;
259249ab747fSPaolo Bonzini }
259349ab747fSPaolo Bonzini
rtl8139_IntrStatus_write(RTL8139State * s,uint32_t val)259449ab747fSPaolo Bonzini static void rtl8139_IntrStatus_write(RTL8139State *s, uint32_t val)
259549ab747fSPaolo Bonzini {
259649ab747fSPaolo Bonzini DPRINTF("IntrStatus write(w) val=0x%04x\n", val);
259749ab747fSPaolo Bonzini
259849ab747fSPaolo Bonzini #if 0
259949ab747fSPaolo Bonzini
260049ab747fSPaolo Bonzini /* writing to ISR has no effect */
260149ab747fSPaolo Bonzini
260249ab747fSPaolo Bonzini return;
260349ab747fSPaolo Bonzini
260449ab747fSPaolo Bonzini #else
260549ab747fSPaolo Bonzini uint16_t newStatus = s->IntrStatus & ~val;
260649ab747fSPaolo Bonzini
260749ab747fSPaolo Bonzini /* mask unwritable bits */
260849ab747fSPaolo Bonzini newStatus = SET_MASKED(newStatus, 0x1e00, s->IntrStatus);
260949ab747fSPaolo Bonzini
261049ab747fSPaolo Bonzini /* writing 1 to interrupt status register bit clears it */
261149ab747fSPaolo Bonzini s->IntrStatus = 0;
261249ab747fSPaolo Bonzini rtl8139_update_irq(s);
261349ab747fSPaolo Bonzini
261449ab747fSPaolo Bonzini s->IntrStatus = newStatus;
2615237c255cSPaolo Bonzini rtl8139_set_next_tctr_time(s);
261649ab747fSPaolo Bonzini rtl8139_update_irq(s);
261749ab747fSPaolo Bonzini
261849ab747fSPaolo Bonzini #endif
261949ab747fSPaolo Bonzini }
262049ab747fSPaolo Bonzini
rtl8139_IntrStatus_read(RTL8139State * s)262149ab747fSPaolo Bonzini static uint32_t rtl8139_IntrStatus_read(RTL8139State *s)
262249ab747fSPaolo Bonzini {
262349ab747fSPaolo Bonzini uint32_t ret = s->IntrStatus;
262449ab747fSPaolo Bonzini
262549ab747fSPaolo Bonzini DPRINTF("IntrStatus read(w) val=0x%04x\n", ret);
262649ab747fSPaolo Bonzini
262749ab747fSPaolo Bonzini #if 0
262849ab747fSPaolo Bonzini
262949ab747fSPaolo Bonzini /* reading ISR clears all interrupts */
263049ab747fSPaolo Bonzini s->IntrStatus = 0;
263149ab747fSPaolo Bonzini
263249ab747fSPaolo Bonzini rtl8139_update_irq(s);
263349ab747fSPaolo Bonzini
263449ab747fSPaolo Bonzini #endif
263549ab747fSPaolo Bonzini
263649ab747fSPaolo Bonzini return ret;
263749ab747fSPaolo Bonzini }
263849ab747fSPaolo Bonzini
rtl8139_MultiIntr_write(RTL8139State * s,uint32_t val)263949ab747fSPaolo Bonzini static void rtl8139_MultiIntr_write(RTL8139State *s, uint32_t val)
264049ab747fSPaolo Bonzini {
264149ab747fSPaolo Bonzini DPRINTF("MultiIntr write(w) val=0x%04x\n", val);
264249ab747fSPaolo Bonzini
264349ab747fSPaolo Bonzini /* mask unwritable bits */
264449ab747fSPaolo Bonzini val = SET_MASKED(val, 0xf000, s->MultiIntr);
264549ab747fSPaolo Bonzini
264649ab747fSPaolo Bonzini s->MultiIntr = val;
264749ab747fSPaolo Bonzini }
264849ab747fSPaolo Bonzini
rtl8139_MultiIntr_read(RTL8139State * s)264949ab747fSPaolo Bonzini static uint32_t rtl8139_MultiIntr_read(RTL8139State *s)
265049ab747fSPaolo Bonzini {
265149ab747fSPaolo Bonzini uint32_t ret = s->MultiIntr;
265249ab747fSPaolo Bonzini
265349ab747fSPaolo Bonzini DPRINTF("MultiIntr read(w) val=0x%04x\n", ret);
265449ab747fSPaolo Bonzini
265549ab747fSPaolo Bonzini return ret;
265649ab747fSPaolo Bonzini }
265749ab747fSPaolo Bonzini
rtl8139_io_writeb(void * opaque,uint8_t addr,uint32_t val)265849ab747fSPaolo Bonzini static void rtl8139_io_writeb(void *opaque, uint8_t addr, uint32_t val)
265949ab747fSPaolo Bonzini {
266049ab747fSPaolo Bonzini RTL8139State *s = opaque;
266149ab747fSPaolo Bonzini
266249ab747fSPaolo Bonzini switch (addr)
266349ab747fSPaolo Bonzini {
266490d131fbSMichael S. Tsirkin case MAC0 ... MAC0+4:
266590d131fbSMichael S. Tsirkin s->phys[addr - MAC0] = val;
266690d131fbSMichael S. Tsirkin break;
266790d131fbSMichael S. Tsirkin case MAC0+5:
266823c37c37SAmos Kong s->phys[addr - MAC0] = val;
266923c37c37SAmos Kong qemu_format_nic_info_str(qemu_get_queue(s->nic), s->phys);
267023c37c37SAmos Kong break;
267149ab747fSPaolo Bonzini case MAC0+6 ... MAC0+7:
267249ab747fSPaolo Bonzini /* reserved */
267349ab747fSPaolo Bonzini break;
267449ab747fSPaolo Bonzini case MAR0 ... MAR0+7:
267549ab747fSPaolo Bonzini s->mult[addr - MAR0] = val;
267649ab747fSPaolo Bonzini break;
267749ab747fSPaolo Bonzini case ChipCmd:
267849ab747fSPaolo Bonzini rtl8139_ChipCmd_write(s, val);
267949ab747fSPaolo Bonzini break;
268049ab747fSPaolo Bonzini case Cfg9346:
268149ab747fSPaolo Bonzini rtl8139_Cfg9346_write(s, val);
268249ab747fSPaolo Bonzini break;
268349ab747fSPaolo Bonzini case TxConfig: /* windows driver sometimes writes using byte-lenth call */
268449ab747fSPaolo Bonzini rtl8139_TxConfig_writeb(s, val);
268549ab747fSPaolo Bonzini break;
268649ab747fSPaolo Bonzini case Config0:
268749ab747fSPaolo Bonzini rtl8139_Config0_write(s, val);
268849ab747fSPaolo Bonzini break;
268949ab747fSPaolo Bonzini case Config1:
269049ab747fSPaolo Bonzini rtl8139_Config1_write(s, val);
269149ab747fSPaolo Bonzini break;
269249ab747fSPaolo Bonzini case Config3:
269349ab747fSPaolo Bonzini rtl8139_Config3_write(s, val);
269449ab747fSPaolo Bonzini break;
269549ab747fSPaolo Bonzini case Config4:
269649ab747fSPaolo Bonzini rtl8139_Config4_write(s, val);
269749ab747fSPaolo Bonzini break;
269849ab747fSPaolo Bonzini case Config5:
269949ab747fSPaolo Bonzini rtl8139_Config5_write(s, val);
270049ab747fSPaolo Bonzini break;
270149ab747fSPaolo Bonzini case MediaStatus:
270249ab747fSPaolo Bonzini /* ignore */
270349ab747fSPaolo Bonzini DPRINTF("not implemented write(b) to MediaStatus val=0x%02x\n",
270449ab747fSPaolo Bonzini val);
270549ab747fSPaolo Bonzini break;
270649ab747fSPaolo Bonzini
270749ab747fSPaolo Bonzini case HltClk:
270849ab747fSPaolo Bonzini DPRINTF("HltClk write val=0x%08x\n", val);
270949ab747fSPaolo Bonzini if (val == 'R')
271049ab747fSPaolo Bonzini {
271149ab747fSPaolo Bonzini s->clock_enabled = 1;
271249ab747fSPaolo Bonzini }
271349ab747fSPaolo Bonzini else if (val == 'H')
271449ab747fSPaolo Bonzini {
271549ab747fSPaolo Bonzini s->clock_enabled = 0;
271649ab747fSPaolo Bonzini }
271749ab747fSPaolo Bonzini break;
271849ab747fSPaolo Bonzini
271949ab747fSPaolo Bonzini case TxThresh:
272049ab747fSPaolo Bonzini DPRINTF("C+ TxThresh write(b) val=0x%02x\n", val);
272149ab747fSPaolo Bonzini s->TxThresh = val;
272249ab747fSPaolo Bonzini break;
272349ab747fSPaolo Bonzini
272449ab747fSPaolo Bonzini case TxPoll:
272549ab747fSPaolo Bonzini DPRINTF("C+ TxPoll write(b) val=0x%02x\n", val);
272649ab747fSPaolo Bonzini if (val & (1 << 7))
272749ab747fSPaolo Bonzini {
272849ab747fSPaolo Bonzini DPRINTF("C+ TxPoll high priority transmission (not "
272949ab747fSPaolo Bonzini "implemented)\n");
273049ab747fSPaolo Bonzini //rtl8139_cplus_transmit(s);
273149ab747fSPaolo Bonzini }
273249ab747fSPaolo Bonzini if (val & (1 << 6))
273349ab747fSPaolo Bonzini {
273449ab747fSPaolo Bonzini DPRINTF("C+ TxPoll normal priority transmission\n");
273549ab747fSPaolo Bonzini rtl8139_cplus_transmit(s);
273649ab747fSPaolo Bonzini }
273749ab747fSPaolo Bonzini
273849ab747fSPaolo Bonzini break;
27399e3b9f27SHans case RxConfig:
27409e3b9f27SHans DPRINTF("RxConfig write(b) val=0x%02x\n", val);
27419e3b9f27SHans rtl8139_RxConfig_write(s,
27429e3b9f27SHans (rtl8139_RxConfig_read(s) & 0xFFFFFF00) | val);
27439e3b9f27SHans break;
274449ab747fSPaolo Bonzini default:
274549ab747fSPaolo Bonzini DPRINTF("not implemented write(b) addr=0x%x val=0x%02x\n", addr,
274649ab747fSPaolo Bonzini val);
274749ab747fSPaolo Bonzini break;
274849ab747fSPaolo Bonzini }
274949ab747fSPaolo Bonzini }
275049ab747fSPaolo Bonzini
rtl8139_io_writew(void * opaque,uint8_t addr,uint32_t val)275149ab747fSPaolo Bonzini static void rtl8139_io_writew(void *opaque, uint8_t addr, uint32_t val)
275249ab747fSPaolo Bonzini {
275349ab747fSPaolo Bonzini RTL8139State *s = opaque;
275449ab747fSPaolo Bonzini
275549ab747fSPaolo Bonzini switch (addr)
275649ab747fSPaolo Bonzini {
275749ab747fSPaolo Bonzini case IntrMask:
275849ab747fSPaolo Bonzini rtl8139_IntrMask_write(s, val);
275949ab747fSPaolo Bonzini break;
276049ab747fSPaolo Bonzini
276149ab747fSPaolo Bonzini case IntrStatus:
276249ab747fSPaolo Bonzini rtl8139_IntrStatus_write(s, val);
276349ab747fSPaolo Bonzini break;
276449ab747fSPaolo Bonzini
276549ab747fSPaolo Bonzini case MultiIntr:
276649ab747fSPaolo Bonzini rtl8139_MultiIntr_write(s, val);
276749ab747fSPaolo Bonzini break;
276849ab747fSPaolo Bonzini
276949ab747fSPaolo Bonzini case RxBufPtr:
277049ab747fSPaolo Bonzini rtl8139_RxBufPtr_write(s, val);
277149ab747fSPaolo Bonzini break;
277249ab747fSPaolo Bonzini
277349ab747fSPaolo Bonzini case BasicModeCtrl:
277449ab747fSPaolo Bonzini rtl8139_BasicModeCtrl_write(s, val);
277549ab747fSPaolo Bonzini break;
277649ab747fSPaolo Bonzini case BasicModeStatus:
277749ab747fSPaolo Bonzini rtl8139_BasicModeStatus_write(s, val);
277849ab747fSPaolo Bonzini break;
277949ab747fSPaolo Bonzini case NWayAdvert:
278049ab747fSPaolo Bonzini DPRINTF("NWayAdvert write(w) val=0x%04x\n", val);
278149ab747fSPaolo Bonzini s->NWayAdvert = val;
278249ab747fSPaolo Bonzini break;
278349ab747fSPaolo Bonzini case NWayLPAR:
278449ab747fSPaolo Bonzini DPRINTF("forbidden NWayLPAR write(w) val=0x%04x\n", val);
278549ab747fSPaolo Bonzini break;
278649ab747fSPaolo Bonzini case NWayExpansion:
278749ab747fSPaolo Bonzini DPRINTF("NWayExpansion write(w) val=0x%04x\n", val);
278849ab747fSPaolo Bonzini s->NWayExpansion = val;
278949ab747fSPaolo Bonzini break;
279049ab747fSPaolo Bonzini
279149ab747fSPaolo Bonzini case CpCmd:
279249ab747fSPaolo Bonzini rtl8139_CpCmd_write(s, val);
279349ab747fSPaolo Bonzini break;
279449ab747fSPaolo Bonzini
279549ab747fSPaolo Bonzini case IntrMitigate:
279649ab747fSPaolo Bonzini rtl8139_IntrMitigate_write(s, val);
279749ab747fSPaolo Bonzini break;
279849ab747fSPaolo Bonzini
279949ab747fSPaolo Bonzini default:
280049ab747fSPaolo Bonzini DPRINTF("ioport write(w) addr=0x%x val=0x%04x via write(b)\n",
280149ab747fSPaolo Bonzini addr, val);
280249ab747fSPaolo Bonzini
280349ab747fSPaolo Bonzini rtl8139_io_writeb(opaque, addr, val & 0xff);
280449ab747fSPaolo Bonzini rtl8139_io_writeb(opaque, addr + 1, (val >> 8) & 0xff);
280549ab747fSPaolo Bonzini break;
280649ab747fSPaolo Bonzini }
280749ab747fSPaolo Bonzini }
280849ab747fSPaolo Bonzini
rtl8139_set_next_tctr_time(RTL8139State * s)2809237c255cSPaolo Bonzini static void rtl8139_set_next_tctr_time(RTL8139State *s)
281049ab747fSPaolo Bonzini {
281137b9ab92SLaurent Vivier const uint64_t ns_per_period = (uint64_t)PCI_PERIOD << 32;
281249ab747fSPaolo Bonzini
281349ab747fSPaolo Bonzini DPRINTF("entered rtl8139_set_next_tctr_time\n");
281449ab747fSPaolo Bonzini
2815237c255cSPaolo Bonzini /* This function is called at least once per period, so it is a good
2816237c255cSPaolo Bonzini * place to update the timer base.
2817237c255cSPaolo Bonzini *
2818237c255cSPaolo Bonzini * After one iteration of this loop the value in the Timer register does
2819237c255cSPaolo Bonzini * not change, but the device model is counting up by 2^32 ticks (approx.
2820237c255cSPaolo Bonzini * 130 seconds).
282149ab747fSPaolo Bonzini */
2822237c255cSPaolo Bonzini while (s->TCTR_base + ns_per_period <= qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)) {
2823237c255cSPaolo Bonzini s->TCTR_base += ns_per_period;
2824237c255cSPaolo Bonzini }
2825237c255cSPaolo Bonzini
282649ab747fSPaolo Bonzini if (!s->TimerInt) {
2827237c255cSPaolo Bonzini timer_del(s->timer);
2828237c255cSPaolo Bonzini } else {
282937b9ab92SLaurent Vivier uint64_t delta = (uint64_t)s->TimerInt * PCI_PERIOD;
2830237c255cSPaolo Bonzini if (s->TCTR_base + delta <= qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)) {
2831237c255cSPaolo Bonzini delta += ns_per_period;
283249ab747fSPaolo Bonzini }
2833237c255cSPaolo Bonzini timer_mod(s->timer, s->TCTR_base + delta);
283449ab747fSPaolo Bonzini }
283549ab747fSPaolo Bonzini }
283649ab747fSPaolo Bonzini
rtl8139_io_writel(void * opaque,uint8_t addr,uint32_t val)283749ab747fSPaolo Bonzini static void rtl8139_io_writel(void *opaque, uint8_t addr, uint32_t val)
283849ab747fSPaolo Bonzini {
283949ab747fSPaolo Bonzini RTL8139State *s = opaque;
284049ab747fSPaolo Bonzini
284149ab747fSPaolo Bonzini switch (addr)
284249ab747fSPaolo Bonzini {
284349ab747fSPaolo Bonzini case RxMissed:
284449ab747fSPaolo Bonzini DPRINTF("RxMissed clearing on write\n");
284549ab747fSPaolo Bonzini s->RxMissed = 0;
284649ab747fSPaolo Bonzini break;
284749ab747fSPaolo Bonzini
284849ab747fSPaolo Bonzini case TxConfig:
284949ab747fSPaolo Bonzini rtl8139_TxConfig_write(s, val);
285049ab747fSPaolo Bonzini break;
285149ab747fSPaolo Bonzini
285249ab747fSPaolo Bonzini case RxConfig:
285349ab747fSPaolo Bonzini rtl8139_RxConfig_write(s, val);
285449ab747fSPaolo Bonzini break;
285549ab747fSPaolo Bonzini
285649ab747fSPaolo Bonzini case TxStatus0 ... TxStatus0+4*4-1:
285749ab747fSPaolo Bonzini rtl8139_TxStatus_write(s, addr-TxStatus0, val);
285849ab747fSPaolo Bonzini break;
285949ab747fSPaolo Bonzini
286049ab747fSPaolo Bonzini case TxAddr0 ... TxAddr0+4*4-1:
286149ab747fSPaolo Bonzini rtl8139_TxAddr_write(s, addr-TxAddr0, val);
286249ab747fSPaolo Bonzini break;
286349ab747fSPaolo Bonzini
286449ab747fSPaolo Bonzini case RxBuf:
286549ab747fSPaolo Bonzini rtl8139_RxBuf_write(s, val);
286649ab747fSPaolo Bonzini break;
286749ab747fSPaolo Bonzini
286849ab747fSPaolo Bonzini case RxRingAddrLO:
286949ab747fSPaolo Bonzini DPRINTF("C+ RxRing low bits write val=0x%08x\n", val);
287049ab747fSPaolo Bonzini s->RxRingAddrLO = val;
287149ab747fSPaolo Bonzini break;
287249ab747fSPaolo Bonzini
287349ab747fSPaolo Bonzini case RxRingAddrHI:
287449ab747fSPaolo Bonzini DPRINTF("C+ RxRing high bits write val=0x%08x\n", val);
287549ab747fSPaolo Bonzini s->RxRingAddrHI = val;
287649ab747fSPaolo Bonzini break;
287749ab747fSPaolo Bonzini
287849ab747fSPaolo Bonzini case Timer:
287949ab747fSPaolo Bonzini DPRINTF("TCTR Timer reset on write\n");
2880bc72ad67SAlex Bligh s->TCTR_base = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
2881237c255cSPaolo Bonzini rtl8139_set_next_tctr_time(s);
288249ab747fSPaolo Bonzini break;
288349ab747fSPaolo Bonzini
288449ab747fSPaolo Bonzini case FlashReg:
288549ab747fSPaolo Bonzini DPRINTF("FlashReg TimerInt write val=0x%08x\n", val);
288649ab747fSPaolo Bonzini if (s->TimerInt != val) {
288749ab747fSPaolo Bonzini s->TimerInt = val;
2888237c255cSPaolo Bonzini rtl8139_set_next_tctr_time(s);
288949ab747fSPaolo Bonzini }
289049ab747fSPaolo Bonzini break;
289149ab747fSPaolo Bonzini
289249ab747fSPaolo Bonzini default:
289349ab747fSPaolo Bonzini DPRINTF("ioport write(l) addr=0x%x val=0x%08x via write(b)\n",
289449ab747fSPaolo Bonzini addr, val);
289549ab747fSPaolo Bonzini rtl8139_io_writeb(opaque, addr, val & 0xff);
289649ab747fSPaolo Bonzini rtl8139_io_writeb(opaque, addr + 1, (val >> 8) & 0xff);
289749ab747fSPaolo Bonzini rtl8139_io_writeb(opaque, addr + 2, (val >> 16) & 0xff);
289849ab747fSPaolo Bonzini rtl8139_io_writeb(opaque, addr + 3, (val >> 24) & 0xff);
289949ab747fSPaolo Bonzini break;
290049ab747fSPaolo Bonzini }
290149ab747fSPaolo Bonzini }
290249ab747fSPaolo Bonzini
rtl8139_io_readb(void * opaque,uint8_t addr)290349ab747fSPaolo Bonzini static uint32_t rtl8139_io_readb(void *opaque, uint8_t addr)
290449ab747fSPaolo Bonzini {
290549ab747fSPaolo Bonzini RTL8139State *s = opaque;
290649ab747fSPaolo Bonzini int ret;
290749ab747fSPaolo Bonzini
290849ab747fSPaolo Bonzini switch (addr)
290949ab747fSPaolo Bonzini {
291049ab747fSPaolo Bonzini case MAC0 ... MAC0+5:
291149ab747fSPaolo Bonzini ret = s->phys[addr - MAC0];
291249ab747fSPaolo Bonzini break;
291349ab747fSPaolo Bonzini case MAC0+6 ... MAC0+7:
291449ab747fSPaolo Bonzini ret = 0;
291549ab747fSPaolo Bonzini break;
291649ab747fSPaolo Bonzini case MAR0 ... MAR0+7:
291749ab747fSPaolo Bonzini ret = s->mult[addr - MAR0];
291849ab747fSPaolo Bonzini break;
291949ab747fSPaolo Bonzini case TxStatus0 ... TxStatus0+4*4-1:
292049ab747fSPaolo Bonzini ret = rtl8139_TxStatus_TxAddr_read(s, s->TxStatus, TxStatus0,
292149ab747fSPaolo Bonzini addr, 1);
292249ab747fSPaolo Bonzini break;
292349ab747fSPaolo Bonzini case ChipCmd:
292449ab747fSPaolo Bonzini ret = rtl8139_ChipCmd_read(s);
292549ab747fSPaolo Bonzini break;
292649ab747fSPaolo Bonzini case Cfg9346:
292749ab747fSPaolo Bonzini ret = rtl8139_Cfg9346_read(s);
292849ab747fSPaolo Bonzini break;
292949ab747fSPaolo Bonzini case Config0:
293049ab747fSPaolo Bonzini ret = rtl8139_Config0_read(s);
293149ab747fSPaolo Bonzini break;
293249ab747fSPaolo Bonzini case Config1:
293349ab747fSPaolo Bonzini ret = rtl8139_Config1_read(s);
293449ab747fSPaolo Bonzini break;
293549ab747fSPaolo Bonzini case Config3:
293649ab747fSPaolo Bonzini ret = rtl8139_Config3_read(s);
293749ab747fSPaolo Bonzini break;
293849ab747fSPaolo Bonzini case Config4:
293949ab747fSPaolo Bonzini ret = rtl8139_Config4_read(s);
294049ab747fSPaolo Bonzini break;
294149ab747fSPaolo Bonzini case Config5:
294249ab747fSPaolo Bonzini ret = rtl8139_Config5_read(s);
294349ab747fSPaolo Bonzini break;
294449ab747fSPaolo Bonzini
294549ab747fSPaolo Bonzini case MediaStatus:
294649ab747fSPaolo Bonzini /* The LinkDown bit of MediaStatus is inverse with link status */
294749ab747fSPaolo Bonzini ret = 0xd0 | (~s->BasicModeStatus & 0x04);
294849ab747fSPaolo Bonzini DPRINTF("MediaStatus read 0x%x\n", ret);
294949ab747fSPaolo Bonzini break;
295049ab747fSPaolo Bonzini
295149ab747fSPaolo Bonzini case HltClk:
295249ab747fSPaolo Bonzini ret = s->clock_enabled;
295349ab747fSPaolo Bonzini DPRINTF("HltClk read 0x%x\n", ret);
295449ab747fSPaolo Bonzini break;
295549ab747fSPaolo Bonzini
295649ab747fSPaolo Bonzini case PCIRevisionID:
295749ab747fSPaolo Bonzini ret = RTL8139_PCI_REVID;
295849ab747fSPaolo Bonzini DPRINTF("PCI Revision ID read 0x%x\n", ret);
295949ab747fSPaolo Bonzini break;
296049ab747fSPaolo Bonzini
296149ab747fSPaolo Bonzini case TxThresh:
296249ab747fSPaolo Bonzini ret = s->TxThresh;
296349ab747fSPaolo Bonzini DPRINTF("C+ TxThresh read(b) val=0x%02x\n", ret);
296449ab747fSPaolo Bonzini break;
296549ab747fSPaolo Bonzini
296649ab747fSPaolo Bonzini case 0x43: /* Part of TxConfig register. Windows driver tries to read it */
296749ab747fSPaolo Bonzini ret = s->TxConfig >> 24;
296849ab747fSPaolo Bonzini DPRINTF("RTL8139C TxConfig at 0x43 read(b) val=0x%02x\n", ret);
296949ab747fSPaolo Bonzini break;
297049ab747fSPaolo Bonzini
297149ab747fSPaolo Bonzini default:
297249ab747fSPaolo Bonzini DPRINTF("not implemented read(b) addr=0x%x\n", addr);
297349ab747fSPaolo Bonzini ret = 0;
297449ab747fSPaolo Bonzini break;
297549ab747fSPaolo Bonzini }
297649ab747fSPaolo Bonzini
297749ab747fSPaolo Bonzini return ret;
297849ab747fSPaolo Bonzini }
297949ab747fSPaolo Bonzini
rtl8139_io_readw(void * opaque,uint8_t addr)298049ab747fSPaolo Bonzini static uint32_t rtl8139_io_readw(void *opaque, uint8_t addr)
298149ab747fSPaolo Bonzini {
298249ab747fSPaolo Bonzini RTL8139State *s = opaque;
298349ab747fSPaolo Bonzini uint32_t ret;
298449ab747fSPaolo Bonzini
298549ab747fSPaolo Bonzini switch (addr)
298649ab747fSPaolo Bonzini {
298749ab747fSPaolo Bonzini case TxAddr0 ... TxAddr0+4*4-1:
298849ab747fSPaolo Bonzini ret = rtl8139_TxStatus_TxAddr_read(s, s->TxAddr, TxAddr0, addr, 2);
298949ab747fSPaolo Bonzini break;
299049ab747fSPaolo Bonzini case IntrMask:
299149ab747fSPaolo Bonzini ret = rtl8139_IntrMask_read(s);
299249ab747fSPaolo Bonzini break;
299349ab747fSPaolo Bonzini
299449ab747fSPaolo Bonzini case IntrStatus:
299549ab747fSPaolo Bonzini ret = rtl8139_IntrStatus_read(s);
299649ab747fSPaolo Bonzini break;
299749ab747fSPaolo Bonzini
299849ab747fSPaolo Bonzini case MultiIntr:
299949ab747fSPaolo Bonzini ret = rtl8139_MultiIntr_read(s);
300049ab747fSPaolo Bonzini break;
300149ab747fSPaolo Bonzini
300249ab747fSPaolo Bonzini case RxBufPtr:
300349ab747fSPaolo Bonzini ret = rtl8139_RxBufPtr_read(s);
300449ab747fSPaolo Bonzini break;
300549ab747fSPaolo Bonzini
300649ab747fSPaolo Bonzini case RxBufAddr:
300749ab747fSPaolo Bonzini ret = rtl8139_RxBufAddr_read(s);
300849ab747fSPaolo Bonzini break;
300949ab747fSPaolo Bonzini
301049ab747fSPaolo Bonzini case BasicModeCtrl:
301149ab747fSPaolo Bonzini ret = rtl8139_BasicModeCtrl_read(s);
301249ab747fSPaolo Bonzini break;
301349ab747fSPaolo Bonzini case BasicModeStatus:
301449ab747fSPaolo Bonzini ret = rtl8139_BasicModeStatus_read(s);
301549ab747fSPaolo Bonzini break;
301649ab747fSPaolo Bonzini case NWayAdvert:
301749ab747fSPaolo Bonzini ret = s->NWayAdvert;
301849ab747fSPaolo Bonzini DPRINTF("NWayAdvert read(w) val=0x%04x\n", ret);
301949ab747fSPaolo Bonzini break;
302049ab747fSPaolo Bonzini case NWayLPAR:
302149ab747fSPaolo Bonzini ret = s->NWayLPAR;
302249ab747fSPaolo Bonzini DPRINTF("NWayLPAR read(w) val=0x%04x\n", ret);
302349ab747fSPaolo Bonzini break;
302449ab747fSPaolo Bonzini case NWayExpansion:
302549ab747fSPaolo Bonzini ret = s->NWayExpansion;
302649ab747fSPaolo Bonzini DPRINTF("NWayExpansion read(w) val=0x%04x\n", ret);
302749ab747fSPaolo Bonzini break;
302849ab747fSPaolo Bonzini
302949ab747fSPaolo Bonzini case CpCmd:
303049ab747fSPaolo Bonzini ret = rtl8139_CpCmd_read(s);
303149ab747fSPaolo Bonzini break;
303249ab747fSPaolo Bonzini
303349ab747fSPaolo Bonzini case IntrMitigate:
303449ab747fSPaolo Bonzini ret = rtl8139_IntrMitigate_read(s);
303549ab747fSPaolo Bonzini break;
303649ab747fSPaolo Bonzini
303749ab747fSPaolo Bonzini case TxSummary:
303849ab747fSPaolo Bonzini ret = rtl8139_TSAD_read(s);
303949ab747fSPaolo Bonzini break;
304049ab747fSPaolo Bonzini
304149ab747fSPaolo Bonzini case CSCR:
304249ab747fSPaolo Bonzini ret = rtl8139_CSCR_read(s);
304349ab747fSPaolo Bonzini break;
304449ab747fSPaolo Bonzini
304549ab747fSPaolo Bonzini default:
304649ab747fSPaolo Bonzini DPRINTF("ioport read(w) addr=0x%x via read(b)\n", addr);
304749ab747fSPaolo Bonzini
304849ab747fSPaolo Bonzini ret = rtl8139_io_readb(opaque, addr);
304949ab747fSPaolo Bonzini ret |= rtl8139_io_readb(opaque, addr + 1) << 8;
305049ab747fSPaolo Bonzini
305149ab747fSPaolo Bonzini DPRINTF("ioport read(w) addr=0x%x val=0x%04x\n", addr, ret);
305249ab747fSPaolo Bonzini break;
305349ab747fSPaolo Bonzini }
305449ab747fSPaolo Bonzini
305549ab747fSPaolo Bonzini return ret;
305649ab747fSPaolo Bonzini }
305749ab747fSPaolo Bonzini
rtl8139_io_readl(void * opaque,uint8_t addr)305849ab747fSPaolo Bonzini static uint32_t rtl8139_io_readl(void *opaque, uint8_t addr)
305949ab747fSPaolo Bonzini {
306049ab747fSPaolo Bonzini RTL8139State *s = opaque;
306149ab747fSPaolo Bonzini uint32_t ret;
306249ab747fSPaolo Bonzini
306349ab747fSPaolo Bonzini switch (addr)
306449ab747fSPaolo Bonzini {
306549ab747fSPaolo Bonzini case RxMissed:
306649ab747fSPaolo Bonzini ret = s->RxMissed;
306749ab747fSPaolo Bonzini
306849ab747fSPaolo Bonzini DPRINTF("RxMissed read val=0x%08x\n", ret);
306949ab747fSPaolo Bonzini break;
307049ab747fSPaolo Bonzini
307149ab747fSPaolo Bonzini case TxConfig:
307249ab747fSPaolo Bonzini ret = rtl8139_TxConfig_read(s);
307349ab747fSPaolo Bonzini break;
307449ab747fSPaolo Bonzini
307549ab747fSPaolo Bonzini case RxConfig:
307649ab747fSPaolo Bonzini ret = rtl8139_RxConfig_read(s);
307749ab747fSPaolo Bonzini break;
307849ab747fSPaolo Bonzini
307949ab747fSPaolo Bonzini case TxStatus0 ... TxStatus0+4*4-1:
308049ab747fSPaolo Bonzini ret = rtl8139_TxStatus_TxAddr_read(s, s->TxStatus, TxStatus0,
308149ab747fSPaolo Bonzini addr, 4);
308249ab747fSPaolo Bonzini break;
308349ab747fSPaolo Bonzini
308449ab747fSPaolo Bonzini case TxAddr0 ... TxAddr0+4*4-1:
308549ab747fSPaolo Bonzini ret = rtl8139_TxAddr_read(s, addr-TxAddr0);
308649ab747fSPaolo Bonzini break;
308749ab747fSPaolo Bonzini
308849ab747fSPaolo Bonzini case RxBuf:
308949ab747fSPaolo Bonzini ret = rtl8139_RxBuf_read(s);
309049ab747fSPaolo Bonzini break;
309149ab747fSPaolo Bonzini
309249ab747fSPaolo Bonzini case RxRingAddrLO:
309349ab747fSPaolo Bonzini ret = s->RxRingAddrLO;
309449ab747fSPaolo Bonzini DPRINTF("C+ RxRing low bits read val=0x%08x\n", ret);
309549ab747fSPaolo Bonzini break;
309649ab747fSPaolo Bonzini
309749ab747fSPaolo Bonzini case RxRingAddrHI:
309849ab747fSPaolo Bonzini ret = s->RxRingAddrHI;
309949ab747fSPaolo Bonzini DPRINTF("C+ RxRing high bits read val=0x%08x\n", ret);
310049ab747fSPaolo Bonzini break;
310149ab747fSPaolo Bonzini
310249ab747fSPaolo Bonzini case Timer:
310337b9ab92SLaurent Vivier ret = (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - s->TCTR_base) /
310437b9ab92SLaurent Vivier PCI_PERIOD;
310549ab747fSPaolo Bonzini DPRINTF("TCTR Timer read val=0x%08x\n", ret);
310649ab747fSPaolo Bonzini break;
310749ab747fSPaolo Bonzini
310849ab747fSPaolo Bonzini case FlashReg:
310949ab747fSPaolo Bonzini ret = s->TimerInt;
311049ab747fSPaolo Bonzini DPRINTF("FlashReg TimerInt read val=0x%08x\n", ret);
311149ab747fSPaolo Bonzini break;
311249ab747fSPaolo Bonzini
311349ab747fSPaolo Bonzini default:
311449ab747fSPaolo Bonzini DPRINTF("ioport read(l) addr=0x%x via read(b)\n", addr);
311549ab747fSPaolo Bonzini
311649ab747fSPaolo Bonzini ret = rtl8139_io_readb(opaque, addr);
311749ab747fSPaolo Bonzini ret |= rtl8139_io_readb(opaque, addr + 1) << 8;
311849ab747fSPaolo Bonzini ret |= rtl8139_io_readb(opaque, addr + 2) << 16;
311949ab747fSPaolo Bonzini ret |= rtl8139_io_readb(opaque, addr + 3) << 24;
312049ab747fSPaolo Bonzini
312149ab747fSPaolo Bonzini DPRINTF("read(l) addr=0x%x val=%08x\n", addr, ret);
312249ab747fSPaolo Bonzini break;
312349ab747fSPaolo Bonzini }
312449ab747fSPaolo Bonzini
312549ab747fSPaolo Bonzini return ret;
312649ab747fSPaolo Bonzini }
312749ab747fSPaolo Bonzini
312849ab747fSPaolo Bonzini /* */
312949ab747fSPaolo Bonzini
rtl8139_post_load(void * opaque,int version_id)313049ab747fSPaolo Bonzini static int rtl8139_post_load(void *opaque, int version_id)
313149ab747fSPaolo Bonzini {
313249ab747fSPaolo Bonzini RTL8139State* s = opaque;
3133237c255cSPaolo Bonzini rtl8139_set_next_tctr_time(s);
313449ab747fSPaolo Bonzini if (version_id < 4) {
313549ab747fSPaolo Bonzini s->cplus_enabled = s->CpCmd != 0;
313649ab747fSPaolo Bonzini }
313749ab747fSPaolo Bonzini
313849ab747fSPaolo Bonzini /* nc.link_down can't be migrated, so infer link_down according
313949ab747fSPaolo Bonzini * to link status bit in BasicModeStatus */
314049ab747fSPaolo Bonzini qemu_get_queue(s->nic)->link_down = (s->BasicModeStatus & 0x04) == 0;
314149ab747fSPaolo Bonzini
314249ab747fSPaolo Bonzini return 0;
314349ab747fSPaolo Bonzini }
314449ab747fSPaolo Bonzini
rtl8139_hotplug_ready_needed(void * opaque)314549ab747fSPaolo Bonzini static bool rtl8139_hotplug_ready_needed(void *opaque)
314649ab747fSPaolo Bonzini {
314749ab747fSPaolo Bonzini return qdev_machine_modified();
314849ab747fSPaolo Bonzini }
314949ab747fSPaolo Bonzini
315049ab747fSPaolo Bonzini static const VMStateDescription vmstate_rtl8139_hotplug_ready ={
315149ab747fSPaolo Bonzini .name = "rtl8139/hotplug_ready",
315249ab747fSPaolo Bonzini .version_id = 1,
315349ab747fSPaolo Bonzini .minimum_version_id = 1,
31545cd8cadaSJuan Quintela .needed = rtl8139_hotplug_ready_needed,
31551de81b42SRichard Henderson .fields = (const VMStateField[]) {
315649ab747fSPaolo Bonzini VMSTATE_END_OF_LIST()
315749ab747fSPaolo Bonzini }
315849ab747fSPaolo Bonzini };
315949ab747fSPaolo Bonzini
rtl8139_pre_save(void * opaque)316044b1ff31SDr. David Alan Gilbert static int rtl8139_pre_save(void *opaque)
316149ab747fSPaolo Bonzini {
316249ab747fSPaolo Bonzini RTL8139State* s = opaque;
3163bc72ad67SAlex Bligh int64_t current_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
316449ab747fSPaolo Bonzini
3165237c255cSPaolo Bonzini /* for migration to older versions */
316637b9ab92SLaurent Vivier s->TCTR = (current_time - s->TCTR_base) / PCI_PERIOD;
316749ab747fSPaolo Bonzini s->rtl8139_mmio_io_addr_dummy = 0;
316844b1ff31SDr. David Alan Gilbert
316944b1ff31SDr. David Alan Gilbert return 0;
317049ab747fSPaolo Bonzini }
317149ab747fSPaolo Bonzini
317249ab747fSPaolo Bonzini static const VMStateDescription vmstate_rtl8139 = {
317349ab747fSPaolo Bonzini .name = "rtl8139",
317446fe8befSDavid Vrabel .version_id = 5,
317549ab747fSPaolo Bonzini .minimum_version_id = 3,
317649ab747fSPaolo Bonzini .post_load = rtl8139_post_load,
317749ab747fSPaolo Bonzini .pre_save = rtl8139_pre_save,
31781de81b42SRichard Henderson .fields = (const VMStateField[]) {
317988a411a8SAndreas Färber VMSTATE_PCI_DEVICE(parent_obj, RTL8139State),
318049ab747fSPaolo Bonzini VMSTATE_PARTIAL_BUFFER(phys, RTL8139State, 6),
318149ab747fSPaolo Bonzini VMSTATE_BUFFER(mult, RTL8139State),
318249ab747fSPaolo Bonzini VMSTATE_UINT32_ARRAY(TxStatus, RTL8139State, 4),
318349ab747fSPaolo Bonzini VMSTATE_UINT32_ARRAY(TxAddr, RTL8139State, 4),
318449ab747fSPaolo Bonzini
318549ab747fSPaolo Bonzini VMSTATE_UINT32(RxBuf, RTL8139State),
318649ab747fSPaolo Bonzini VMSTATE_UINT32(RxBufferSize, RTL8139State),
318749ab747fSPaolo Bonzini VMSTATE_UINT32(RxBufPtr, RTL8139State),
318849ab747fSPaolo Bonzini VMSTATE_UINT32(RxBufAddr, RTL8139State),
318949ab747fSPaolo Bonzini
319049ab747fSPaolo Bonzini VMSTATE_UINT16(IntrStatus, RTL8139State),
319149ab747fSPaolo Bonzini VMSTATE_UINT16(IntrMask, RTL8139State),
319249ab747fSPaolo Bonzini
319349ab747fSPaolo Bonzini VMSTATE_UINT32(TxConfig, RTL8139State),
319449ab747fSPaolo Bonzini VMSTATE_UINT32(RxConfig, RTL8139State),
319549ab747fSPaolo Bonzini VMSTATE_UINT32(RxMissed, RTL8139State),
319649ab747fSPaolo Bonzini VMSTATE_UINT16(CSCR, RTL8139State),
319749ab747fSPaolo Bonzini
319849ab747fSPaolo Bonzini VMSTATE_UINT8(Cfg9346, RTL8139State),
319949ab747fSPaolo Bonzini VMSTATE_UINT8(Config0, RTL8139State),
320049ab747fSPaolo Bonzini VMSTATE_UINT8(Config1, RTL8139State),
320149ab747fSPaolo Bonzini VMSTATE_UINT8(Config3, RTL8139State),
320249ab747fSPaolo Bonzini VMSTATE_UINT8(Config4, RTL8139State),
320349ab747fSPaolo Bonzini VMSTATE_UINT8(Config5, RTL8139State),
320449ab747fSPaolo Bonzini
320549ab747fSPaolo Bonzini VMSTATE_UINT8(clock_enabled, RTL8139State),
320649ab747fSPaolo Bonzini VMSTATE_UINT8(bChipCmdState, RTL8139State),
320749ab747fSPaolo Bonzini
320849ab747fSPaolo Bonzini VMSTATE_UINT16(MultiIntr, RTL8139State),
320949ab747fSPaolo Bonzini
321049ab747fSPaolo Bonzini VMSTATE_UINT16(BasicModeCtrl, RTL8139State),
321149ab747fSPaolo Bonzini VMSTATE_UINT16(BasicModeStatus, RTL8139State),
321249ab747fSPaolo Bonzini VMSTATE_UINT16(NWayAdvert, RTL8139State),
321349ab747fSPaolo Bonzini VMSTATE_UINT16(NWayLPAR, RTL8139State),
321449ab747fSPaolo Bonzini VMSTATE_UINT16(NWayExpansion, RTL8139State),
321549ab747fSPaolo Bonzini
321649ab747fSPaolo Bonzini VMSTATE_UINT16(CpCmd, RTL8139State),
321749ab747fSPaolo Bonzini VMSTATE_UINT8(TxThresh, RTL8139State),
321849ab747fSPaolo Bonzini
321949ab747fSPaolo Bonzini VMSTATE_UNUSED(4),
322049ab747fSPaolo Bonzini VMSTATE_MACADDR(conf.macaddr, RTL8139State),
322149ab747fSPaolo Bonzini VMSTATE_INT32(rtl8139_mmio_io_addr_dummy, RTL8139State),
322249ab747fSPaolo Bonzini
322349ab747fSPaolo Bonzini VMSTATE_UINT32(currTxDesc, RTL8139State),
322449ab747fSPaolo Bonzini VMSTATE_UINT32(currCPlusRxDesc, RTL8139State),
322549ab747fSPaolo Bonzini VMSTATE_UINT32(currCPlusTxDesc, RTL8139State),
322649ab747fSPaolo Bonzini VMSTATE_UINT32(RxRingAddrLO, RTL8139State),
322749ab747fSPaolo Bonzini VMSTATE_UINT32(RxRingAddrHI, RTL8139State),
322849ab747fSPaolo Bonzini
322949ab747fSPaolo Bonzini VMSTATE_UINT16_ARRAY(eeprom.contents, RTL8139State, EEPROM_9346_SIZE),
323049ab747fSPaolo Bonzini VMSTATE_INT32(eeprom.mode, RTL8139State),
323149ab747fSPaolo Bonzini VMSTATE_UINT32(eeprom.tick, RTL8139State),
323249ab747fSPaolo Bonzini VMSTATE_UINT8(eeprom.address, RTL8139State),
323349ab747fSPaolo Bonzini VMSTATE_UINT16(eeprom.input, RTL8139State),
323449ab747fSPaolo Bonzini VMSTATE_UINT16(eeprom.output, RTL8139State),
323549ab747fSPaolo Bonzini
323649ab747fSPaolo Bonzini VMSTATE_UINT8(eeprom.eecs, RTL8139State),
323749ab747fSPaolo Bonzini VMSTATE_UINT8(eeprom.eesk, RTL8139State),
323849ab747fSPaolo Bonzini VMSTATE_UINT8(eeprom.eedi, RTL8139State),
323949ab747fSPaolo Bonzini VMSTATE_UINT8(eeprom.eedo, RTL8139State),
324049ab747fSPaolo Bonzini
324149ab747fSPaolo Bonzini VMSTATE_UINT32(TCTR, RTL8139State),
324249ab747fSPaolo Bonzini VMSTATE_UINT32(TimerInt, RTL8139State),
324349ab747fSPaolo Bonzini VMSTATE_INT64(TCTR_base, RTL8139State),
324449ab747fSPaolo Bonzini
324546fe8befSDavid Vrabel VMSTATE_UINT64(tally_counters.TxOk, RTL8139State),
324646fe8befSDavid Vrabel VMSTATE_UINT64(tally_counters.RxOk, RTL8139State),
324746fe8befSDavid Vrabel VMSTATE_UINT64(tally_counters.TxERR, RTL8139State),
324846fe8befSDavid Vrabel VMSTATE_UINT32(tally_counters.RxERR, RTL8139State),
324946fe8befSDavid Vrabel VMSTATE_UINT16(tally_counters.MissPkt, RTL8139State),
325046fe8befSDavid Vrabel VMSTATE_UINT16(tally_counters.FAE, RTL8139State),
325146fe8befSDavid Vrabel VMSTATE_UINT32(tally_counters.Tx1Col, RTL8139State),
325246fe8befSDavid Vrabel VMSTATE_UINT32(tally_counters.TxMCol, RTL8139State),
325346fe8befSDavid Vrabel VMSTATE_UINT64(tally_counters.RxOkPhy, RTL8139State),
325446fe8befSDavid Vrabel VMSTATE_UINT64(tally_counters.RxOkBrd, RTL8139State),
325546fe8befSDavid Vrabel VMSTATE_UINT32_V(tally_counters.RxOkMul, RTL8139State, 5),
325646fe8befSDavid Vrabel VMSTATE_UINT16(tally_counters.TxAbt, RTL8139State),
325746fe8befSDavid Vrabel VMSTATE_UINT16(tally_counters.TxUndrn, RTL8139State),
325849ab747fSPaolo Bonzini
325949ab747fSPaolo Bonzini VMSTATE_UINT32_V(cplus_enabled, RTL8139State, 4),
326049ab747fSPaolo Bonzini VMSTATE_END_OF_LIST()
326149ab747fSPaolo Bonzini },
32621de81b42SRichard Henderson .subsections = (const VMStateDescription * const []) {
32635cd8cadaSJuan Quintela &vmstate_rtl8139_hotplug_ready,
32645cd8cadaSJuan Quintela NULL
326549ab747fSPaolo Bonzini }
326649ab747fSPaolo Bonzini };
326749ab747fSPaolo Bonzini
326849ab747fSPaolo Bonzini /***********************************************************/
326949ab747fSPaolo Bonzini /* PCI RTL8139 definitions */
327049ab747fSPaolo Bonzini
rtl8139_ioport_write(void * opaque,hwaddr addr,uint64_t val,unsigned size)327149ab747fSPaolo Bonzini static void rtl8139_ioport_write(void *opaque, hwaddr addr,
327249ab747fSPaolo Bonzini uint64_t val, unsigned size)
327349ab747fSPaolo Bonzini {
327449ab747fSPaolo Bonzini switch (size) {
327549ab747fSPaolo Bonzini case 1:
327649ab747fSPaolo Bonzini rtl8139_io_writeb(opaque, addr, val);
327749ab747fSPaolo Bonzini break;
327849ab747fSPaolo Bonzini case 2:
327949ab747fSPaolo Bonzini rtl8139_io_writew(opaque, addr, val);
328049ab747fSPaolo Bonzini break;
328149ab747fSPaolo Bonzini case 4:
328249ab747fSPaolo Bonzini rtl8139_io_writel(opaque, addr, val);
328349ab747fSPaolo Bonzini break;
328449ab747fSPaolo Bonzini }
328549ab747fSPaolo Bonzini }
328649ab747fSPaolo Bonzini
rtl8139_ioport_read(void * opaque,hwaddr addr,unsigned size)328749ab747fSPaolo Bonzini static uint64_t rtl8139_ioport_read(void *opaque, hwaddr addr,
328849ab747fSPaolo Bonzini unsigned size)
328949ab747fSPaolo Bonzini {
329049ab747fSPaolo Bonzini switch (size) {
329149ab747fSPaolo Bonzini case 1:
329249ab747fSPaolo Bonzini return rtl8139_io_readb(opaque, addr);
329349ab747fSPaolo Bonzini case 2:
329449ab747fSPaolo Bonzini return rtl8139_io_readw(opaque, addr);
329549ab747fSPaolo Bonzini case 4:
329649ab747fSPaolo Bonzini return rtl8139_io_readl(opaque, addr);
329749ab747fSPaolo Bonzini }
329849ab747fSPaolo Bonzini
329949ab747fSPaolo Bonzini return -1;
330049ab747fSPaolo Bonzini }
330149ab747fSPaolo Bonzini
330249ab747fSPaolo Bonzini static const MemoryRegionOps rtl8139_io_ops = {
330349ab747fSPaolo Bonzini .read = rtl8139_ioport_read,
330449ab747fSPaolo Bonzini .write = rtl8139_ioport_write,
330549ab747fSPaolo Bonzini .impl = {
330649ab747fSPaolo Bonzini .min_access_size = 1,
330749ab747fSPaolo Bonzini .max_access_size = 4,
330849ab747fSPaolo Bonzini },
330949ab747fSPaolo Bonzini .endianness = DEVICE_LITTLE_ENDIAN,
331049ab747fSPaolo Bonzini };
331149ab747fSPaolo Bonzini
rtl8139_timer(void * opaque)331249ab747fSPaolo Bonzini static void rtl8139_timer(void *opaque)
331349ab747fSPaolo Bonzini {
331449ab747fSPaolo Bonzini RTL8139State *s = opaque;
331549ab747fSPaolo Bonzini
331649ab747fSPaolo Bonzini if (!s->clock_enabled)
331749ab747fSPaolo Bonzini {
331849ab747fSPaolo Bonzini DPRINTF(">>> timer: clock is not running\n");
331949ab747fSPaolo Bonzini return;
332049ab747fSPaolo Bonzini }
332149ab747fSPaolo Bonzini
332249ab747fSPaolo Bonzini s->IntrStatus |= PCSTimeout;
332349ab747fSPaolo Bonzini rtl8139_update_irq(s);
3324237c255cSPaolo Bonzini rtl8139_set_next_tctr_time(s);
332549ab747fSPaolo Bonzini }
332649ab747fSPaolo Bonzini
pci_rtl8139_uninit(PCIDevice * dev)332749ab747fSPaolo Bonzini static void pci_rtl8139_uninit(PCIDevice *dev)
332849ab747fSPaolo Bonzini {
332939257515SPeter Crosthwaite RTL8139State *s = RTL8139(dev);
333049ab747fSPaolo Bonzini
333149ab747fSPaolo Bonzini g_free(s->cplus_txbuffer);
333249ab747fSPaolo Bonzini s->cplus_txbuffer = NULL;
3333bc72ad67SAlex Bligh timer_free(s->timer);
333449ab747fSPaolo Bonzini qemu_del_nic(s->nic);
333549ab747fSPaolo Bonzini }
333649ab747fSPaolo Bonzini
rtl8139_set_link_status(NetClientState * nc)333749ab747fSPaolo Bonzini static void rtl8139_set_link_status(NetClientState *nc)
333849ab747fSPaolo Bonzini {
333949ab747fSPaolo Bonzini RTL8139State *s = qemu_get_nic_opaque(nc);
334049ab747fSPaolo Bonzini
334149ab747fSPaolo Bonzini if (nc->link_down) {
334249ab747fSPaolo Bonzini s->BasicModeStatus &= ~0x04;
334349ab747fSPaolo Bonzini } else {
334449ab747fSPaolo Bonzini s->BasicModeStatus |= 0x04;
334549ab747fSPaolo Bonzini }
334649ab747fSPaolo Bonzini
334749ab747fSPaolo Bonzini s->IntrStatus |= RxUnderrun;
334849ab747fSPaolo Bonzini rtl8139_update_irq(s);
334949ab747fSPaolo Bonzini }
335049ab747fSPaolo Bonzini
335149ab747fSPaolo Bonzini static NetClientInfo net_rtl8139_info = {
3352f394b2e2SEric Blake .type = NET_CLIENT_DRIVER_NIC,
335349ab747fSPaolo Bonzini .size = sizeof(NICState),
335449ab747fSPaolo Bonzini .can_receive = rtl8139_can_receive,
335549ab747fSPaolo Bonzini .receive = rtl8139_receive,
335649ab747fSPaolo Bonzini .link_status_changed = rtl8139_set_link_status,
335749ab747fSPaolo Bonzini };
335849ab747fSPaolo Bonzini
pci_rtl8139_realize(PCIDevice * dev,Error ** errp)33599af21dbeSMarkus Armbruster static void pci_rtl8139_realize(PCIDevice *dev, Error **errp)
336049ab747fSPaolo Bonzini {
336139257515SPeter Crosthwaite RTL8139State *s = RTL8139(dev);
336239257515SPeter Crosthwaite DeviceState *d = DEVICE(dev);
336349ab747fSPaolo Bonzini uint8_t *pci_conf;
336449ab747fSPaolo Bonzini
336588a411a8SAndreas Färber pci_conf = dev->config;
336649ab747fSPaolo Bonzini pci_conf[PCI_INTERRUPT_PIN] = 1; /* interrupt pin A */
336749ab747fSPaolo Bonzini /* TODO: start of capability list, but no capability
336849ab747fSPaolo Bonzini * list bit in status register, and offset 0xdc seems unused. */
336949ab747fSPaolo Bonzini pci_conf[PCI_CAPABILITY_LIST] = 0xdc;
337049ab747fSPaolo Bonzini
3371eedfac6fSPaolo Bonzini memory_region_init_io(&s->bar_io, OBJECT(s), &rtl8139_io_ops, s,
3372eedfac6fSPaolo Bonzini "rtl8139", 0x100);
3373726ec828SMatt Parker memory_region_init_alias(&s->bar_mem, OBJECT(s), "rtl8139-mem", &s->bar_io,
3374726ec828SMatt Parker 0, 0x100);
3375726ec828SMatt Parker
337688a411a8SAndreas Färber pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->bar_io);
337788a411a8SAndreas Färber pci_register_bar(dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar_mem);
337849ab747fSPaolo Bonzini
337949ab747fSPaolo Bonzini qemu_macaddr_default_if_unset(&s->conf.macaddr);
338049ab747fSPaolo Bonzini
338149ab747fSPaolo Bonzini /* prepare eeprom */
338249ab747fSPaolo Bonzini s->eeprom.contents[0] = 0x8129;
338349ab747fSPaolo Bonzini #if 1
338449ab747fSPaolo Bonzini /* PCI vendor and device ID should be mirrored here */
338549ab747fSPaolo Bonzini s->eeprom.contents[1] = PCI_VENDOR_ID_REALTEK;
338649ab747fSPaolo Bonzini s->eeprom.contents[2] = PCI_DEVICE_ID_REALTEK_8139;
338749ab747fSPaolo Bonzini #endif
338849ab747fSPaolo Bonzini s->eeprom.contents[7] = s->conf.macaddr.a[0] | s->conf.macaddr.a[1] << 8;
338949ab747fSPaolo Bonzini s->eeprom.contents[8] = s->conf.macaddr.a[2] | s->conf.macaddr.a[3] << 8;
339049ab747fSPaolo Bonzini s->eeprom.contents[9] = s->conf.macaddr.a[4] | s->conf.macaddr.a[5] << 8;
339149ab747fSPaolo Bonzini
339249ab747fSPaolo Bonzini s->nic = qemu_new_nic(&net_rtl8139_info, &s->conf,
33937d0fefdfSAkihiko Odaki object_get_typename(OBJECT(dev)), d->id,
33947d0fefdfSAkihiko Odaki &d->mem_reentrancy_guard, s);
339549ab747fSPaolo Bonzini qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
339649ab747fSPaolo Bonzini
339749ab747fSPaolo Bonzini s->cplus_txbuffer = NULL;
339849ab747fSPaolo Bonzini s->cplus_txbuffer_len = 0;
339949ab747fSPaolo Bonzini s->cplus_txbuffer_offset = 0;
340049ab747fSPaolo Bonzini
3401bc72ad67SAlex Bligh s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, rtl8139_timer, s);
340249ab747fSPaolo Bonzini }
340349ab747fSPaolo Bonzini
rtl8139_instance_init(Object * obj)3404afd7c850SGonglei static void rtl8139_instance_init(Object *obj)
3405afd7c850SGonglei {
3406afd7c850SGonglei RTL8139State *s = RTL8139(obj);
3407afd7c850SGonglei
3408afd7c850SGonglei device_add_bootindex_property(obj, &s->conf.bootindex,
3409afd7c850SGonglei "bootindex", "/ethernet-phy@0",
341040c2281cSMarkus Armbruster DEVICE(obj));
3411afd7c850SGonglei }
3412afd7c850SGonglei
341349ab747fSPaolo Bonzini static Property rtl8139_properties[] = {
341449ab747fSPaolo Bonzini DEFINE_NIC_PROPERTIES(RTL8139State, conf),
341549ab747fSPaolo Bonzini DEFINE_PROP_END_OF_LIST(),
341649ab747fSPaolo Bonzini };
341749ab747fSPaolo Bonzini
rtl8139_class_init(ObjectClass * klass,void * data)341849ab747fSPaolo Bonzini static void rtl8139_class_init(ObjectClass *klass, void *data)
341949ab747fSPaolo Bonzini {
342049ab747fSPaolo Bonzini DeviceClass *dc = DEVICE_CLASS(klass);
342149ab747fSPaolo Bonzini PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
342249ab747fSPaolo Bonzini
34239af21dbeSMarkus Armbruster k->realize = pci_rtl8139_realize;
342449ab747fSPaolo Bonzini k->exit = pci_rtl8139_uninit;
342549ab747fSPaolo Bonzini k->romfile = "efi-rtl8139.rom";
342649ab747fSPaolo Bonzini k->vendor_id = PCI_VENDOR_ID_REALTEK;
342749ab747fSPaolo Bonzini k->device_id = PCI_DEVICE_ID_REALTEK_8139;
342849ab747fSPaolo Bonzini k->revision = RTL8139_PCI_REVID; /* >=0x20 is for 8139C+ */
342949ab747fSPaolo Bonzini k->class_id = PCI_CLASS_NETWORK_ETHERNET;
3430e3d08143SPeter Maydell device_class_set_legacy_reset(dc, rtl8139_reset);
343149ab747fSPaolo Bonzini dc->vmsd = &vmstate_rtl8139;
34324f67d30bSMarc-André Lureau device_class_set_props(dc, rtl8139_properties);
3433125ee0edSMarcel Apfelbaum set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
343449ab747fSPaolo Bonzini }
343549ab747fSPaolo Bonzini
343649ab747fSPaolo Bonzini static const TypeInfo rtl8139_info = {
343739257515SPeter Crosthwaite .name = TYPE_RTL8139,
343849ab747fSPaolo Bonzini .parent = TYPE_PCI_DEVICE,
343949ab747fSPaolo Bonzini .instance_size = sizeof(RTL8139State),
344049ab747fSPaolo Bonzini .class_init = rtl8139_class_init,
3441afd7c850SGonglei .instance_init = rtl8139_instance_init,
3442fd3b02c8SEduardo Habkost .interfaces = (InterfaceInfo[]) {
3443fd3b02c8SEduardo Habkost { INTERFACE_CONVENTIONAL_PCI_DEVICE },
3444fd3b02c8SEduardo Habkost { },
3445fd3b02c8SEduardo Habkost },
344649ab747fSPaolo Bonzini };
344749ab747fSPaolo Bonzini
rtl8139_register_types(void)344849ab747fSPaolo Bonzini static void rtl8139_register_types(void)
344949ab747fSPaolo Bonzini {
345049ab747fSPaolo Bonzini type_register_static(&rtl8139_info);
345149ab747fSPaolo Bonzini }
345249ab747fSPaolo Bonzini
345349ab747fSPaolo Bonzini type_init(rtl8139_register_types)
3454