149ab747fSPaolo Bonzini /*
249ab747fSPaolo Bonzini * QEMU e1000 emulation
349ab747fSPaolo Bonzini *
449ab747fSPaolo Bonzini * Software developer's manual:
549ab747fSPaolo Bonzini * http://download.intel.com/design/network/manuals/8254x_GBe_SDM.pdf
649ab747fSPaolo Bonzini *
749ab747fSPaolo Bonzini * Nir Peleg, Tutis Systems Ltd. for Qumranet Inc.
849ab747fSPaolo Bonzini * Copyright (c) 2008 Qumranet
949ab747fSPaolo Bonzini * Based on work done by:
1049ab747fSPaolo Bonzini * Copyright (c) 2007 Dan Aloni
1149ab747fSPaolo Bonzini * Copyright (c) 2004 Antony T Curtis
1249ab747fSPaolo Bonzini *
1349ab747fSPaolo Bonzini * This library is free software; you can redistribute it and/or
1449ab747fSPaolo Bonzini * modify it under the terms of the GNU Lesser General Public
1549ab747fSPaolo Bonzini * License as published by the Free Software Foundation; either
1661f3c91aSChetan Pant * version 2.1 of the License, or (at your option) any later version.
1749ab747fSPaolo Bonzini *
1849ab747fSPaolo Bonzini * This library is distributed in the hope that it will be useful,
1949ab747fSPaolo Bonzini * but WITHOUT ANY WARRANTY; without even the implied warranty of
2049ab747fSPaolo Bonzini * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2149ab747fSPaolo Bonzini * Lesser General Public License for more details.
2249ab747fSPaolo Bonzini *
2349ab747fSPaolo Bonzini * You should have received a copy of the GNU Lesser General Public
2449ab747fSPaolo Bonzini * License along with this library; if not, see <http://www.gnu.org/licenses/>.
2549ab747fSPaolo Bonzini */
2649ab747fSPaolo Bonzini
2749ab747fSPaolo Bonzini
28e8d40465SPeter Maydell #include "qemu/osdep.h"
29b7728c9fSAkihiko Odaki #include "hw/net/mii.h"
30edf5ca5dSMarkus Armbruster #include "hw/pci/pci_device.h"
31a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h"
32d6454270SMarkus Armbruster #include "migration/vmstate.h"
33a1d7e475SChristina Wang #include "net/eth.h"
3449ab747fSPaolo Bonzini #include "net/net.h"
3549ab747fSPaolo Bonzini #include "net/checksum.h"
3649ab747fSPaolo Bonzini #include "sysemu/sysemu.h"
3749ab747fSPaolo Bonzini #include "sysemu/dma.h"
3897410ddeSVincenzo Maffione #include "qemu/iov.h"
390b8fa32fSMarkus Armbruster #include "qemu/module.h"
4020302e71SMichael S. Tsirkin #include "qemu/range.h"
4149ab747fSPaolo Bonzini
42c9653b77SAkihiko Odaki #include "e1000_common.h"
43093454e2SDmitry Fleytman #include "e1000x_common.h"
441001cf45SJason Wang #include "trace.h"
45db1015e9SEduardo Habkost #include "qom/object.h"
4649ab747fSPaolo Bonzini
47b4053c64SJason Wang /* #define E1000_DEBUG */
4849ab747fSPaolo Bonzini
4949ab747fSPaolo Bonzini #ifdef E1000_DEBUG
5049ab747fSPaolo Bonzini enum {
5149ab747fSPaolo Bonzini DEBUG_GENERAL, DEBUG_IO, DEBUG_MMIO, DEBUG_INTERRUPT,
5249ab747fSPaolo Bonzini DEBUG_RX, DEBUG_TX, DEBUG_MDIC, DEBUG_EEPROM,
5349ab747fSPaolo Bonzini DEBUG_UNKNOWN, DEBUG_TXSUM, DEBUG_TXERR, DEBUG_RXERR,
5449ab747fSPaolo Bonzini DEBUG_RXFILTER, DEBUG_PHY, DEBUG_NOTYET,
5549ab747fSPaolo Bonzini };
5649ab747fSPaolo Bonzini #define DBGBIT(x) (1<<DEBUG_##x)
5749ab747fSPaolo Bonzini static int debugflags = DBGBIT(TXERR) | DBGBIT(GENERAL);
5849ab747fSPaolo Bonzini
5949ab747fSPaolo Bonzini #define DBGOUT(what, fmt, ...) do { \
6049ab747fSPaolo Bonzini if (debugflags & DBGBIT(what)) \
6149ab747fSPaolo Bonzini fprintf(stderr, "e1000: " fmt, ## __VA_ARGS__); \
6249ab747fSPaolo Bonzini } while (0)
6349ab747fSPaolo Bonzini #else
6449ab747fSPaolo Bonzini #define DBGOUT(what, fmt, ...) do {} while (0)
6549ab747fSPaolo Bonzini #endif
6649ab747fSPaolo Bonzini
6749ab747fSPaolo Bonzini #define IOPORT_SIZE 0x40
6849ab747fSPaolo Bonzini #define PNPMMIO_SIZE 0x20000
6949ab747fSPaolo Bonzini
702fe63579SAkihiko Odaki #define MAXIMUM_ETHERNET_HDR_LEN (ETH_HLEN + 4)
7197410ddeSVincenzo Maffione
7249ab747fSPaolo Bonzini /*
7349ab747fSPaolo Bonzini * HW models:
748597f2e1SGabriel L. Somlo * E1000_DEV_ID_82540EM works with Windows, Linux, and OS X <= 10.8
7549ab747fSPaolo Bonzini * E1000_DEV_ID_82544GC_COPPER appears to work; not well tested
768597f2e1SGabriel L. Somlo * E1000_DEV_ID_82545EM_COPPER works with Linux and OS X >= 10.6
7749ab747fSPaolo Bonzini * Others never tested
7849ab747fSPaolo Bonzini */
7949ab747fSPaolo Bonzini
80db1015e9SEduardo Habkost struct E1000State_st {
81b08340d5SAndreas Färber /*< private >*/
82b08340d5SAndreas Färber PCIDevice parent_obj;
83b08340d5SAndreas Färber /*< public >*/
84b08340d5SAndreas Färber
8549ab747fSPaolo Bonzini NICState *nic;
8649ab747fSPaolo Bonzini NICConf conf;
8749ab747fSPaolo Bonzini MemoryRegion mmio;
8849ab747fSPaolo Bonzini MemoryRegion io;
8949ab747fSPaolo Bonzini
9049ab747fSPaolo Bonzini uint32_t mac_reg[0x8000];
9149ab747fSPaolo Bonzini uint16_t phy_reg[0x20];
9249ab747fSPaolo Bonzini uint16_t eeprom_data[64];
9349ab747fSPaolo Bonzini
9449ab747fSPaolo Bonzini uint32_t rxbuf_size;
9549ab747fSPaolo Bonzini uint32_t rxbuf_min_shift;
9649ab747fSPaolo Bonzini struct e1000_tx {
9749ab747fSPaolo Bonzini unsigned char header[256];
9849ab747fSPaolo Bonzini unsigned char vlan_header[4];
9949ab747fSPaolo Bonzini /* Fields vlan and data must not be reordered or separated. */
10049ab747fSPaolo Bonzini unsigned char vlan[4];
10149ab747fSPaolo Bonzini unsigned char data[0x10000];
10249ab747fSPaolo Bonzini uint16_t size;
10349ab747fSPaolo Bonzini unsigned char vlan_needed;
1047d08c73eSEd Swierk via Qemu-devel unsigned char sum_needed;
1057d08c73eSEd Swierk via Qemu-devel bool cptse;
106093454e2SDmitry Fleytman e1000x_txd_props props;
107d62644b4SEd Swierk via Qemu-devel e1000x_txd_props tso_props;
10849ab747fSPaolo Bonzini uint16_t tso_frames;
10925ddb946SJon Maloy bool busy;
11049ab747fSPaolo Bonzini } tx;
11149ab747fSPaolo Bonzini
11249ab747fSPaolo Bonzini struct {
11320f3e863SLeonid Bloch uint32_t val_in; /* shifted in from guest driver */
11449ab747fSPaolo Bonzini uint16_t bitnum_in;
11549ab747fSPaolo Bonzini uint16_t bitnum_out;
11649ab747fSPaolo Bonzini uint16_t reading;
11749ab747fSPaolo Bonzini uint32_t old_eecd;
11849ab747fSPaolo Bonzini } eecd_state;
11949ab747fSPaolo Bonzini
12049ab747fSPaolo Bonzini QEMUTimer *autoneg_timer;
12149ab747fSPaolo Bonzini
122e9845f09SVincenzo Maffione QEMUTimer *mit_timer; /* Mitigation timer. */
123e9845f09SVincenzo Maffione bool mit_timer_on; /* Mitigation timer is running. */
124e9845f09SVincenzo Maffione bool mit_irq_level; /* Tracks interrupt pin level. */
125e9845f09SVincenzo Maffione uint32_t mit_ide; /* Tracks E1000_TXD_CMD_IDE bit. */
126e9845f09SVincenzo Maffione
127157628d0Syuchenlin QEMUTimer *flush_queue_timer;
128157628d0Syuchenlin
12949ab747fSPaolo Bonzini /* Compatibility flags for migration to/from qemu 1.3.0 and older */
1309e117734SLeonid Bloch #define E1000_FLAG_MAC_BIT 2
13146f2a9ecSDr. David Alan Gilbert #define E1000_FLAG_TSO_BIT 3
132a1d7e475SChristina Wang #define E1000_FLAG_VET_BIT 4
1339e117734SLeonid Bloch #define E1000_FLAG_MAC (1 << E1000_FLAG_MAC_BIT)
13446f2a9ecSDr. David Alan Gilbert #define E1000_FLAG_TSO (1 << E1000_FLAG_TSO_BIT)
135a1d7e475SChristina Wang #define E1000_FLAG_VET (1 << E1000_FLAG_VET_BIT)
136a1d7e475SChristina Wang
13749ab747fSPaolo Bonzini uint32_t compat_flags;
1383c4053c5SDr. David Alan Gilbert bool received_tx_tso;
139ff214d42SDr. David Alan Gilbert bool use_tso_for_migration;
14059354484SDr. David Alan Gilbert e1000x_txd_props mig_props;
141db1015e9SEduardo Habkost };
142db1015e9SEduardo Habkost typedef struct E1000State_st E1000State;
14349ab747fSPaolo Bonzini
144bc0f0674SLeonid Bloch #define chkflag(x) (s->compat_flags & E1000_FLAG_##x)
145bc0f0674SLeonid Bloch
146db1015e9SEduardo Habkost struct E1000BaseClass {
1478597f2e1SGabriel L. Somlo PCIDeviceClass parent_class;
1488597f2e1SGabriel L. Somlo uint16_t phy_id2;
149db1015e9SEduardo Habkost };
150db1015e9SEduardo Habkost typedef struct E1000BaseClass E1000BaseClass;
1518597f2e1SGabriel L. Somlo
1528597f2e1SGabriel L. Somlo #define TYPE_E1000_BASE "e1000-base"
153567a3c9eSPeter Crosthwaite
DECLARE_OBJ_CHECKERS(E1000State,E1000BaseClass,E1000,TYPE_E1000_BASE)1548110fa1dSEduardo Habkost DECLARE_OBJ_CHECKERS(E1000State, E1000BaseClass,
1558110fa1dSEduardo Habkost E1000, TYPE_E1000_BASE)
1568597f2e1SGabriel L. Somlo
157567a3c9eSPeter Crosthwaite
15849ab747fSPaolo Bonzini static void
15949ab747fSPaolo Bonzini e1000_link_up(E1000State *s)
16049ab747fSPaolo Bonzini {
161093454e2SDmitry Fleytman e1000x_update_regs_on_link_up(s->mac_reg, s->phy_reg);
162093454e2SDmitry Fleytman
163093454e2SDmitry Fleytman /* E1000_STATUS_LU is tested by e1000_can_receive() */
164093454e2SDmitry Fleytman qemu_flush_queued_packets(qemu_get_queue(s->nic));
165093454e2SDmitry Fleytman }
166093454e2SDmitry Fleytman
167093454e2SDmitry Fleytman static void
e1000_autoneg_done(E1000State * s)168093454e2SDmitry Fleytman e1000_autoneg_done(E1000State *s)
169093454e2SDmitry Fleytman {
170093454e2SDmitry Fleytman e1000x_update_regs_on_autoneg_done(s->mac_reg, s->phy_reg);
1715df6a185SStefan Hajnoczi
1725df6a185SStefan Hajnoczi /* E1000_STATUS_LU is tested by e1000_can_receive() */
1735df6a185SStefan Hajnoczi qemu_flush_queued_packets(qemu_get_queue(s->nic));
17449ab747fSPaolo Bonzini }
17549ab747fSPaolo Bonzini
1761195fed9SGabriel L. Somlo static bool
have_autoneg(E1000State * s)1771195fed9SGabriel L. Somlo have_autoneg(E1000State *s)
1781195fed9SGabriel L. Somlo {
179fa4ec9ffSPaolo Bonzini return (s->phy_reg[MII_BMCR] & MII_BMCR_AUTOEN);
1801195fed9SGabriel L. Somlo }
1811195fed9SGabriel L. Somlo
18249ab747fSPaolo Bonzini static void
set_phy_ctrl(E1000State * s,int index,uint16_t val)18349ab747fSPaolo Bonzini set_phy_ctrl(E1000State *s, int index, uint16_t val)
18449ab747fSPaolo Bonzini {
185b7728c9fSAkihiko Odaki /* bits 0-5 reserved; MII_BMCR_[ANRESTART,RESET] are self clearing */
186b7728c9fSAkihiko Odaki s->phy_reg[MII_BMCR] = val & ~(0x3f |
187b7728c9fSAkihiko Odaki MII_BMCR_RESET |
188b7728c9fSAkihiko Odaki MII_BMCR_ANRESTART);
1891195fed9SGabriel L. Somlo
19049ab747fSPaolo Bonzini /*
19149ab747fSPaolo Bonzini * QEMU 1.3 does not support link auto-negotiation emulation, so if we
19249ab747fSPaolo Bonzini * migrate during auto negotiation, after migration the link will be
19349ab747fSPaolo Bonzini * down.
19449ab747fSPaolo Bonzini */
195b7728c9fSAkihiko Odaki if (have_autoneg(s) && (val & MII_BMCR_ANRESTART)) {
196093454e2SDmitry Fleytman e1000x_restart_autoneg(s->mac_reg, s->phy_reg, s->autoneg_timer);
19749ab747fSPaolo Bonzini }
19849ab747fSPaolo Bonzini }
19949ab747fSPaolo Bonzini
20049ab747fSPaolo Bonzini static void (*phyreg_writeops[])(E1000State *, int, uint16_t) = {
201b7728c9fSAkihiko Odaki [MII_BMCR] = set_phy_ctrl,
20249ab747fSPaolo Bonzini };
20349ab747fSPaolo Bonzini
20449ab747fSPaolo Bonzini enum { NPHYWRITEOPS = ARRAY_SIZE(phyreg_writeops) };
20549ab747fSPaolo Bonzini
20649ab747fSPaolo Bonzini enum { PHY_R = 1, PHY_W = 2, PHY_RW = PHY_R | PHY_W };
20749ab747fSPaolo Bonzini static const char phy_regcap[0x20] = {
208b7728c9fSAkihiko Odaki [MII_BMSR] = PHY_R, [M88E1000_EXT_PHY_SPEC_CTRL] = PHY_RW,
209b7728c9fSAkihiko Odaki [MII_PHYID1] = PHY_R, [M88E1000_PHY_SPEC_CTRL] = PHY_RW,
210b7728c9fSAkihiko Odaki [MII_BMCR] = PHY_RW, [MII_CTRL1000] = PHY_RW,
211b7728c9fSAkihiko Odaki [MII_ANLPAR] = PHY_R, [MII_STAT1000] = PHY_R,
212b7728c9fSAkihiko Odaki [MII_ANAR] = PHY_RW, [M88E1000_RX_ERR_CNTR] = PHY_R,
213b7728c9fSAkihiko Odaki [MII_PHYID2] = PHY_R, [M88E1000_PHY_SPEC_STATUS] = PHY_R,
214b7728c9fSAkihiko Odaki [MII_ANER] = PHY_R,
21549ab747fSPaolo Bonzini };
21649ab747fSPaolo Bonzini
217b7728c9fSAkihiko Odaki /* MII_PHYID2 documented in 8254x_GBe_SDM.pdf, pp. 250 */
21849ab747fSPaolo Bonzini static const uint16_t phy_reg_init[] = {
219b7728c9fSAkihiko Odaki [MII_BMCR] = MII_BMCR_SPEED1000 |
220b7728c9fSAkihiko Odaki MII_BMCR_FD |
221b7728c9fSAkihiko Odaki MII_BMCR_AUTOEN,
2229616c290SGabriel L. Somlo
223b7728c9fSAkihiko Odaki [MII_BMSR] = MII_BMSR_EXTCAP |
224b7728c9fSAkihiko Odaki MII_BMSR_LINK_ST | /* link initially up */
225b7728c9fSAkihiko Odaki MII_BMSR_AUTONEG |
226b7728c9fSAkihiko Odaki /* MII_BMSR_AN_COMP: initially NOT completed */
227b7728c9fSAkihiko Odaki MII_BMSR_MFPS |
228b7728c9fSAkihiko Odaki MII_BMSR_EXTSTAT |
229b7728c9fSAkihiko Odaki MII_BMSR_10T_HD |
230b7728c9fSAkihiko Odaki MII_BMSR_10T_FD |
231b7728c9fSAkihiko Odaki MII_BMSR_100TX_HD |
232b7728c9fSAkihiko Odaki MII_BMSR_100TX_FD,
2339616c290SGabriel L. Somlo
234b7728c9fSAkihiko Odaki [MII_PHYID1] = 0x141,
235b7728c9fSAkihiko Odaki /* [MII_PHYID2] configured per DevId, from e1000_reset() */
2362fe63579SAkihiko Odaki [MII_ANAR] = MII_ANAR_CSMACD | MII_ANAR_10 |
2372fe63579SAkihiko Odaki MII_ANAR_10FD | MII_ANAR_TX |
2382fe63579SAkihiko Odaki MII_ANAR_TXFD | MII_ANAR_PAUSE |
2392fe63579SAkihiko Odaki MII_ANAR_PAUSE_ASYM,
2402fe63579SAkihiko Odaki [MII_ANLPAR] = MII_ANLPAR_10 | MII_ANLPAR_10FD |
2412fe63579SAkihiko Odaki MII_ANLPAR_TX | MII_ANLPAR_TXFD,
2422fe63579SAkihiko Odaki [MII_CTRL1000] = MII_CTRL1000_FULL | MII_CTRL1000_PORT |
2432fe63579SAkihiko Odaki MII_CTRL1000_MASTER,
2442fe63579SAkihiko Odaki [MII_STAT1000] = MII_STAT1000_HALF | MII_STAT1000_FULL |
2452fe63579SAkihiko Odaki MII_STAT1000_ROK | MII_STAT1000_LOK,
2469616c290SGabriel L. Somlo [M88E1000_PHY_SPEC_CTRL] = 0x360,
24749ab747fSPaolo Bonzini [M88E1000_PHY_SPEC_STATUS] = 0xac00,
2489616c290SGabriel L. Somlo [M88E1000_EXT_PHY_SPEC_CTRL] = 0x0d60,
24949ab747fSPaolo Bonzini };
25049ab747fSPaolo Bonzini
25149ab747fSPaolo Bonzini static const uint32_t mac_reg_init[] = {
25249ab747fSPaolo Bonzini [PBA] = 0x00100030,
25349ab747fSPaolo Bonzini [LEDCTL] = 0x602,
25449ab747fSPaolo Bonzini [CTRL] = E1000_CTRL_SWDPIN2 | E1000_CTRL_SWDPIN0 |
25549ab747fSPaolo Bonzini E1000_CTRL_SPD_1000 | E1000_CTRL_SLU,
25649ab747fSPaolo Bonzini [STATUS] = 0x80000000 | E1000_STATUS_GIO_MASTER_ENABLE |
25749ab747fSPaolo Bonzini E1000_STATUS_ASDV | E1000_STATUS_MTXCKOK |
25849ab747fSPaolo Bonzini E1000_STATUS_SPEED_1000 | E1000_STATUS_FD |
25949ab747fSPaolo Bonzini E1000_STATUS_LU,
26049ab747fSPaolo Bonzini [MANC] = E1000_MANC_EN_MNG2HOST | E1000_MANC_RCV_TCO_EN |
26149ab747fSPaolo Bonzini E1000_MANC_ARP_EN | E1000_MANC_0298_EN |
26249ab747fSPaolo Bonzini E1000_MANC_RMCP_EN,
26349ab747fSPaolo Bonzini };
26449ab747fSPaolo Bonzini
265e9845f09SVincenzo Maffione /* Helper function, *curr == 0 means the value is not set */
266e9845f09SVincenzo Maffione static inline void
mit_update_delay(uint32_t * curr,uint32_t value)267e9845f09SVincenzo Maffione mit_update_delay(uint32_t *curr, uint32_t value)
268e9845f09SVincenzo Maffione {
269e9845f09SVincenzo Maffione if (value && (*curr == 0 || value < *curr)) {
270e9845f09SVincenzo Maffione *curr = value;
271e9845f09SVincenzo Maffione }
272e9845f09SVincenzo Maffione }
273e9845f09SVincenzo Maffione
27449ab747fSPaolo Bonzini static void
set_interrupt_cause(E1000State * s,int index,uint32_t val)27549ab747fSPaolo Bonzini set_interrupt_cause(E1000State *s, int index, uint32_t val)
27649ab747fSPaolo Bonzini {
277b08340d5SAndreas Färber PCIDevice *d = PCI_DEVICE(s);
278e9845f09SVincenzo Maffione uint32_t pending_ints;
279e9845f09SVincenzo Maffione uint32_t mit_delay;
280b08340d5SAndreas Färber
28149ab747fSPaolo Bonzini s->mac_reg[ICR] = val;
28249ab747fSPaolo Bonzini
28349ab747fSPaolo Bonzini /*
28449ab747fSPaolo Bonzini * Make sure ICR and ICS registers have the same value.
28549ab747fSPaolo Bonzini * The spec says that the ICS register is write-only. However in practice,
28649ab747fSPaolo Bonzini * on real hardware ICS is readable, and for reads it has the same value as
28749ab747fSPaolo Bonzini * ICR (except that ICS does not have the clear on read behaviour of ICR).
28849ab747fSPaolo Bonzini *
28949ab747fSPaolo Bonzini * The VxWorks PRO/1000 driver uses this behaviour.
29049ab747fSPaolo Bonzini */
29149ab747fSPaolo Bonzini s->mac_reg[ICS] = val;
29249ab747fSPaolo Bonzini
293e9845f09SVincenzo Maffione pending_ints = (s->mac_reg[IMS] & s->mac_reg[ICR]);
294e9845f09SVincenzo Maffione if (!s->mit_irq_level && pending_ints) {
295e9845f09SVincenzo Maffione /*
296e9845f09SVincenzo Maffione * Here we detect a potential raising edge. We postpone raising the
297e9845f09SVincenzo Maffione * interrupt line if we are inside the mitigation delay window
298e9845f09SVincenzo Maffione * (s->mit_timer_on == 1).
299e9845f09SVincenzo Maffione * We provide a partial implementation of interrupt mitigation,
300e9845f09SVincenzo Maffione * emulating only RADV, TADV and ITR (lower 16 bits, 1024ns units for
301e9845f09SVincenzo Maffione * RADV and TADV, 256ns units for ITR). RDTR is only used to enable
302e9845f09SVincenzo Maffione * RADV; relative timers based on TIDV and RDTR are not implemented.
303e9845f09SVincenzo Maffione */
304e9845f09SVincenzo Maffione if (s->mit_timer_on) {
305e9845f09SVincenzo Maffione return;
306e9845f09SVincenzo Maffione }
307fa4ec9ffSPaolo Bonzini
308e9845f09SVincenzo Maffione /* Compute the next mitigation delay according to pending
309e9845f09SVincenzo Maffione * interrupts and the current values of RADV (provided
310e9845f09SVincenzo Maffione * RDTR!=0), TADV and ITR.
311e9845f09SVincenzo Maffione * Then rearm the timer.
312e9845f09SVincenzo Maffione */
313e9845f09SVincenzo Maffione mit_delay = 0;
314e9845f09SVincenzo Maffione if (s->mit_ide &&
315e9845f09SVincenzo Maffione (pending_ints & (E1000_ICR_TXQE | E1000_ICR_TXDW))) {
316e9845f09SVincenzo Maffione mit_update_delay(&mit_delay, s->mac_reg[TADV] * 4);
317e9845f09SVincenzo Maffione }
318e9845f09SVincenzo Maffione if (s->mac_reg[RDTR] && (pending_ints & E1000_ICS_RXT0)) {
319e9845f09SVincenzo Maffione mit_update_delay(&mit_delay, s->mac_reg[RADV] * 4);
320e9845f09SVincenzo Maffione }
321e9845f09SVincenzo Maffione mit_update_delay(&mit_delay, s->mac_reg[ITR]);
322e9845f09SVincenzo Maffione
32374004e8cSSameeh Jubran /*
32474004e8cSSameeh Jubran * According to e1000 SPEC, the Ethernet controller guarantees
32574004e8cSSameeh Jubran * a maximum observable interrupt rate of 7813 interrupts/sec.
32674004e8cSSameeh Jubran * Thus if mit_delay < 500 then the delay should be set to the
32774004e8cSSameeh Jubran * minimum delay possible which is 500.
32874004e8cSSameeh Jubran */
32974004e8cSSameeh Jubran mit_delay = (mit_delay < 500) ? 500 : mit_delay;
33074004e8cSSameeh Jubran
331e9845f09SVincenzo Maffione s->mit_timer_on = 1;
332e9845f09SVincenzo Maffione timer_mod(s->mit_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
333e9845f09SVincenzo Maffione mit_delay * 256);
334e9845f09SVincenzo Maffione s->mit_ide = 0;
335e9845f09SVincenzo Maffione }
336e9845f09SVincenzo Maffione
337e9845f09SVincenzo Maffione s->mit_irq_level = (pending_ints != 0);
3389e64f8a3SMarcel Apfelbaum pci_set_irq(d, s->mit_irq_level);
339e9845f09SVincenzo Maffione }
340e9845f09SVincenzo Maffione
341e9845f09SVincenzo Maffione static void
e1000_mit_timer(void * opaque)342e9845f09SVincenzo Maffione e1000_mit_timer(void *opaque)
343e9845f09SVincenzo Maffione {
344e9845f09SVincenzo Maffione E1000State *s = opaque;
345e9845f09SVincenzo Maffione
346e9845f09SVincenzo Maffione s->mit_timer_on = 0;
347e9845f09SVincenzo Maffione /* Call set_interrupt_cause to update the irq level (if necessary). */
348e9845f09SVincenzo Maffione set_interrupt_cause(s, 0, s->mac_reg[ICR]);
34949ab747fSPaolo Bonzini }
35049ab747fSPaolo Bonzini
35149ab747fSPaolo Bonzini static void
set_ics(E1000State * s,int index,uint32_t val)35249ab747fSPaolo Bonzini set_ics(E1000State *s, int index, uint32_t val)
35349ab747fSPaolo Bonzini {
35449ab747fSPaolo Bonzini DBGOUT(INTERRUPT, "set_ics %x, ICR %x, IMR %x\n", val, s->mac_reg[ICR],
35549ab747fSPaolo Bonzini s->mac_reg[IMS]);
35649ab747fSPaolo Bonzini set_interrupt_cause(s, 0, val | s->mac_reg[ICR]);
35749ab747fSPaolo Bonzini }
35849ab747fSPaolo Bonzini
359d52aec95SGabriel L. Somlo static void
e1000_autoneg_timer(void * opaque)360d52aec95SGabriel L. Somlo e1000_autoneg_timer(void *opaque)
361d52aec95SGabriel L. Somlo {
362d52aec95SGabriel L. Somlo E1000State *s = opaque;
363d52aec95SGabriel L. Somlo if (!qemu_get_queue(s->nic)->link_down) {
364093454e2SDmitry Fleytman e1000_autoneg_done(s);
365d52aec95SGabriel L. Somlo set_ics(s, 0, E1000_ICS_LSC); /* signal link status change to guest */
366d52aec95SGabriel L. Somlo }
367d52aec95SGabriel L. Somlo }
368d52aec95SGabriel L. Somlo
e1000_vet_init_need(void * opaque)369a1d7e475SChristina Wang static bool e1000_vet_init_need(void *opaque)
370a1d7e475SChristina Wang {
371a1d7e475SChristina Wang E1000State *s = opaque;
372a1d7e475SChristina Wang
373a1d7e475SChristina Wang return chkflag(VET);
374a1d7e475SChristina Wang }
375a1d7e475SChristina Wang
e1000_reset_hold(Object * obj,ResetType type)376*ad80e367SPeter Maydell static void e1000_reset_hold(Object *obj, ResetType type)
37749ab747fSPaolo Bonzini {
3789d465053SAkihiko Odaki E1000State *d = E1000(obj);
379c51325d8SEduardo Habkost E1000BaseClass *edc = E1000_GET_CLASS(d);
38049ab747fSPaolo Bonzini uint8_t *macaddr = d->conf.macaddr.a;
38149ab747fSPaolo Bonzini
382bc72ad67SAlex Bligh timer_del(d->autoneg_timer);
383e9845f09SVincenzo Maffione timer_del(d->mit_timer);
384157628d0Syuchenlin timer_del(d->flush_queue_timer);
385e9845f09SVincenzo Maffione d->mit_timer_on = 0;
386e9845f09SVincenzo Maffione d->mit_irq_level = 0;
387e9845f09SVincenzo Maffione d->mit_ide = 0;
38849ab747fSPaolo Bonzini memset(d->phy_reg, 0, sizeof d->phy_reg);
3899eb525eeSAkihiko Odaki memcpy(d->phy_reg, phy_reg_init, sizeof phy_reg_init);
390b7728c9fSAkihiko Odaki d->phy_reg[MII_PHYID2] = edc->phy_id2;
39149ab747fSPaolo Bonzini memset(d->mac_reg, 0, sizeof d->mac_reg);
3929eb525eeSAkihiko Odaki memcpy(d->mac_reg, mac_reg_init, sizeof mac_reg_init);
39349ab747fSPaolo Bonzini d->rxbuf_min_shift = 1;
39449ab747fSPaolo Bonzini memset(&d->tx, 0, sizeof d->tx);
39549ab747fSPaolo Bonzini
39649ab747fSPaolo Bonzini if (qemu_get_queue(d->nic)->link_down) {
397093454e2SDmitry Fleytman e1000x_update_regs_on_link_down(d->mac_reg, d->phy_reg);
39849ab747fSPaolo Bonzini }
39949ab747fSPaolo Bonzini
400093454e2SDmitry Fleytman e1000x_reset_mac_addr(d->nic, d->mac_reg, macaddr);
401a1d7e475SChristina Wang
402a1d7e475SChristina Wang if (e1000_vet_init_need(d)) {
403a1d7e475SChristina Wang d->mac_reg[VET] = ETH_P_VLAN;
404a1d7e475SChristina Wang }
40549ab747fSPaolo Bonzini }
40649ab747fSPaolo Bonzini
40749ab747fSPaolo Bonzini static void
set_ctrl(E1000State * s,int index,uint32_t val)40849ab747fSPaolo Bonzini set_ctrl(E1000State *s, int index, uint32_t val)
40949ab747fSPaolo Bonzini {
41049ab747fSPaolo Bonzini /* RST is self clearing */
41149ab747fSPaolo Bonzini s->mac_reg[CTRL] = val & ~E1000_CTRL_RST;
41249ab747fSPaolo Bonzini }
41349ab747fSPaolo Bonzini
41449ab747fSPaolo Bonzini static void
e1000_flush_queue_timer(void * opaque)415157628d0Syuchenlin e1000_flush_queue_timer(void *opaque)
416157628d0Syuchenlin {
417157628d0Syuchenlin E1000State *s = opaque;
418157628d0Syuchenlin
419157628d0Syuchenlin qemu_flush_queued_packets(qemu_get_queue(s->nic));
420157628d0Syuchenlin }
421157628d0Syuchenlin
422157628d0Syuchenlin static void
set_rx_control(E1000State * s,int index,uint32_t val)42349ab747fSPaolo Bonzini set_rx_control(E1000State *s, int index, uint32_t val)
42449ab747fSPaolo Bonzini {
42549ab747fSPaolo Bonzini s->mac_reg[RCTL] = val;
426093454e2SDmitry Fleytman s->rxbuf_size = e1000x_rxbufsize(val);
42749ab747fSPaolo Bonzini s->rxbuf_min_shift = ((val / E1000_RCTL_RDMTS_QUAT) & 3) + 1;
42849ab747fSPaolo Bonzini DBGOUT(RX, "RCTL: %d, mac_reg[RCTL] = 0x%x\n", s->mac_reg[RDT],
42949ab747fSPaolo Bonzini s->mac_reg[RCTL]);
430157628d0Syuchenlin timer_mod(s->flush_queue_timer,
431157628d0Syuchenlin qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 1000);
43249ab747fSPaolo Bonzini }
43349ab747fSPaolo Bonzini
43449ab747fSPaolo Bonzini static void
set_mdic(E1000State * s,int index,uint32_t val)43549ab747fSPaolo Bonzini set_mdic(E1000State *s, int index, uint32_t val)
43649ab747fSPaolo Bonzini {
43749ab747fSPaolo Bonzini uint32_t data = val & E1000_MDIC_DATA_MASK;
43849ab747fSPaolo Bonzini uint32_t addr = ((val & E1000_MDIC_REG_MASK) >> E1000_MDIC_REG_SHIFT);
43949ab747fSPaolo Bonzini
44049ab747fSPaolo Bonzini if ((val & E1000_MDIC_PHY_MASK) >> E1000_MDIC_PHY_SHIFT != 1) // phy #
44149ab747fSPaolo Bonzini val = s->mac_reg[MDIC] | E1000_MDIC_ERROR;
44249ab747fSPaolo Bonzini else if (val & E1000_MDIC_OP_READ) {
44349ab747fSPaolo Bonzini DBGOUT(MDIC, "MDIC read reg 0x%x\n", addr);
44449ab747fSPaolo Bonzini if (!(phy_regcap[addr] & PHY_R)) {
44549ab747fSPaolo Bonzini DBGOUT(MDIC, "MDIC read reg %x unhandled\n", addr);
44649ab747fSPaolo Bonzini val |= E1000_MDIC_ERROR;
44749ab747fSPaolo Bonzini } else
44849ab747fSPaolo Bonzini val = (val ^ data) | s->phy_reg[addr];
44949ab747fSPaolo Bonzini } else if (val & E1000_MDIC_OP_WRITE) {
45049ab747fSPaolo Bonzini DBGOUT(MDIC, "MDIC write reg 0x%x, value 0x%x\n", addr, data);
45149ab747fSPaolo Bonzini if (!(phy_regcap[addr] & PHY_W)) {
45249ab747fSPaolo Bonzini DBGOUT(MDIC, "MDIC write reg %x unhandled\n", addr);
45349ab747fSPaolo Bonzini val |= E1000_MDIC_ERROR;
45449ab747fSPaolo Bonzini } else {
45549ab747fSPaolo Bonzini if (addr < NPHYWRITEOPS && phyreg_writeops[addr]) {
45649ab747fSPaolo Bonzini phyreg_writeops[addr](s, index, data);
4571195fed9SGabriel L. Somlo } else {
45849ab747fSPaolo Bonzini s->phy_reg[addr] = data;
45949ab747fSPaolo Bonzini }
46049ab747fSPaolo Bonzini }
4611195fed9SGabriel L. Somlo }
46249ab747fSPaolo Bonzini s->mac_reg[MDIC] = val | E1000_MDIC_READY;
46349ab747fSPaolo Bonzini
46449ab747fSPaolo Bonzini if (val & E1000_MDIC_INT_EN) {
46549ab747fSPaolo Bonzini set_ics(s, 0, E1000_ICR_MDAC);
46649ab747fSPaolo Bonzini }
46749ab747fSPaolo Bonzini }
46849ab747fSPaolo Bonzini
46949ab747fSPaolo Bonzini static uint32_t
get_eecd(E1000State * s,int index)47049ab747fSPaolo Bonzini get_eecd(E1000State *s, int index)
47149ab747fSPaolo Bonzini {
47249ab747fSPaolo Bonzini uint32_t ret = E1000_EECD_PRES|E1000_EECD_GNT | s->eecd_state.old_eecd;
47349ab747fSPaolo Bonzini
47449ab747fSPaolo Bonzini DBGOUT(EEPROM, "reading eeprom bit %d (reading %d)\n",
47549ab747fSPaolo Bonzini s->eecd_state.bitnum_out, s->eecd_state.reading);
47649ab747fSPaolo Bonzini if (!s->eecd_state.reading ||
47749ab747fSPaolo Bonzini ((s->eeprom_data[(s->eecd_state.bitnum_out >> 4) & 0x3f] >>
47849ab747fSPaolo Bonzini ((s->eecd_state.bitnum_out & 0xf) ^ 0xf))) & 1)
47949ab747fSPaolo Bonzini ret |= E1000_EECD_DO;
48049ab747fSPaolo Bonzini return ret;
48149ab747fSPaolo Bonzini }
48249ab747fSPaolo Bonzini
48349ab747fSPaolo Bonzini static void
set_eecd(E1000State * s,int index,uint32_t val)48449ab747fSPaolo Bonzini set_eecd(E1000State *s, int index, uint32_t val)
48549ab747fSPaolo Bonzini {
48649ab747fSPaolo Bonzini uint32_t oldval = s->eecd_state.old_eecd;
48749ab747fSPaolo Bonzini
48849ab747fSPaolo Bonzini s->eecd_state.old_eecd = val & (E1000_EECD_SK | E1000_EECD_CS |
48949ab747fSPaolo Bonzini E1000_EECD_DI|E1000_EECD_FWE_MASK|E1000_EECD_REQ);
49020f3e863SLeonid Bloch if (!(E1000_EECD_CS & val)) { /* CS inactive; nothing to do */
49149ab747fSPaolo Bonzini return;
49220f3e863SLeonid Bloch }
49320f3e863SLeonid Bloch if (E1000_EECD_CS & (val ^ oldval)) { /* CS rise edge; reset state */
49449ab747fSPaolo Bonzini s->eecd_state.val_in = 0;
49549ab747fSPaolo Bonzini s->eecd_state.bitnum_in = 0;
49649ab747fSPaolo Bonzini s->eecd_state.bitnum_out = 0;
49749ab747fSPaolo Bonzini s->eecd_state.reading = 0;
49849ab747fSPaolo Bonzini }
49920f3e863SLeonid Bloch if (!(E1000_EECD_SK & (val ^ oldval))) { /* no clock edge */
50049ab747fSPaolo Bonzini return;
50120f3e863SLeonid Bloch }
50220f3e863SLeonid Bloch if (!(E1000_EECD_SK & val)) { /* falling edge */
50349ab747fSPaolo Bonzini s->eecd_state.bitnum_out++;
50449ab747fSPaolo Bonzini return;
50549ab747fSPaolo Bonzini }
50649ab747fSPaolo Bonzini s->eecd_state.val_in <<= 1;
50749ab747fSPaolo Bonzini if (val & E1000_EECD_DI)
50849ab747fSPaolo Bonzini s->eecd_state.val_in |= 1;
50949ab747fSPaolo Bonzini if (++s->eecd_state.bitnum_in == 9 && !s->eecd_state.reading) {
51049ab747fSPaolo Bonzini s->eecd_state.bitnum_out = ((s->eecd_state.val_in & 0x3f)<<4)-1;
51149ab747fSPaolo Bonzini s->eecd_state.reading = (((s->eecd_state.val_in >> 6) & 7) ==
51249ab747fSPaolo Bonzini EEPROM_READ_OPCODE_MICROWIRE);
51349ab747fSPaolo Bonzini }
51449ab747fSPaolo Bonzini DBGOUT(EEPROM, "eeprom bitnum in %d out %d, reading %d\n",
51549ab747fSPaolo Bonzini s->eecd_state.bitnum_in, s->eecd_state.bitnum_out,
51649ab747fSPaolo Bonzini s->eecd_state.reading);
51749ab747fSPaolo Bonzini }
51849ab747fSPaolo Bonzini
51949ab747fSPaolo Bonzini static uint32_t
flash_eerd_read(E1000State * s,int x)52049ab747fSPaolo Bonzini flash_eerd_read(E1000State *s, int x)
52149ab747fSPaolo Bonzini {
52249ab747fSPaolo Bonzini unsigned int index, r = s->mac_reg[EERD] & ~E1000_EEPROM_RW_REG_START;
52349ab747fSPaolo Bonzini
52449ab747fSPaolo Bonzini if ((s->mac_reg[EERD] & E1000_EEPROM_RW_REG_START) == 0)
52549ab747fSPaolo Bonzini return (s->mac_reg[EERD]);
52649ab747fSPaolo Bonzini
52749ab747fSPaolo Bonzini if ((index = r >> E1000_EEPROM_RW_ADDR_SHIFT) > EEPROM_CHECKSUM_REG)
52849ab747fSPaolo Bonzini return (E1000_EEPROM_RW_REG_DONE | r);
52949ab747fSPaolo Bonzini
53049ab747fSPaolo Bonzini return ((s->eeprom_data[index] << E1000_EEPROM_RW_REG_DATA) |
53149ab747fSPaolo Bonzini E1000_EEPROM_RW_REG_DONE | r);
53249ab747fSPaolo Bonzini }
53349ab747fSPaolo Bonzini
53449ab747fSPaolo Bonzini static void
putsum(uint8_t * data,uint32_t n,uint32_t sloc,uint32_t css,uint32_t cse)53549ab747fSPaolo Bonzini putsum(uint8_t *data, uint32_t n, uint32_t sloc, uint32_t css, uint32_t cse)
53649ab747fSPaolo Bonzini {
53749ab747fSPaolo Bonzini uint32_t sum;
53849ab747fSPaolo Bonzini
53949ab747fSPaolo Bonzini if (cse && cse < n)
54049ab747fSPaolo Bonzini n = cse + 1;
54149ab747fSPaolo Bonzini if (sloc < n-1) {
54249ab747fSPaolo Bonzini sum = net_checksum_add(n-css, data+css);
5430dacea92SEd Swierk stw_be_p(data + sloc, net_checksum_finish_nozero(sum));
54449ab747fSPaolo Bonzini }
54549ab747fSPaolo Bonzini }
54649ab747fSPaolo Bonzini
5471f67f92cSLeonid Bloch static inline void
inc_tx_bcast_or_mcast_count(E1000State * s,const unsigned char * arr)5483b274301SLeonid Bloch inc_tx_bcast_or_mcast_count(E1000State *s, const unsigned char *arr)
5493b274301SLeonid Bloch {
5502fe63579SAkihiko Odaki if (is_broadcast_ether_addr(arr)) {
551093454e2SDmitry Fleytman e1000x_inc_reg_if_not_full(s->mac_reg, BPTC);
5522fe63579SAkihiko Odaki } else if (is_multicast_ether_addr(arr)) {
553093454e2SDmitry Fleytman e1000x_inc_reg_if_not_full(s->mac_reg, MPTC);
5543b274301SLeonid Bloch }
5553b274301SLeonid Bloch }
5563b274301SLeonid Bloch
55745e93764SLeonid Bloch static void
e1000_send_packet(E1000State * s,const uint8_t * buf,int size)55849ab747fSPaolo Bonzini e1000_send_packet(E1000State *s, const uint8_t *buf, int size)
55949ab747fSPaolo Bonzini {
5603b274301SLeonid Bloch static const int PTCregs[6] = { PTC64, PTC127, PTC255, PTC511,
5613b274301SLeonid Bloch PTC1023, PTC1522 };
5623b274301SLeonid Bloch
56349ab747fSPaolo Bonzini NetClientState *nc = qemu_get_queue(s->nic);
564b7728c9fSAkihiko Odaki if (s->phy_reg[MII_BMCR] & MII_BMCR_LOOPBACK) {
5651caff034SJason Wang qemu_receive_packet(nc, buf, size);
56649ab747fSPaolo Bonzini } else {
56749ab747fSPaolo Bonzini qemu_send_packet(nc, buf, size);
56849ab747fSPaolo Bonzini }
5693b274301SLeonid Bloch inc_tx_bcast_or_mcast_count(s, buf);
570c50b1524SAkihiko Odaki e1000x_increase_size_stats(s->mac_reg, PTCregs, size + 4);
57149ab747fSPaolo Bonzini }
57249ab747fSPaolo Bonzini
57349ab747fSPaolo Bonzini static void
xmit_seg(E1000State * s)57449ab747fSPaolo Bonzini xmit_seg(E1000State *s)
57549ab747fSPaolo Bonzini {
57614e60aaeSPeter Maydell uint16_t len;
57745e93764SLeonid Bloch unsigned int frames = s->tx.tso_frames, css, sofar;
57849ab747fSPaolo Bonzini struct e1000_tx *tp = &s->tx;
579d62644b4SEd Swierk via Qemu-devel struct e1000x_txd_props *props = tp->cptse ? &tp->tso_props : &tp->props;
58049ab747fSPaolo Bonzini
581d62644b4SEd Swierk via Qemu-devel if (tp->cptse) {
582d62644b4SEd Swierk via Qemu-devel css = props->ipcss;
58349ab747fSPaolo Bonzini DBGOUT(TXSUM, "frames %d size %d ipcss %d\n",
58449ab747fSPaolo Bonzini frames, tp->size, css);
585d62644b4SEd Swierk via Qemu-devel if (props->ip) { /* IPv4 */
586d8ee2591SPeter Maydell stw_be_p(tp->data+css+2, tp->size - css);
587d8ee2591SPeter Maydell stw_be_p(tp->data+css+4,
58814e60aaeSPeter Maydell lduw_be_p(tp->data + css + 4) + frames);
58920f3e863SLeonid Bloch } else { /* IPv6 */
590d8ee2591SPeter Maydell stw_be_p(tp->data+css+4, tp->size - css);
59120f3e863SLeonid Bloch }
592d62644b4SEd Swierk via Qemu-devel css = props->tucss;
59349ab747fSPaolo Bonzini len = tp->size - css;
594d62644b4SEd Swierk via Qemu-devel DBGOUT(TXSUM, "tcp %d tucss %d len %d\n", props->tcp, css, len);
595d62644b4SEd Swierk via Qemu-devel if (props->tcp) {
596d62644b4SEd Swierk via Qemu-devel sofar = frames * props->mss;
5976bd194abSPeter Maydell stl_be_p(tp->data+css+4, ldl_be_p(tp->data+css+4)+sofar); /* seq */
598d62644b4SEd Swierk via Qemu-devel if (props->paylen - sofar > props->mss) {
59920f3e863SLeonid Bloch tp->data[css + 13] &= ~9; /* PSH, FIN */
6003b274301SLeonid Bloch } else if (frames) {
601093454e2SDmitry Fleytman e1000x_inc_reg_if_not_full(s->mac_reg, TSCTC);
6023b274301SLeonid Bloch }
603d62644b4SEd Swierk via Qemu-devel } else { /* UDP */
604d8ee2591SPeter Maydell stw_be_p(tp->data+css+4, len);
605d62644b4SEd Swierk via Qemu-devel }
6067d08c73eSEd Swierk via Qemu-devel if (tp->sum_needed & E1000_TXD_POPTS_TXSM) {
60749ab747fSPaolo Bonzini unsigned int phsum;
60849ab747fSPaolo Bonzini // add pseudo-header length before checksum calculation
609d62644b4SEd Swierk via Qemu-devel void *sp = tp->data + props->tucso;
61014e60aaeSPeter Maydell
61114e60aaeSPeter Maydell phsum = lduw_be_p(sp) + len;
61249ab747fSPaolo Bonzini phsum = (phsum >> 16) + (phsum & 0xffff);
613d8ee2591SPeter Maydell stw_be_p(sp, phsum);
61449ab747fSPaolo Bonzini }
61549ab747fSPaolo Bonzini tp->tso_frames++;
61649ab747fSPaolo Bonzini }
61749ab747fSPaolo Bonzini
6187d08c73eSEd Swierk via Qemu-devel if (tp->sum_needed & E1000_TXD_POPTS_TXSM) {
619d62644b4SEd Swierk via Qemu-devel putsum(tp->data, tp->size, props->tucso, props->tucss, props->tucse);
620093454e2SDmitry Fleytman }
6217d08c73eSEd Swierk via Qemu-devel if (tp->sum_needed & E1000_TXD_POPTS_IXSM) {
622d62644b4SEd Swierk via Qemu-devel putsum(tp->data, tp->size, props->ipcso, props->ipcss, props->ipcse);
623093454e2SDmitry Fleytman }
62449ab747fSPaolo Bonzini if (tp->vlan_needed) {
62549ab747fSPaolo Bonzini memmove(tp->vlan, tp->data, 4);
62649ab747fSPaolo Bonzini memmove(tp->data, tp->data + 4, 8);
62749ab747fSPaolo Bonzini memcpy(tp->data + 8, tp->vlan_header, 4);
62849ab747fSPaolo Bonzini e1000_send_packet(s, tp->vlan, tp->size + 4);
62920f3e863SLeonid Bloch } else {
63049ab747fSPaolo Bonzini e1000_send_packet(s, tp->data, tp->size);
63120f3e863SLeonid Bloch }
63220f3e863SLeonid Bloch
633093454e2SDmitry Fleytman e1000x_inc_reg_if_not_full(s->mac_reg, TPT);
634c50b1524SAkihiko Odaki e1000x_grow_8reg_if_not_full(s->mac_reg, TOTL, s->tx.size + 4);
6358d689f6aStimothee.cocault@gmail.com e1000x_inc_reg_if_not_full(s->mac_reg, GPTC);
6368d689f6aStimothee.cocault@gmail.com e1000x_grow_8reg_if_not_full(s->mac_reg, GOTCL, s->tx.size + 4);
63749ab747fSPaolo Bonzini }
63849ab747fSPaolo Bonzini
63949ab747fSPaolo Bonzini static void
process_tx_desc(E1000State * s,struct e1000_tx_desc * dp)64049ab747fSPaolo Bonzini process_tx_desc(E1000State *s, struct e1000_tx_desc *dp)
64149ab747fSPaolo Bonzini {
642b08340d5SAndreas Färber PCIDevice *d = PCI_DEVICE(s);
64349ab747fSPaolo Bonzini uint32_t txd_lower = le32_to_cpu(dp->lower.data);
64449ab747fSPaolo Bonzini uint32_t dtype = txd_lower & (E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D);
645093454e2SDmitry Fleytman unsigned int split_size = txd_lower & 0xffff, bytes, sz;
646a0ae17a6SAndrew Jones unsigned int msh = 0xfffff;
64749ab747fSPaolo Bonzini uint64_t addr;
64849ab747fSPaolo Bonzini struct e1000_context_desc *xp = (struct e1000_context_desc *)dp;
64949ab747fSPaolo Bonzini struct e1000_tx *tp = &s->tx;
65049ab747fSPaolo Bonzini
651e9845f09SVincenzo Maffione s->mit_ide |= (txd_lower & E1000_TXD_CMD_IDE);
65220f3e863SLeonid Bloch if (dtype == E1000_TXD_CMD_DEXT) { /* context descriptor */
653d62644b4SEd Swierk via Qemu-devel if (le32_to_cpu(xp->cmd_and_length) & E1000_TXD_CMD_TSE) {
654d62644b4SEd Swierk via Qemu-devel e1000x_read_tx_ctx_descr(xp, &tp->tso_props);
655ff214d42SDr. David Alan Gilbert s->use_tso_for_migration = 1;
65649ab747fSPaolo Bonzini tp->tso_frames = 0;
657d62644b4SEd Swierk via Qemu-devel } else {
658d62644b4SEd Swierk via Qemu-devel e1000x_read_tx_ctx_descr(xp, &tp->props);
659ff214d42SDr. David Alan Gilbert s->use_tso_for_migration = 0;
66049ab747fSPaolo Bonzini }
66149ab747fSPaolo Bonzini return;
66249ab747fSPaolo Bonzini } else if (dtype == (E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D)) {
66349ab747fSPaolo Bonzini // data descriptor
66449ab747fSPaolo Bonzini if (tp->size == 0) {
6657d08c73eSEd Swierk via Qemu-devel tp->sum_needed = le32_to_cpu(dp->upper.data) >> 8;
66649ab747fSPaolo Bonzini }
6677d08c73eSEd Swierk via Qemu-devel tp->cptse = (txd_lower & E1000_TXD_CMD_TSE) ? 1 : 0;
66849ab747fSPaolo Bonzini } else {
66949ab747fSPaolo Bonzini // legacy descriptor
6707d08c73eSEd Swierk via Qemu-devel tp->cptse = 0;
67149ab747fSPaolo Bonzini }
67249ab747fSPaolo Bonzini
673093454e2SDmitry Fleytman if (e1000x_vlan_enabled(s->mac_reg) &&
674093454e2SDmitry Fleytman e1000x_is_vlan_txd(txd_lower) &&
6757d08c73eSEd Swierk via Qemu-devel (tp->cptse || txd_lower & E1000_TXD_CMD_EOP)) {
67649ab747fSPaolo Bonzini tp->vlan_needed = 1;
677d8ee2591SPeter Maydell stw_be_p(tp->vlan_header,
6784e60a250SShannon Zhao le16_to_cpu(s->mac_reg[VET]));
679d8ee2591SPeter Maydell stw_be_p(tp->vlan_header + 2,
68049ab747fSPaolo Bonzini le16_to_cpu(dp->upper.fields.special));
68149ab747fSPaolo Bonzini }
68249ab747fSPaolo Bonzini
68349ab747fSPaolo Bonzini addr = le64_to_cpu(dp->buffer_addr);
684d62644b4SEd Swierk via Qemu-devel if (tp->cptse) {
685d62644b4SEd Swierk via Qemu-devel msh = tp->tso_props.hdr_len + tp->tso_props.mss;
68649ab747fSPaolo Bonzini do {
68749ab747fSPaolo Bonzini bytes = split_size;
6883de46e6fSJason Wang if (tp->size >= msh) {
6893de46e6fSJason Wang goto eop;
6903de46e6fSJason Wang }
69149ab747fSPaolo Bonzini if (tp->size + bytes > msh)
69249ab747fSPaolo Bonzini bytes = msh - tp->size;
69349ab747fSPaolo Bonzini
69449ab747fSPaolo Bonzini bytes = MIN(sizeof(tp->data) - tp->size, bytes);
695b08340d5SAndreas Färber pci_dma_read(d, addr, tp->data + tp->size, bytes);
696a0ae17a6SAndrew Jones sz = tp->size + bytes;
697d62644b4SEd Swierk via Qemu-devel if (sz >= tp->tso_props.hdr_len
698d62644b4SEd Swierk via Qemu-devel && tp->size < tp->tso_props.hdr_len) {
699d62644b4SEd Swierk via Qemu-devel memmove(tp->header, tp->data, tp->tso_props.hdr_len);
700a0ae17a6SAndrew Jones }
70149ab747fSPaolo Bonzini tp->size = sz;
70249ab747fSPaolo Bonzini addr += bytes;
70349ab747fSPaolo Bonzini if (sz == msh) {
70449ab747fSPaolo Bonzini xmit_seg(s);
705d62644b4SEd Swierk via Qemu-devel memmove(tp->data, tp->header, tp->tso_props.hdr_len);
706d62644b4SEd Swierk via Qemu-devel tp->size = tp->tso_props.hdr_len;
70749ab747fSPaolo Bonzini }
708b947ac2bSP J P split_size -= bytes;
709b947ac2bSP J P } while (bytes && split_size);
71049ab747fSPaolo Bonzini } else {
71149ab747fSPaolo Bonzini split_size = MIN(sizeof(tp->data) - tp->size, split_size);
712b08340d5SAndreas Färber pci_dma_read(d, addr, tp->data + tp->size, split_size);
71349ab747fSPaolo Bonzini tp->size += split_size;
71449ab747fSPaolo Bonzini }
71549ab747fSPaolo Bonzini
7163de46e6fSJason Wang eop:
71749ab747fSPaolo Bonzini if (!(txd_lower & E1000_TXD_CMD_EOP))
71849ab747fSPaolo Bonzini return;
719d62644b4SEd Swierk via Qemu-devel if (!(tp->cptse && tp->size < tp->tso_props.hdr_len)) {
72049ab747fSPaolo Bonzini xmit_seg(s);
721a0ae17a6SAndrew Jones }
72249ab747fSPaolo Bonzini tp->tso_frames = 0;
7237d08c73eSEd Swierk via Qemu-devel tp->sum_needed = 0;
72449ab747fSPaolo Bonzini tp->vlan_needed = 0;
72549ab747fSPaolo Bonzini tp->size = 0;
7267d08c73eSEd Swierk via Qemu-devel tp->cptse = 0;
72749ab747fSPaolo Bonzini }
72849ab747fSPaolo Bonzini
72949ab747fSPaolo Bonzini static uint32_t
txdesc_writeback(E1000State * s,dma_addr_t base,struct e1000_tx_desc * dp)73049ab747fSPaolo Bonzini txdesc_writeback(E1000State *s, dma_addr_t base, struct e1000_tx_desc *dp)
73149ab747fSPaolo Bonzini {
732b08340d5SAndreas Färber PCIDevice *d = PCI_DEVICE(s);
73349ab747fSPaolo Bonzini uint32_t txd_upper, txd_lower = le32_to_cpu(dp->lower.data);
73449ab747fSPaolo Bonzini
73549ab747fSPaolo Bonzini if (!(txd_lower & (E1000_TXD_CMD_RS|E1000_TXD_CMD_RPS)))
73649ab747fSPaolo Bonzini return 0;
73749ab747fSPaolo Bonzini txd_upper = (le32_to_cpu(dp->upper.data) | E1000_TXD_STAT_DD) &
73849ab747fSPaolo Bonzini ~(E1000_TXD_STAT_EC | E1000_TXD_STAT_LC | E1000_TXD_STAT_TU);
73949ab747fSPaolo Bonzini dp->upper.data = cpu_to_le32(txd_upper);
740b08340d5SAndreas Färber pci_dma_write(d, base + ((char *)&dp->upper - (char *)dp),
74149ab747fSPaolo Bonzini &dp->upper, sizeof(dp->upper));
74249ab747fSPaolo Bonzini return E1000_ICR_TXDW;
74349ab747fSPaolo Bonzini }
74449ab747fSPaolo Bonzini
tx_desc_base(E1000State * s)74549ab747fSPaolo Bonzini static uint64_t tx_desc_base(E1000State *s)
74649ab747fSPaolo Bonzini {
74749ab747fSPaolo Bonzini uint64_t bah = s->mac_reg[TDBAH];
74849ab747fSPaolo Bonzini uint64_t bal = s->mac_reg[TDBAL] & ~0xf;
74949ab747fSPaolo Bonzini
75049ab747fSPaolo Bonzini return (bah << 32) + bal;
75149ab747fSPaolo Bonzini }
75249ab747fSPaolo Bonzini
75349ab747fSPaolo Bonzini static void
start_xmit(E1000State * s)75449ab747fSPaolo Bonzini start_xmit(E1000State *s)
75549ab747fSPaolo Bonzini {
756b08340d5SAndreas Färber PCIDevice *d = PCI_DEVICE(s);
75749ab747fSPaolo Bonzini dma_addr_t base;
75849ab747fSPaolo Bonzini struct e1000_tx_desc desc;
75949ab747fSPaolo Bonzini uint32_t tdh_start = s->mac_reg[TDH], cause = E1000_ICS_TXQE;
76049ab747fSPaolo Bonzini
76149ab747fSPaolo Bonzini if (!(s->mac_reg[TCTL] & E1000_TCTL_EN)) {
76249ab747fSPaolo Bonzini DBGOUT(TX, "tx disabled\n");
76349ab747fSPaolo Bonzini return;
76449ab747fSPaolo Bonzini }
76549ab747fSPaolo Bonzini
76625ddb946SJon Maloy if (s->tx.busy) {
76725ddb946SJon Maloy return;
76825ddb946SJon Maloy }
76925ddb946SJon Maloy s->tx.busy = true;
77025ddb946SJon Maloy
77149ab747fSPaolo Bonzini while (s->mac_reg[TDH] != s->mac_reg[TDT]) {
77249ab747fSPaolo Bonzini base = tx_desc_base(s) +
77349ab747fSPaolo Bonzini sizeof(struct e1000_tx_desc) * s->mac_reg[TDH];
774b08340d5SAndreas Färber pci_dma_read(d, base, &desc, sizeof(desc));
77549ab747fSPaolo Bonzini
77649ab747fSPaolo Bonzini DBGOUT(TX, "index %d: %p : %x %x\n", s->mac_reg[TDH],
77749ab747fSPaolo Bonzini (void *)(intptr_t)desc.buffer_addr, desc.lower.data,
77849ab747fSPaolo Bonzini desc.upper.data);
77949ab747fSPaolo Bonzini
78049ab747fSPaolo Bonzini process_tx_desc(s, &desc);
78149ab747fSPaolo Bonzini cause |= txdesc_writeback(s, base, &desc);
78249ab747fSPaolo Bonzini
78349ab747fSPaolo Bonzini if (++s->mac_reg[TDH] * sizeof(desc) >= s->mac_reg[TDLEN])
78449ab747fSPaolo Bonzini s->mac_reg[TDH] = 0;
78549ab747fSPaolo Bonzini /*
78649ab747fSPaolo Bonzini * the following could happen only if guest sw assigns
78749ab747fSPaolo Bonzini * bogus values to TDT/TDLEN.
78849ab747fSPaolo Bonzini * there's nothing too intelligent we could do about this.
78949ab747fSPaolo Bonzini */
790dd793a74SLaszlo Ersek if (s->mac_reg[TDH] == tdh_start ||
791dd793a74SLaszlo Ersek tdh_start >= s->mac_reg[TDLEN] / sizeof(desc)) {
79249ab747fSPaolo Bonzini DBGOUT(TXERR, "TDH wraparound @%x, TDT %x, TDLEN %x\n",
79349ab747fSPaolo Bonzini tdh_start, s->mac_reg[TDT], s->mac_reg[TDLEN]);
79449ab747fSPaolo Bonzini break;
79549ab747fSPaolo Bonzini }
79649ab747fSPaolo Bonzini }
79725ddb946SJon Maloy s->tx.busy = false;
79849ab747fSPaolo Bonzini set_ics(s, 0, cause);
79949ab747fSPaolo Bonzini }
80049ab747fSPaolo Bonzini
80149ab747fSPaolo Bonzini static int
receive_filter(E1000State * s,const void * buf)802e9e5b930SAkihiko Odaki receive_filter(E1000State *s, const void *buf)
80349ab747fSPaolo Bonzini {
804e9e5b930SAkihiko Odaki return (!e1000x_is_vlan_packet(buf, s->mac_reg[VET]) ||
805e9e5b930SAkihiko Odaki e1000x_rx_vlan_filter(s->mac_reg, PKT_GET_VLAN_HDR(buf))) &&
806e9e5b930SAkihiko Odaki e1000x_rx_group_filter(s->mac_reg, buf);
80749ab747fSPaolo Bonzini }
80849ab747fSPaolo Bonzini
80949ab747fSPaolo Bonzini static void
e1000_set_link_status(NetClientState * nc)81049ab747fSPaolo Bonzini e1000_set_link_status(NetClientState *nc)
81149ab747fSPaolo Bonzini {
81249ab747fSPaolo Bonzini E1000State *s = qemu_get_nic_opaque(nc);
81349ab747fSPaolo Bonzini uint32_t old_status = s->mac_reg[STATUS];
81449ab747fSPaolo Bonzini
81549ab747fSPaolo Bonzini if (nc->link_down) {
816093454e2SDmitry Fleytman e1000x_update_regs_on_link_down(s->mac_reg, s->phy_reg);
81749ab747fSPaolo Bonzini } else {
818d7a41552SGabriel L. Somlo if (have_autoneg(s) &&
819b7728c9fSAkihiko Odaki !(s->phy_reg[MII_BMSR] & MII_BMSR_AN_COMP)) {
820093454e2SDmitry Fleytman e1000x_restart_autoneg(s->mac_reg, s->phy_reg, s->autoneg_timer);
8216a2acedbSGabriel L. Somlo } else {
82249ab747fSPaolo Bonzini e1000_link_up(s);
82349ab747fSPaolo Bonzini }
8246a2acedbSGabriel L. Somlo }
82549ab747fSPaolo Bonzini
82649ab747fSPaolo Bonzini if (s->mac_reg[STATUS] != old_status)
82749ab747fSPaolo Bonzini set_ics(s, 0, E1000_ICR_LSC);
82849ab747fSPaolo Bonzini }
82949ab747fSPaolo Bonzini
e1000_has_rxbufs(E1000State * s,size_t total_size)83049ab747fSPaolo Bonzini static bool e1000_has_rxbufs(E1000State *s, size_t total_size)
83149ab747fSPaolo Bonzini {
83249ab747fSPaolo Bonzini int bufs;
83349ab747fSPaolo Bonzini /* Fast-path short packets */
83449ab747fSPaolo Bonzini if (total_size <= s->rxbuf_size) {
83549ab747fSPaolo Bonzini return s->mac_reg[RDH] != s->mac_reg[RDT];
83649ab747fSPaolo Bonzini }
83749ab747fSPaolo Bonzini if (s->mac_reg[RDH] < s->mac_reg[RDT]) {
83849ab747fSPaolo Bonzini bufs = s->mac_reg[RDT] - s->mac_reg[RDH];
83949ab747fSPaolo Bonzini } else if (s->mac_reg[RDH] > s->mac_reg[RDT]) {
84049ab747fSPaolo Bonzini bufs = s->mac_reg[RDLEN] / sizeof(struct e1000_rx_desc) +
84149ab747fSPaolo Bonzini s->mac_reg[RDT] - s->mac_reg[RDH];
84249ab747fSPaolo Bonzini } else {
84349ab747fSPaolo Bonzini return false;
84449ab747fSPaolo Bonzini }
84549ab747fSPaolo Bonzini return total_size <= bufs * s->rxbuf_size;
84649ab747fSPaolo Bonzini }
84749ab747fSPaolo Bonzini
848b8c4b67eSPhilippe Mathieu-Daudé static bool
e1000_can_receive(NetClientState * nc)84949ab747fSPaolo Bonzini e1000_can_receive(NetClientState *nc)
85049ab747fSPaolo Bonzini {
85149ab747fSPaolo Bonzini E1000State *s = qemu_get_nic_opaque(nc);
85249ab747fSPaolo Bonzini
853093454e2SDmitry Fleytman return e1000x_rx_ready(&s->parent_obj, s->mac_reg) &&
854157628d0Syuchenlin e1000_has_rxbufs(s, 1) && !timer_pending(s->flush_queue_timer);
85549ab747fSPaolo Bonzini }
85649ab747fSPaolo Bonzini
rx_desc_base(E1000State * s)85749ab747fSPaolo Bonzini static uint64_t rx_desc_base(E1000State *s)
85849ab747fSPaolo Bonzini {
85949ab747fSPaolo Bonzini uint64_t bah = s->mac_reg[RDBAH];
86049ab747fSPaolo Bonzini uint64_t bal = s->mac_reg[RDBAL] & ~0xf;
86149ab747fSPaolo Bonzini
86249ab747fSPaolo Bonzini return (bah << 32) + bal;
86349ab747fSPaolo Bonzini }
86449ab747fSPaolo Bonzini
8651001cf45SJason Wang static void
e1000_receiver_overrun(E1000State * s,size_t size)8661001cf45SJason Wang e1000_receiver_overrun(E1000State *s, size_t size)
8671001cf45SJason Wang {
8681001cf45SJason Wang trace_e1000_receiver_overrun(size, s->mac_reg[RDH], s->mac_reg[RDT]);
8691001cf45SJason Wang e1000x_inc_reg_if_not_full(s->mac_reg, RNBC);
8701001cf45SJason Wang e1000x_inc_reg_if_not_full(s->mac_reg, MPC);
8711001cf45SJason Wang set_ics(s, 0, E1000_ICS_RXO);
8721001cf45SJason Wang }
8731001cf45SJason Wang
87449ab747fSPaolo Bonzini static ssize_t
e1000_receive_iov(NetClientState * nc,const struct iovec * iov,int iovcnt)87597410ddeSVincenzo Maffione e1000_receive_iov(NetClientState *nc, const struct iovec *iov, int iovcnt)
87649ab747fSPaolo Bonzini {
87749ab747fSPaolo Bonzini E1000State *s = qemu_get_nic_opaque(nc);
878b08340d5SAndreas Färber PCIDevice *d = PCI_DEVICE(s);
87949ab747fSPaolo Bonzini struct e1000_rx_desc desc;
88049ab747fSPaolo Bonzini dma_addr_t base;
88149ab747fSPaolo Bonzini unsigned int n, rdt;
88249ab747fSPaolo Bonzini uint32_t rdh_start;
88349ab747fSPaolo Bonzini uint16_t vlan_special = 0;
88497410ddeSVincenzo Maffione uint8_t vlan_status = 0;
8852fe63579SAkihiko Odaki uint8_t min_buf[ETH_ZLEN];
88697410ddeSVincenzo Maffione uint8_t *filter_buf = iov->iov_base;
88797410ddeSVincenzo Maffione size_t size = iov_size(iov, iovcnt);
88897410ddeSVincenzo Maffione size_t iov_ofs = 0;
88949ab747fSPaolo Bonzini size_t desc_offset;
89049ab747fSPaolo Bonzini size_t desc_size;
89149ab747fSPaolo Bonzini size_t total_size;
892f3f9b726SAkihiko Odaki eth_pkt_types_e pkt_type;
89349ab747fSPaolo Bonzini
894093454e2SDmitry Fleytman if (!e1000x_hw_rx_enabled(s->mac_reg)) {
89549ab747fSPaolo Bonzini return -1;
89649ab747fSPaolo Bonzini }
89749ab747fSPaolo Bonzini
898157628d0Syuchenlin if (timer_pending(s->flush_queue_timer)) {
899157628d0Syuchenlin return 0;
900157628d0Syuchenlin }
901157628d0Syuchenlin
902140eae9cSBin Meng if (iov->iov_len < MAXIMUM_ETHERNET_HDR_LEN) {
90397410ddeSVincenzo Maffione /* This is very unlikely, but may happen. */
90497410ddeSVincenzo Maffione iov_to_buf(iov, iovcnt, 0, min_buf, MAXIMUM_ETHERNET_HDR_LEN);
90597410ddeSVincenzo Maffione filter_buf = min_buf;
90649ab747fSPaolo Bonzini }
90749ab747fSPaolo Bonzini
90849ab747fSPaolo Bonzini /* Discard oversized packets if !LPE and !SBP. */
909093454e2SDmitry Fleytman if (e1000x_is_oversized(s->mac_reg, size)) {
91049ab747fSPaolo Bonzini return size;
91149ab747fSPaolo Bonzini }
91249ab747fSPaolo Bonzini
913e9e5b930SAkihiko Odaki if (!receive_filter(s, filter_buf)) {
91449ab747fSPaolo Bonzini return size;
91597410ddeSVincenzo Maffione }
91649ab747fSPaolo Bonzini
917093454e2SDmitry Fleytman if (e1000x_vlan_enabled(s->mac_reg) &&
918093454e2SDmitry Fleytman e1000x_is_vlan_packet(filter_buf, le16_to_cpu(s->mac_reg[VET]))) {
91914e60aaeSPeter Maydell vlan_special = cpu_to_le16(lduw_be_p(filter_buf + 14));
92097410ddeSVincenzo Maffione iov_ofs = 4;
92197410ddeSVincenzo Maffione if (filter_buf == iov->iov_base) {
92297410ddeSVincenzo Maffione memmove(filter_buf + 4, filter_buf, 12);
92397410ddeSVincenzo Maffione } else {
92497410ddeSVincenzo Maffione iov_from_buf(iov, iovcnt, 4, filter_buf, 12);
92597410ddeSVincenzo Maffione while (iov->iov_len <= iov_ofs) {
92697410ddeSVincenzo Maffione iov_ofs -= iov->iov_len;
92797410ddeSVincenzo Maffione iov++;
92897410ddeSVincenzo Maffione }
92997410ddeSVincenzo Maffione }
93049ab747fSPaolo Bonzini vlan_status = E1000_RXD_STAT_VP;
93149ab747fSPaolo Bonzini size -= 4;
93249ab747fSPaolo Bonzini }
93349ab747fSPaolo Bonzini
934f3f9b726SAkihiko Odaki pkt_type = get_eth_packet_type(PKT_GET_ETH_HDR(filter_buf));
93549ab747fSPaolo Bonzini rdh_start = s->mac_reg[RDH];
93649ab747fSPaolo Bonzini desc_offset = 0;
937093454e2SDmitry Fleytman total_size = size + e1000x_fcs_len(s->mac_reg);
93849ab747fSPaolo Bonzini if (!e1000_has_rxbufs(s, total_size)) {
9391001cf45SJason Wang e1000_receiver_overrun(s, total_size);
94049ab747fSPaolo Bonzini return -1;
94149ab747fSPaolo Bonzini }
94249ab747fSPaolo Bonzini do {
94349ab747fSPaolo Bonzini desc_size = total_size - desc_offset;
94449ab747fSPaolo Bonzini if (desc_size > s->rxbuf_size) {
94549ab747fSPaolo Bonzini desc_size = s->rxbuf_size;
94649ab747fSPaolo Bonzini }
94749ab747fSPaolo Bonzini base = rx_desc_base(s) + sizeof(desc) * s->mac_reg[RDH];
948b08340d5SAndreas Färber pci_dma_read(d, base, &desc, sizeof(desc));
94949ab747fSPaolo Bonzini desc.special = vlan_special;
950034d00d4SDing Hui desc.status &= ~E1000_RXD_STAT_DD;
95149ab747fSPaolo Bonzini if (desc.buffer_addr) {
95249ab747fSPaolo Bonzini if (desc_offset < size) {
95397410ddeSVincenzo Maffione size_t iov_copy;
95497410ddeSVincenzo Maffione hwaddr ba = le64_to_cpu(desc.buffer_addr);
95549ab747fSPaolo Bonzini size_t copy_size = size - desc_offset;
95649ab747fSPaolo Bonzini if (copy_size > s->rxbuf_size) {
95749ab747fSPaolo Bonzini copy_size = s->rxbuf_size;
95849ab747fSPaolo Bonzini }
95997410ddeSVincenzo Maffione do {
96097410ddeSVincenzo Maffione iov_copy = MIN(copy_size, iov->iov_len - iov_ofs);
96197410ddeSVincenzo Maffione pci_dma_write(d, ba, iov->iov_base + iov_ofs, iov_copy);
96297410ddeSVincenzo Maffione copy_size -= iov_copy;
96397410ddeSVincenzo Maffione ba += iov_copy;
96497410ddeSVincenzo Maffione iov_ofs += iov_copy;
96597410ddeSVincenzo Maffione if (iov_ofs == iov->iov_len) {
96697410ddeSVincenzo Maffione iov++;
96797410ddeSVincenzo Maffione iov_ofs = 0;
96897410ddeSVincenzo Maffione }
96997410ddeSVincenzo Maffione } while (copy_size);
97049ab747fSPaolo Bonzini }
97149ab747fSPaolo Bonzini desc_offset += desc_size;
97249ab747fSPaolo Bonzini desc.length = cpu_to_le16(desc_size);
97349ab747fSPaolo Bonzini if (desc_offset >= total_size) {
97449ab747fSPaolo Bonzini desc.status |= E1000_RXD_STAT_EOP | E1000_RXD_STAT_IXSM;
97549ab747fSPaolo Bonzini } else {
97649ab747fSPaolo Bonzini /* Guest zeroing out status is not a hardware requirement.
97749ab747fSPaolo Bonzini Clear EOP in case guest didn't do it. */
97849ab747fSPaolo Bonzini desc.status &= ~E1000_RXD_STAT_EOP;
97949ab747fSPaolo Bonzini }
98049ab747fSPaolo Bonzini } else { // as per intel docs; skip descriptors with null buf addr
98149ab747fSPaolo Bonzini DBGOUT(RX, "Null RX descriptor!!\n");
98249ab747fSPaolo Bonzini }
983b08340d5SAndreas Färber pci_dma_write(d, base, &desc, sizeof(desc));
984034d00d4SDing Hui desc.status |= (vlan_status | E1000_RXD_STAT_DD);
985034d00d4SDing Hui pci_dma_write(d, base + offsetof(struct e1000_rx_desc, status),
986034d00d4SDing Hui &desc.status, sizeof(desc.status));
98749ab747fSPaolo Bonzini
98849ab747fSPaolo Bonzini if (++s->mac_reg[RDH] * sizeof(desc) >= s->mac_reg[RDLEN])
98949ab747fSPaolo Bonzini s->mac_reg[RDH] = 0;
99049ab747fSPaolo Bonzini /* see comment in start_xmit; same here */
991dd793a74SLaszlo Ersek if (s->mac_reg[RDH] == rdh_start ||
992dd793a74SLaszlo Ersek rdh_start >= s->mac_reg[RDLEN] / sizeof(desc)) {
99349ab747fSPaolo Bonzini DBGOUT(RXERR, "RDH wraparound @%x, RDT %x, RDLEN %x\n",
99449ab747fSPaolo Bonzini rdh_start, s->mac_reg[RDT], s->mac_reg[RDLEN]);
9951001cf45SJason Wang e1000_receiver_overrun(s, total_size);
99649ab747fSPaolo Bonzini return -1;
99749ab747fSPaolo Bonzini }
99849ab747fSPaolo Bonzini } while (desc_offset < total_size);
99949ab747fSPaolo Bonzini
1000f3f9b726SAkihiko Odaki e1000x_update_rx_total_stats(s->mac_reg, pkt_type, size, total_size);
100149ab747fSPaolo Bonzini
100249ab747fSPaolo Bonzini n = E1000_ICS_RXT0;
100349ab747fSPaolo Bonzini if ((rdt = s->mac_reg[RDT]) < s->mac_reg[RDH])
100449ab747fSPaolo Bonzini rdt += s->mac_reg[RDLEN] / sizeof(desc);
100549ab747fSPaolo Bonzini if (((rdt - s->mac_reg[RDH]) * sizeof(desc)) <= s->mac_reg[RDLEN] >>
100649ab747fSPaolo Bonzini s->rxbuf_min_shift)
100749ab747fSPaolo Bonzini n |= E1000_ICS_RXDMT0;
100849ab747fSPaolo Bonzini
100949ab747fSPaolo Bonzini set_ics(s, 0, n);
101049ab747fSPaolo Bonzini
101149ab747fSPaolo Bonzini return size;
101249ab747fSPaolo Bonzini }
101349ab747fSPaolo Bonzini
101497410ddeSVincenzo Maffione static ssize_t
e1000_receive(NetClientState * nc,const uint8_t * buf,size_t size)101597410ddeSVincenzo Maffione e1000_receive(NetClientState *nc, const uint8_t *buf, size_t size)
101697410ddeSVincenzo Maffione {
101797410ddeSVincenzo Maffione const struct iovec iov = {
101897410ddeSVincenzo Maffione .iov_base = (uint8_t *)buf,
101997410ddeSVincenzo Maffione .iov_len = size
102097410ddeSVincenzo Maffione };
102197410ddeSVincenzo Maffione
102297410ddeSVincenzo Maffione return e1000_receive_iov(nc, &iov, 1);
102397410ddeSVincenzo Maffione }
102497410ddeSVincenzo Maffione
102549ab747fSPaolo Bonzini static uint32_t
mac_readreg(E1000State * s,int index)102649ab747fSPaolo Bonzini mac_readreg(E1000State *s, int index)
102749ab747fSPaolo Bonzini {
102849ab747fSPaolo Bonzini return s->mac_reg[index];
102949ab747fSPaolo Bonzini }
103049ab747fSPaolo Bonzini
103149ab747fSPaolo Bonzini static uint32_t
mac_icr_read(E1000State * s,int index)103249ab747fSPaolo Bonzini mac_icr_read(E1000State *s, int index)
103349ab747fSPaolo Bonzini {
103449ab747fSPaolo Bonzini uint32_t ret = s->mac_reg[ICR];
103549ab747fSPaolo Bonzini
103649ab747fSPaolo Bonzini DBGOUT(INTERRUPT, "ICR read: %x\n", ret);
103749ab747fSPaolo Bonzini set_interrupt_cause(s, 0, 0);
103849ab747fSPaolo Bonzini return ret;
103949ab747fSPaolo Bonzini }
104049ab747fSPaolo Bonzini
104149ab747fSPaolo Bonzini static uint32_t
mac_read_clr4(E1000State * s,int index)104249ab747fSPaolo Bonzini mac_read_clr4(E1000State *s, int index)
104349ab747fSPaolo Bonzini {
104449ab747fSPaolo Bonzini uint32_t ret = s->mac_reg[index];
104549ab747fSPaolo Bonzini
104649ab747fSPaolo Bonzini s->mac_reg[index] = 0;
104749ab747fSPaolo Bonzini return ret;
104849ab747fSPaolo Bonzini }
104949ab747fSPaolo Bonzini
105049ab747fSPaolo Bonzini static uint32_t
mac_read_clr8(E1000State * s,int index)105149ab747fSPaolo Bonzini mac_read_clr8(E1000State *s, int index)
105249ab747fSPaolo Bonzini {
105349ab747fSPaolo Bonzini uint32_t ret = s->mac_reg[index];
105449ab747fSPaolo Bonzini
105549ab747fSPaolo Bonzini s->mac_reg[index] = 0;
105649ab747fSPaolo Bonzini s->mac_reg[index-1] = 0;
105749ab747fSPaolo Bonzini return ret;
105849ab747fSPaolo Bonzini }
105949ab747fSPaolo Bonzini
106049ab747fSPaolo Bonzini static void
mac_writereg(E1000State * s,int index,uint32_t val)106149ab747fSPaolo Bonzini mac_writereg(E1000State *s, int index, uint32_t val)
106249ab747fSPaolo Bonzini {
10637c36507cSAmos Kong uint32_t macaddr[2];
10647c36507cSAmos Kong
106549ab747fSPaolo Bonzini s->mac_reg[index] = val;
10667c36507cSAmos Kong
106790d131fbSMichael S. Tsirkin if (index == RA + 1) {
10687c36507cSAmos Kong macaddr[0] = cpu_to_le32(s->mac_reg[RA]);
10697c36507cSAmos Kong macaddr[1] = cpu_to_le32(s->mac_reg[RA + 1]);
10707c36507cSAmos Kong qemu_format_nic_info_str(qemu_get_queue(s->nic), (uint8_t *)macaddr);
10717c36507cSAmos Kong }
107249ab747fSPaolo Bonzini }
107349ab747fSPaolo Bonzini
107449ab747fSPaolo Bonzini static void
set_rdt(E1000State * s,int index,uint32_t val)107549ab747fSPaolo Bonzini set_rdt(E1000State *s, int index, uint32_t val)
107649ab747fSPaolo Bonzini {
107749ab747fSPaolo Bonzini s->mac_reg[index] = val & 0xffff;
107849ab747fSPaolo Bonzini if (e1000_has_rxbufs(s, 1)) {
107949ab747fSPaolo Bonzini qemu_flush_queued_packets(qemu_get_queue(s->nic));
108049ab747fSPaolo Bonzini }
108149ab747fSPaolo Bonzini }
108249ab747fSPaolo Bonzini
1083a9484b8aSAkihiko Odaki #define LOW_BITS_SET_FUNC(num) \
1084a9484b8aSAkihiko Odaki static void \
1085a9484b8aSAkihiko Odaki set_##num##bit(E1000State *s, int index, uint32_t val) \
1086a9484b8aSAkihiko Odaki { \
1087a9484b8aSAkihiko Odaki s->mac_reg[index] = val & (BIT(num) - 1); \
108849ab747fSPaolo Bonzini }
108949ab747fSPaolo Bonzini
1090a9484b8aSAkihiko Odaki LOW_BITS_SET_FUNC(4)
1091a9484b8aSAkihiko Odaki LOW_BITS_SET_FUNC(11)
1092a9484b8aSAkihiko Odaki LOW_BITS_SET_FUNC(13)
1093a9484b8aSAkihiko Odaki LOW_BITS_SET_FUNC(16)
1094a9484b8aSAkihiko Odaki
109549ab747fSPaolo Bonzini static void
set_dlen(E1000State * s,int index,uint32_t val)109649ab747fSPaolo Bonzini set_dlen(E1000State *s, int index, uint32_t val)
109749ab747fSPaolo Bonzini {
109849ab747fSPaolo Bonzini s->mac_reg[index] = val & 0xfff80;
109949ab747fSPaolo Bonzini }
110049ab747fSPaolo Bonzini
110149ab747fSPaolo Bonzini static void
set_tctl(E1000State * s,int index,uint32_t val)110249ab747fSPaolo Bonzini set_tctl(E1000State *s, int index, uint32_t val)
110349ab747fSPaolo Bonzini {
110449ab747fSPaolo Bonzini s->mac_reg[index] = val;
110549ab747fSPaolo Bonzini s->mac_reg[TDT] &= 0xffff;
110649ab747fSPaolo Bonzini start_xmit(s);
110749ab747fSPaolo Bonzini }
110849ab747fSPaolo Bonzini
110949ab747fSPaolo Bonzini static void
set_icr(E1000State * s,int index,uint32_t val)111049ab747fSPaolo Bonzini set_icr(E1000State *s, int index, uint32_t val)
111149ab747fSPaolo Bonzini {
111249ab747fSPaolo Bonzini DBGOUT(INTERRUPT, "set_icr %x\n", val);
111349ab747fSPaolo Bonzini set_interrupt_cause(s, 0, s->mac_reg[ICR] & ~val);
111449ab747fSPaolo Bonzini }
111549ab747fSPaolo Bonzini
111649ab747fSPaolo Bonzini static void
set_imc(E1000State * s,int index,uint32_t val)111749ab747fSPaolo Bonzini set_imc(E1000State *s, int index, uint32_t val)
111849ab747fSPaolo Bonzini {
111949ab747fSPaolo Bonzini s->mac_reg[IMS] &= ~val;
112049ab747fSPaolo Bonzini set_ics(s, 0, 0);
112149ab747fSPaolo Bonzini }
112249ab747fSPaolo Bonzini
112349ab747fSPaolo Bonzini static void
set_ims(E1000State * s,int index,uint32_t val)112449ab747fSPaolo Bonzini set_ims(E1000State *s, int index, uint32_t val)
112549ab747fSPaolo Bonzini {
112649ab747fSPaolo Bonzini s->mac_reg[IMS] |= val;
112749ab747fSPaolo Bonzini set_ics(s, 0, 0);
112849ab747fSPaolo Bonzini }
112949ab747fSPaolo Bonzini
113049ab747fSPaolo Bonzini #define getreg(x) [x] = mac_readreg
11313b6b3a27SPhilippe Mathieu-Daudé typedef uint32_t (*readops)(E1000State *, int);
1132da5cf9a4SPhilippe Mathieu-Daudé static const readops macreg_readops[] = {
113349ab747fSPaolo Bonzini getreg(PBA), getreg(RCTL), getreg(TDH), getreg(TXDCTL),
113449ab747fSPaolo Bonzini getreg(WUFC), getreg(TDT), getreg(CTRL), getreg(LEDCTL),
113549ab747fSPaolo Bonzini getreg(MANC), getreg(MDIC), getreg(SWSM), getreg(STATUS),
113649ab747fSPaolo Bonzini getreg(TORL), getreg(TOTL), getreg(IMS), getreg(TCTL),
113749ab747fSPaolo Bonzini getreg(RDH), getreg(RDT), getreg(VET), getreg(ICS),
113849ab747fSPaolo Bonzini getreg(TDBAL), getreg(TDBAH), getreg(RDBAH), getreg(RDBAL),
1139e9845f09SVincenzo Maffione getreg(TDLEN), getreg(RDLEN), getreg(RDTR), getreg(RADV),
114072ea771cSLeonid Bloch getreg(TADV), getreg(ITR), getreg(FCRUC), getreg(IPAV),
114172ea771cSLeonid Bloch getreg(WUC), getreg(WUS), getreg(SCC), getreg(ECOL),
114272ea771cSLeonid Bloch getreg(MCC), getreg(LATECOL), getreg(COLC), getreg(DC),
1143757704f1SKamil Rytarowski getreg(TNCRS), getreg(SEQEC), getreg(CEXTERR), getreg(RLEC),
114472ea771cSLeonid Bloch getreg(XONRXC), getreg(XONTXC), getreg(XOFFRXC), getreg(XOFFTXC),
114572ea771cSLeonid Bloch getreg(RFC), getreg(RJC), getreg(RNBC), getreg(TSCTFC),
11463b274301SLeonid Bloch getreg(MGTPRC), getreg(MGTPDC), getreg(MGTPTC), getreg(GORCL),
1147a9484b8aSAkihiko Odaki getreg(GOTCL), getreg(RDFH), getreg(RDFT), getreg(RDFHS),
1148a9484b8aSAkihiko Odaki getreg(RDFTS), getreg(RDFPC), getreg(TDFH), getreg(TDFT),
1149a9484b8aSAkihiko Odaki getreg(TDFHS), getreg(TDFTS), getreg(TDFPC), getreg(AIT),
115049ab747fSPaolo Bonzini
115120f3e863SLeonid Bloch [TOTH] = mac_read_clr8, [TORH] = mac_read_clr8,
11523b274301SLeonid Bloch [GOTCH] = mac_read_clr8, [GORCH] = mac_read_clr8,
11533b274301SLeonid Bloch [PRC64] = mac_read_clr4, [PRC127] = mac_read_clr4,
11543b274301SLeonid Bloch [PRC255] = mac_read_clr4, [PRC511] = mac_read_clr4,
11553b274301SLeonid Bloch [PRC1023] = mac_read_clr4, [PRC1522] = mac_read_clr4,
11563b274301SLeonid Bloch [PTC64] = mac_read_clr4, [PTC127] = mac_read_clr4,
11573b274301SLeonid Bloch [PTC255] = mac_read_clr4, [PTC511] = mac_read_clr4,
11583b274301SLeonid Bloch [PTC1023] = mac_read_clr4, [PTC1522] = mac_read_clr4,
115920f3e863SLeonid Bloch [GPRC] = mac_read_clr4, [GPTC] = mac_read_clr4,
116020f3e863SLeonid Bloch [TPT] = mac_read_clr4, [TPR] = mac_read_clr4,
11613b274301SLeonid Bloch [RUC] = mac_read_clr4, [ROC] = mac_read_clr4,
11623b274301SLeonid Bloch [BPRC] = mac_read_clr4, [MPRC] = mac_read_clr4,
11633b274301SLeonid Bloch [TSCTC] = mac_read_clr4, [BPTC] = mac_read_clr4,
11643b274301SLeonid Bloch [MPTC] = mac_read_clr4,
116520f3e863SLeonid Bloch [ICR] = mac_icr_read, [EECD] = get_eecd,
116620f3e863SLeonid Bloch [EERD] = flash_eerd_read,
116720f3e863SLeonid Bloch
116849ab747fSPaolo Bonzini [CRCERRS ... MPC] = &mac_readreg,
116972ea771cSLeonid Bloch [IP6AT ... IP6AT + 3] = &mac_readreg, [IP4AT ... IP4AT + 6] = &mac_readreg,
1170a9484b8aSAkihiko Odaki [FFLT ... FFLT + 6] = &mac_readreg,
117149ab747fSPaolo Bonzini [RA ... RA + 31] = &mac_readreg,
117272ea771cSLeonid Bloch [WUPM ... WUPM + 31] = &mac_readreg,
11732fe63579SAkihiko Odaki [MTA ... MTA + E1000_MC_TBL_SIZE - 1] = &mac_readreg,
11742fe63579SAkihiko Odaki [VFTA ... VFTA + E1000_VLAN_FILTER_TBL_SIZE - 1] = &mac_readreg,
1175a9484b8aSAkihiko Odaki [FFMT ... FFMT + 254] = &mac_readreg,
117672ea771cSLeonid Bloch [FFVT ... FFVT + 254] = &mac_readreg,
117772ea771cSLeonid Bloch [PBM ... PBM + 16383] = &mac_readreg,
117849ab747fSPaolo Bonzini };
117949ab747fSPaolo Bonzini enum { NREADOPS = ARRAY_SIZE(macreg_readops) };
118049ab747fSPaolo Bonzini
118149ab747fSPaolo Bonzini #define putreg(x) [x] = mac_writereg
11823b6b3a27SPhilippe Mathieu-Daudé typedef void (*writeops)(E1000State *, int, uint32_t);
1183da5cf9a4SPhilippe Mathieu-Daudé static const writeops macreg_writeops[] = {
118449ab747fSPaolo Bonzini putreg(PBA), putreg(EERD), putreg(SWSM), putreg(WUFC),
118549ab747fSPaolo Bonzini putreg(TDBAL), putreg(TDBAH), putreg(TXDCTL), putreg(RDBAH),
118672ea771cSLeonid Bloch putreg(RDBAL), putreg(LEDCTL), putreg(VET), putreg(FCRUC),
1187a9484b8aSAkihiko Odaki putreg(IPAV), putreg(WUC),
1188a9484b8aSAkihiko Odaki putreg(WUS),
118920f3e863SLeonid Bloch
119049ab747fSPaolo Bonzini [TDLEN] = set_dlen, [RDLEN] = set_dlen, [TCTL] = set_tctl,
119149ab747fSPaolo Bonzini [TDT] = set_tctl, [MDIC] = set_mdic, [ICS] = set_ics,
119249ab747fSPaolo Bonzini [TDH] = set_16bit, [RDH] = set_16bit, [RDT] = set_rdt,
119349ab747fSPaolo Bonzini [IMC] = set_imc, [IMS] = set_ims, [ICR] = set_icr,
119449ab747fSPaolo Bonzini [EECD] = set_eecd, [RCTL] = set_rx_control, [CTRL] = set_ctrl,
1195e9845f09SVincenzo Maffione [RDTR] = set_16bit, [RADV] = set_16bit, [TADV] = set_16bit,
1196a9484b8aSAkihiko Odaki [ITR] = set_16bit, [TDFH] = set_11bit, [TDFT] = set_11bit,
1197a9484b8aSAkihiko Odaki [TDFHS] = set_13bit, [TDFTS] = set_13bit, [TDFPC] = set_13bit,
1198a9484b8aSAkihiko Odaki [RDFH] = set_13bit, [RDFT] = set_13bit, [RDFHS] = set_13bit,
1199a9484b8aSAkihiko Odaki [RDFTS] = set_13bit, [RDFPC] = set_13bit, [AIT] = set_16bit,
120020f3e863SLeonid Bloch
120172ea771cSLeonid Bloch [IP6AT ... IP6AT + 3] = &mac_writereg, [IP4AT ... IP4AT + 6] = &mac_writereg,
1202a9484b8aSAkihiko Odaki [FFLT ... FFLT + 6] = &set_11bit,
120349ab747fSPaolo Bonzini [RA ... RA + 31] = &mac_writereg,
120472ea771cSLeonid Bloch [WUPM ... WUPM + 31] = &mac_writereg,
12052fe63579SAkihiko Odaki [MTA ... MTA + E1000_MC_TBL_SIZE - 1] = &mac_writereg,
12062fe63579SAkihiko Odaki [VFTA ... VFTA + E1000_VLAN_FILTER_TBL_SIZE - 1] = &mac_writereg,
1207a9484b8aSAkihiko Odaki [FFMT ... FFMT + 254] = &set_4bit, [FFVT ... FFVT + 254] = &mac_writereg,
120872ea771cSLeonid Bloch [PBM ... PBM + 16383] = &mac_writereg,
120949ab747fSPaolo Bonzini };
121049ab747fSPaolo Bonzini
121149ab747fSPaolo Bonzini enum { NWRITEOPS = ARRAY_SIZE(macreg_writeops) };
121249ab747fSPaolo Bonzini
1213bc0f0674SLeonid Bloch enum { MAC_ACCESS_PARTIAL = 1, MAC_ACCESS_FLAG_NEEDED = 2 };
1214bc0f0674SLeonid Bloch
1215bc0f0674SLeonid Bloch #define markflag(x) ((E1000_FLAG_##x << 2) | MAC_ACCESS_FLAG_NEEDED)
1216bc0f0674SLeonid Bloch /* In the array below the meaning of the bits is: [f|f|f|f|f|f|n|p]
1217bc0f0674SLeonid Bloch * f - flag bits (up to 6 possible flags)
1218bc0f0674SLeonid Bloch * n - flag needed
1219bc0f0674SLeonid Bloch * p - partially implenented */
1220bc0f0674SLeonid Bloch static const uint8_t mac_reg_access[0x8000] = {
122172ea771cSLeonid Bloch [IPAV] = markflag(MAC), [WUC] = markflag(MAC),
122272ea771cSLeonid Bloch [IP6AT] = markflag(MAC), [IP4AT] = markflag(MAC),
122372ea771cSLeonid Bloch [FFVT] = markflag(MAC), [WUPM] = markflag(MAC),
122472ea771cSLeonid Bloch [ECOL] = markflag(MAC), [MCC] = markflag(MAC),
122572ea771cSLeonid Bloch [DC] = markflag(MAC), [TNCRS] = markflag(MAC),
122672ea771cSLeonid Bloch [RLEC] = markflag(MAC), [XONRXC] = markflag(MAC),
122772ea771cSLeonid Bloch [XOFFTXC] = markflag(MAC), [RFC] = markflag(MAC),
122872ea771cSLeonid Bloch [TSCTFC] = markflag(MAC), [MGTPRC] = markflag(MAC),
122972ea771cSLeonid Bloch [WUS] = markflag(MAC), [AIT] = markflag(MAC),
123072ea771cSLeonid Bloch [FFLT] = markflag(MAC), [FFMT] = markflag(MAC),
123172ea771cSLeonid Bloch [SCC] = markflag(MAC), [FCRUC] = markflag(MAC),
123272ea771cSLeonid Bloch [LATECOL] = markflag(MAC), [COLC] = markflag(MAC),
1233757704f1SKamil Rytarowski [SEQEC] = markflag(MAC), [CEXTERR] = markflag(MAC),
123472ea771cSLeonid Bloch [XONTXC] = markflag(MAC), [XOFFRXC] = markflag(MAC),
123572ea771cSLeonid Bloch [RJC] = markflag(MAC), [RNBC] = markflag(MAC),
123672ea771cSLeonid Bloch [MGTPDC] = markflag(MAC), [MGTPTC] = markflag(MAC),
12373b274301SLeonid Bloch [RUC] = markflag(MAC), [ROC] = markflag(MAC),
12383b274301SLeonid Bloch [GORCL] = markflag(MAC), [GORCH] = markflag(MAC),
12393b274301SLeonid Bloch [GOTCL] = markflag(MAC), [GOTCH] = markflag(MAC),
12403b274301SLeonid Bloch [BPRC] = markflag(MAC), [MPRC] = markflag(MAC),
12413b274301SLeonid Bloch [TSCTC] = markflag(MAC), [PRC64] = markflag(MAC),
12423b274301SLeonid Bloch [PRC127] = markflag(MAC), [PRC255] = markflag(MAC),
12433b274301SLeonid Bloch [PRC511] = markflag(MAC), [PRC1023] = markflag(MAC),
12443b274301SLeonid Bloch [PRC1522] = markflag(MAC), [PTC64] = markflag(MAC),
12453b274301SLeonid Bloch [PTC127] = markflag(MAC), [PTC255] = markflag(MAC),
12463b274301SLeonid Bloch [PTC511] = markflag(MAC), [PTC1023] = markflag(MAC),
12473b274301SLeonid Bloch [PTC1522] = markflag(MAC), [MPTC] = markflag(MAC),
12483b274301SLeonid Bloch [BPTC] = markflag(MAC),
124972ea771cSLeonid Bloch
125072ea771cSLeonid Bloch [TDFH] = markflag(MAC) | MAC_ACCESS_PARTIAL,
125172ea771cSLeonid Bloch [TDFT] = markflag(MAC) | MAC_ACCESS_PARTIAL,
125272ea771cSLeonid Bloch [TDFHS] = markflag(MAC) | MAC_ACCESS_PARTIAL,
125372ea771cSLeonid Bloch [TDFTS] = markflag(MAC) | MAC_ACCESS_PARTIAL,
125472ea771cSLeonid Bloch [TDFPC] = markflag(MAC) | MAC_ACCESS_PARTIAL,
125572ea771cSLeonid Bloch [RDFH] = markflag(MAC) | MAC_ACCESS_PARTIAL,
125672ea771cSLeonid Bloch [RDFT] = markflag(MAC) | MAC_ACCESS_PARTIAL,
125772ea771cSLeonid Bloch [RDFHS] = markflag(MAC) | MAC_ACCESS_PARTIAL,
125872ea771cSLeonid Bloch [RDFTS] = markflag(MAC) | MAC_ACCESS_PARTIAL,
125972ea771cSLeonid Bloch [RDFPC] = markflag(MAC) | MAC_ACCESS_PARTIAL,
126072ea771cSLeonid Bloch [PBM] = markflag(MAC) | MAC_ACCESS_PARTIAL,
1261bc0f0674SLeonid Bloch };
1262bc0f0674SLeonid Bloch
126349ab747fSPaolo Bonzini static void
e1000_mmio_write(void * opaque,hwaddr addr,uint64_t val,unsigned size)126449ab747fSPaolo Bonzini e1000_mmio_write(void *opaque, hwaddr addr, uint64_t val,
126549ab747fSPaolo Bonzini unsigned size)
126649ab747fSPaolo Bonzini {
126749ab747fSPaolo Bonzini E1000State *s = opaque;
126849ab747fSPaolo Bonzini unsigned int index = (addr & 0x1ffff) >> 2;
126949ab747fSPaolo Bonzini
127049ab747fSPaolo Bonzini if (index < NWRITEOPS && macreg_writeops[index]) {
1271bc0f0674SLeonid Bloch if (!(mac_reg_access[index] & MAC_ACCESS_FLAG_NEEDED)
1272bc0f0674SLeonid Bloch || (s->compat_flags & (mac_reg_access[index] >> 2))) {
1273bc0f0674SLeonid Bloch if (mac_reg_access[index] & MAC_ACCESS_PARTIAL) {
1274bc0f0674SLeonid Bloch DBGOUT(GENERAL, "Writing to register at offset: 0x%08x. "
1275bc0f0674SLeonid Bloch "It is not fully implemented.\n", index<<2);
1276bc0f0674SLeonid Bloch }
127749ab747fSPaolo Bonzini macreg_writeops[index](s, index, val);
1278bc0f0674SLeonid Bloch } else { /* "flag needed" bit is set, but the flag is not active */
1279bc0f0674SLeonid Bloch DBGOUT(MMIO, "MMIO write attempt to disabled reg. addr=0x%08x\n",
1280bc0f0674SLeonid Bloch index<<2);
1281bc0f0674SLeonid Bloch }
128249ab747fSPaolo Bonzini } else if (index < NREADOPS && macreg_readops[index]) {
1283bc0f0674SLeonid Bloch DBGOUT(MMIO, "e1000_mmio_writel RO %x: 0x%04"PRIx64"\n",
1284bc0f0674SLeonid Bloch index<<2, val);
128549ab747fSPaolo Bonzini } else {
128649ab747fSPaolo Bonzini DBGOUT(UNKNOWN, "MMIO unknown write addr=0x%08x,val=0x%08"PRIx64"\n",
128749ab747fSPaolo Bonzini index<<2, val);
128849ab747fSPaolo Bonzini }
128949ab747fSPaolo Bonzini }
129049ab747fSPaolo Bonzini
129149ab747fSPaolo Bonzini static uint64_t
e1000_mmio_read(void * opaque,hwaddr addr,unsigned size)129249ab747fSPaolo Bonzini e1000_mmio_read(void *opaque, hwaddr addr, unsigned size)
129349ab747fSPaolo Bonzini {
129449ab747fSPaolo Bonzini E1000State *s = opaque;
129549ab747fSPaolo Bonzini unsigned int index = (addr & 0x1ffff) >> 2;
129649ab747fSPaolo Bonzini
1297bc0f0674SLeonid Bloch if (index < NREADOPS && macreg_readops[index]) {
1298bc0f0674SLeonid Bloch if (!(mac_reg_access[index] & MAC_ACCESS_FLAG_NEEDED)
1299bc0f0674SLeonid Bloch || (s->compat_flags & (mac_reg_access[index] >> 2))) {
1300bc0f0674SLeonid Bloch if (mac_reg_access[index] & MAC_ACCESS_PARTIAL) {
1301bc0f0674SLeonid Bloch DBGOUT(GENERAL, "Reading register at offset: 0x%08x. "
1302bc0f0674SLeonid Bloch "It is not fully implemented.\n", index<<2);
130349ab747fSPaolo Bonzini }
1304bc0f0674SLeonid Bloch return macreg_readops[index](s, index);
1305bc0f0674SLeonid Bloch } else { /* "flag needed" bit is set, but the flag is not active */
1306bc0f0674SLeonid Bloch DBGOUT(MMIO, "MMIO read attempt of disabled reg. addr=0x%08x\n",
1307bc0f0674SLeonid Bloch index<<2);
1308bc0f0674SLeonid Bloch }
1309bc0f0674SLeonid Bloch } else {
131049ab747fSPaolo Bonzini DBGOUT(UNKNOWN, "MMIO unknown read addr=0x%08x\n", index<<2);
1311bc0f0674SLeonid Bloch }
131249ab747fSPaolo Bonzini return 0;
131349ab747fSPaolo Bonzini }
131449ab747fSPaolo Bonzini
131549ab747fSPaolo Bonzini static const MemoryRegionOps e1000_mmio_ops = {
131649ab747fSPaolo Bonzini .read = e1000_mmio_read,
131749ab747fSPaolo Bonzini .write = e1000_mmio_write,
131849ab747fSPaolo Bonzini .endianness = DEVICE_LITTLE_ENDIAN,
131949ab747fSPaolo Bonzini .impl = {
132049ab747fSPaolo Bonzini .min_access_size = 4,
132149ab747fSPaolo Bonzini .max_access_size = 4,
132249ab747fSPaolo Bonzini },
132349ab747fSPaolo Bonzini };
132449ab747fSPaolo Bonzini
e1000_io_read(void * opaque,hwaddr addr,unsigned size)132549ab747fSPaolo Bonzini static uint64_t e1000_io_read(void *opaque, hwaddr addr,
132649ab747fSPaolo Bonzini unsigned size)
132749ab747fSPaolo Bonzini {
132849ab747fSPaolo Bonzini E1000State *s = opaque;
132949ab747fSPaolo Bonzini
133049ab747fSPaolo Bonzini (void)s;
133149ab747fSPaolo Bonzini return 0;
133249ab747fSPaolo Bonzini }
133349ab747fSPaolo Bonzini
e1000_io_write(void * opaque,hwaddr addr,uint64_t val,unsigned size)133449ab747fSPaolo Bonzini static void e1000_io_write(void *opaque, hwaddr addr,
133549ab747fSPaolo Bonzini uint64_t val, unsigned size)
133649ab747fSPaolo Bonzini {
133749ab747fSPaolo Bonzini E1000State *s = opaque;
133849ab747fSPaolo Bonzini
133949ab747fSPaolo Bonzini (void)s;
134049ab747fSPaolo Bonzini }
134149ab747fSPaolo Bonzini
134249ab747fSPaolo Bonzini static const MemoryRegionOps e1000_io_ops = {
134349ab747fSPaolo Bonzini .read = e1000_io_read,
134449ab747fSPaolo Bonzini .write = e1000_io_write,
134549ab747fSPaolo Bonzini .endianness = DEVICE_LITTLE_ENDIAN,
134649ab747fSPaolo Bonzini };
134749ab747fSPaolo Bonzini
is_version_1(void * opaque,int version_id)134849ab747fSPaolo Bonzini static bool is_version_1(void *opaque, int version_id)
134949ab747fSPaolo Bonzini {
135049ab747fSPaolo Bonzini return version_id == 1;
135149ab747fSPaolo Bonzini }
135249ab747fSPaolo Bonzini
e1000_pre_save(void * opaque)135344b1ff31SDr. David Alan Gilbert static int e1000_pre_save(void *opaque)
135449ab747fSPaolo Bonzini {
135549ab747fSPaolo Bonzini E1000State *s = opaque;
135649ab747fSPaolo Bonzini NetClientState *nc = qemu_get_queue(s->nic);
135749ab747fSPaolo Bonzini
135849ab747fSPaolo Bonzini /*
13596a2acedbSGabriel L. Somlo * If link is down and auto-negotiation is supported and ongoing,
13606a2acedbSGabriel L. Somlo * complete auto-negotiation immediately. This allows us to look
1361b7728c9fSAkihiko Odaki * at MII_BMSR_AN_COMP to infer link status on load.
136249ab747fSPaolo Bonzini */
1363d7a41552SGabriel L. Somlo if (nc->link_down && have_autoneg(s)) {
1364b7728c9fSAkihiko Odaki s->phy_reg[MII_BMSR] |= MII_BMSR_AN_COMP;
136549ab747fSPaolo Bonzini }
136644b1ff31SDr. David Alan Gilbert
1367ff214d42SDr. David Alan Gilbert /* Decide which set of props to migrate in the main structure */
1368ff214d42SDr. David Alan Gilbert if (chkflag(TSO) || !s->use_tso_for_migration) {
1369ff214d42SDr. David Alan Gilbert /* Either we're migrating with the extra subsection, in which
1370ff214d42SDr. David Alan Gilbert * case the mig_props is always 'props' OR
1371ff214d42SDr. David Alan Gilbert * we've not got the subsection, but 'props' was the last
1372ff214d42SDr. David Alan Gilbert * updated.
1373ff214d42SDr. David Alan Gilbert */
137459354484SDr. David Alan Gilbert s->mig_props = s->tx.props;
1375ff214d42SDr. David Alan Gilbert } else {
1376ff214d42SDr. David Alan Gilbert /* We're not using the subsection, and 'tso_props' was
1377ff214d42SDr. David Alan Gilbert * the last updated.
1378ff214d42SDr. David Alan Gilbert */
1379ff214d42SDr. David Alan Gilbert s->mig_props = s->tx.tso_props;
1380ff214d42SDr. David Alan Gilbert }
138144b1ff31SDr. David Alan Gilbert return 0;
138249ab747fSPaolo Bonzini }
138349ab747fSPaolo Bonzini
e1000_post_load(void * opaque,int version_id)138449ab747fSPaolo Bonzini static int e1000_post_load(void *opaque, int version_id)
138549ab747fSPaolo Bonzini {
138649ab747fSPaolo Bonzini E1000State *s = opaque;
138749ab747fSPaolo Bonzini NetClientState *nc = qemu_get_queue(s->nic);
138849ab747fSPaolo Bonzini
1389e9845f09SVincenzo Maffione s->mit_ide = 0;
1390f46efa9bSJason Wang s->mit_timer_on = true;
1391f46efa9bSJason Wang timer_mod(s->mit_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 1);
1392e9845f09SVincenzo Maffione
139349ab747fSPaolo Bonzini /* nc.link_down can't be migrated, so infer link_down according
139449ab747fSPaolo Bonzini * to link status bit in mac_reg[STATUS].
139549ab747fSPaolo Bonzini * Alternatively, restart link negotiation if it was in progress. */
139649ab747fSPaolo Bonzini nc->link_down = (s->mac_reg[STATUS] & E1000_STATUS_LU) == 0;
139749ab747fSPaolo Bonzini
1398b7728c9fSAkihiko Odaki if (have_autoneg(s) && !(s->phy_reg[MII_BMSR] & MII_BMSR_AN_COMP)) {
139949ab747fSPaolo Bonzini nc->link_down = false;
1400d7a41552SGabriel L. Somlo timer_mod(s->autoneg_timer,
1401d7a41552SGabriel L. Somlo qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 500);
140249ab747fSPaolo Bonzini }
140349ab747fSPaolo Bonzini
140459354484SDr. David Alan Gilbert s->tx.props = s->mig_props;
14053c4053c5SDr. David Alan Gilbert if (!s->received_tx_tso) {
14063c4053c5SDr. David Alan Gilbert /* We received only one set of offload data (tx.props)
14073c4053c5SDr. David Alan Gilbert * and haven't got tx.tso_props. The best we can do
14083c4053c5SDr. David Alan Gilbert * is dupe the data.
14093c4053c5SDr. David Alan Gilbert */
141059354484SDr. David Alan Gilbert s->tx.tso_props = s->mig_props;
14113c4053c5SDr. David Alan Gilbert }
14123c4053c5SDr. David Alan Gilbert return 0;
14133c4053c5SDr. David Alan Gilbert }
14143c4053c5SDr. David Alan Gilbert
e1000_tx_tso_post_load(void * opaque,int version_id)14153c4053c5SDr. David Alan Gilbert static int e1000_tx_tso_post_load(void *opaque, int version_id)
14163c4053c5SDr. David Alan Gilbert {
14173c4053c5SDr. David Alan Gilbert E1000State *s = opaque;
14183c4053c5SDr. David Alan Gilbert s->received_tx_tso = true;
141949ab747fSPaolo Bonzini return 0;
142049ab747fSPaolo Bonzini }
142149ab747fSPaolo Bonzini
e1000_full_mac_needed(void * opaque)14229e117734SLeonid Bloch static bool e1000_full_mac_needed(void *opaque)
14239e117734SLeonid Bloch {
14249e117734SLeonid Bloch E1000State *s = opaque;
14259e117734SLeonid Bloch
1426bc0f0674SLeonid Bloch return chkflag(MAC);
14279e117734SLeonid Bloch }
14289e117734SLeonid Bloch
e1000_tso_state_needed(void * opaque)142946f2a9ecSDr. David Alan Gilbert static bool e1000_tso_state_needed(void *opaque)
143046f2a9ecSDr. David Alan Gilbert {
143146f2a9ecSDr. David Alan Gilbert E1000State *s = opaque;
143246f2a9ecSDr. David Alan Gilbert
143346f2a9ecSDr. David Alan Gilbert return chkflag(TSO);
143446f2a9ecSDr. David Alan Gilbert }
143546f2a9ecSDr. David Alan Gilbert
1436e9845f09SVincenzo Maffione static const VMStateDescription vmstate_e1000_mit_state = {
1437e9845f09SVincenzo Maffione .name = "e1000/mit_state",
1438e9845f09SVincenzo Maffione .version_id = 1,
1439e9845f09SVincenzo Maffione .minimum_version_id = 1,
14401de81b42SRichard Henderson .fields = (const VMStateField[]) {
1441e9845f09SVincenzo Maffione VMSTATE_UINT32(mac_reg[RDTR], E1000State),
1442e9845f09SVincenzo Maffione VMSTATE_UINT32(mac_reg[RADV], E1000State),
1443e9845f09SVincenzo Maffione VMSTATE_UINT32(mac_reg[TADV], E1000State),
1444e9845f09SVincenzo Maffione VMSTATE_UINT32(mac_reg[ITR], E1000State),
1445e9845f09SVincenzo Maffione VMSTATE_BOOL(mit_irq_level, E1000State),
1446e9845f09SVincenzo Maffione VMSTATE_END_OF_LIST()
1447e9845f09SVincenzo Maffione }
1448e9845f09SVincenzo Maffione };
1449e9845f09SVincenzo Maffione
14509e117734SLeonid Bloch static const VMStateDescription vmstate_e1000_full_mac_state = {
14519e117734SLeonid Bloch .name = "e1000/full_mac_state",
14529e117734SLeonid Bloch .version_id = 1,
14539e117734SLeonid Bloch .minimum_version_id = 1,
14549e117734SLeonid Bloch .needed = e1000_full_mac_needed,
14551de81b42SRichard Henderson .fields = (const VMStateField[]) {
14569e117734SLeonid Bloch VMSTATE_UINT32_ARRAY(mac_reg, E1000State, 0x8000),
14579e117734SLeonid Bloch VMSTATE_END_OF_LIST()
14589e117734SLeonid Bloch }
14599e117734SLeonid Bloch };
14609e117734SLeonid Bloch
14614ae4bf5bSDr. David Alan Gilbert static const VMStateDescription vmstate_e1000_tx_tso_state = {
14624ae4bf5bSDr. David Alan Gilbert .name = "e1000/tx_tso_state",
14634ae4bf5bSDr. David Alan Gilbert .version_id = 1,
14644ae4bf5bSDr. David Alan Gilbert .minimum_version_id = 1,
146546f2a9ecSDr. David Alan Gilbert .needed = e1000_tso_state_needed,
14663c4053c5SDr. David Alan Gilbert .post_load = e1000_tx_tso_post_load,
14671de81b42SRichard Henderson .fields = (const VMStateField[]) {
14684ae4bf5bSDr. David Alan Gilbert VMSTATE_UINT8(tx.tso_props.ipcss, E1000State),
14694ae4bf5bSDr. David Alan Gilbert VMSTATE_UINT8(tx.tso_props.ipcso, E1000State),
14704ae4bf5bSDr. David Alan Gilbert VMSTATE_UINT16(tx.tso_props.ipcse, E1000State),
14714ae4bf5bSDr. David Alan Gilbert VMSTATE_UINT8(tx.tso_props.tucss, E1000State),
14724ae4bf5bSDr. David Alan Gilbert VMSTATE_UINT8(tx.tso_props.tucso, E1000State),
14734ae4bf5bSDr. David Alan Gilbert VMSTATE_UINT16(tx.tso_props.tucse, E1000State),
14744ae4bf5bSDr. David Alan Gilbert VMSTATE_UINT32(tx.tso_props.paylen, E1000State),
14754ae4bf5bSDr. David Alan Gilbert VMSTATE_UINT8(tx.tso_props.hdr_len, E1000State),
14764ae4bf5bSDr. David Alan Gilbert VMSTATE_UINT16(tx.tso_props.mss, E1000State),
14774ae4bf5bSDr. David Alan Gilbert VMSTATE_INT8(tx.tso_props.ip, E1000State),
14784ae4bf5bSDr. David Alan Gilbert VMSTATE_INT8(tx.tso_props.tcp, E1000State),
14794ae4bf5bSDr. David Alan Gilbert VMSTATE_END_OF_LIST()
14804ae4bf5bSDr. David Alan Gilbert }
14814ae4bf5bSDr. David Alan Gilbert };
14824ae4bf5bSDr. David Alan Gilbert
148349ab747fSPaolo Bonzini static const VMStateDescription vmstate_e1000 = {
148449ab747fSPaolo Bonzini .name = "e1000",
14854ae4bf5bSDr. David Alan Gilbert .version_id = 2,
148649ab747fSPaolo Bonzini .minimum_version_id = 1,
148749ab747fSPaolo Bonzini .pre_save = e1000_pre_save,
148849ab747fSPaolo Bonzini .post_load = e1000_post_load,
14891de81b42SRichard Henderson .fields = (const VMStateField[]) {
1490b08340d5SAndreas Färber VMSTATE_PCI_DEVICE(parent_obj, E1000State),
149149ab747fSPaolo Bonzini VMSTATE_UNUSED_TEST(is_version_1, 4), /* was instance id */
149249ab747fSPaolo Bonzini VMSTATE_UNUSED(4), /* Was mmio_base. */
149349ab747fSPaolo Bonzini VMSTATE_UINT32(rxbuf_size, E1000State),
149449ab747fSPaolo Bonzini VMSTATE_UINT32(rxbuf_min_shift, E1000State),
149549ab747fSPaolo Bonzini VMSTATE_UINT32(eecd_state.val_in, E1000State),
149649ab747fSPaolo Bonzini VMSTATE_UINT16(eecd_state.bitnum_in, E1000State),
149749ab747fSPaolo Bonzini VMSTATE_UINT16(eecd_state.bitnum_out, E1000State),
149849ab747fSPaolo Bonzini VMSTATE_UINT16(eecd_state.reading, E1000State),
149949ab747fSPaolo Bonzini VMSTATE_UINT32(eecd_state.old_eecd, E1000State),
150059354484SDr. David Alan Gilbert VMSTATE_UINT8(mig_props.ipcss, E1000State),
150159354484SDr. David Alan Gilbert VMSTATE_UINT8(mig_props.ipcso, E1000State),
150259354484SDr. David Alan Gilbert VMSTATE_UINT16(mig_props.ipcse, E1000State),
150359354484SDr. David Alan Gilbert VMSTATE_UINT8(mig_props.tucss, E1000State),
150459354484SDr. David Alan Gilbert VMSTATE_UINT8(mig_props.tucso, E1000State),
150559354484SDr. David Alan Gilbert VMSTATE_UINT16(mig_props.tucse, E1000State),
150659354484SDr. David Alan Gilbert VMSTATE_UINT32(mig_props.paylen, E1000State),
150759354484SDr. David Alan Gilbert VMSTATE_UINT8(mig_props.hdr_len, E1000State),
150859354484SDr. David Alan Gilbert VMSTATE_UINT16(mig_props.mss, E1000State),
150949ab747fSPaolo Bonzini VMSTATE_UINT16(tx.size, E1000State),
151049ab747fSPaolo Bonzini VMSTATE_UINT16(tx.tso_frames, E1000State),
15117d08c73eSEd Swierk via Qemu-devel VMSTATE_UINT8(tx.sum_needed, E1000State),
151259354484SDr. David Alan Gilbert VMSTATE_INT8(mig_props.ip, E1000State),
151359354484SDr. David Alan Gilbert VMSTATE_INT8(mig_props.tcp, E1000State),
151449ab747fSPaolo Bonzini VMSTATE_BUFFER(tx.header, E1000State),
151549ab747fSPaolo Bonzini VMSTATE_BUFFER(tx.data, E1000State),
151649ab747fSPaolo Bonzini VMSTATE_UINT16_ARRAY(eeprom_data, E1000State, 64),
151749ab747fSPaolo Bonzini VMSTATE_UINT16_ARRAY(phy_reg, E1000State, 0x20),
151849ab747fSPaolo Bonzini VMSTATE_UINT32(mac_reg[CTRL], E1000State),
151949ab747fSPaolo Bonzini VMSTATE_UINT32(mac_reg[EECD], E1000State),
152049ab747fSPaolo Bonzini VMSTATE_UINT32(mac_reg[EERD], E1000State),
152149ab747fSPaolo Bonzini VMSTATE_UINT32(mac_reg[GPRC], E1000State),
152249ab747fSPaolo Bonzini VMSTATE_UINT32(mac_reg[GPTC], E1000State),
152349ab747fSPaolo Bonzini VMSTATE_UINT32(mac_reg[ICR], E1000State),
152449ab747fSPaolo Bonzini VMSTATE_UINT32(mac_reg[ICS], E1000State),
152549ab747fSPaolo Bonzini VMSTATE_UINT32(mac_reg[IMC], E1000State),
152649ab747fSPaolo Bonzini VMSTATE_UINT32(mac_reg[IMS], E1000State),
152749ab747fSPaolo Bonzini VMSTATE_UINT32(mac_reg[LEDCTL], E1000State),
152849ab747fSPaolo Bonzini VMSTATE_UINT32(mac_reg[MANC], E1000State),
152949ab747fSPaolo Bonzini VMSTATE_UINT32(mac_reg[MDIC], E1000State),
153049ab747fSPaolo Bonzini VMSTATE_UINT32(mac_reg[MPC], E1000State),
153149ab747fSPaolo Bonzini VMSTATE_UINT32(mac_reg[PBA], E1000State),
153249ab747fSPaolo Bonzini VMSTATE_UINT32(mac_reg[RCTL], E1000State),
153349ab747fSPaolo Bonzini VMSTATE_UINT32(mac_reg[RDBAH], E1000State),
153449ab747fSPaolo Bonzini VMSTATE_UINT32(mac_reg[RDBAL], E1000State),
153549ab747fSPaolo Bonzini VMSTATE_UINT32(mac_reg[RDH], E1000State),
153649ab747fSPaolo Bonzini VMSTATE_UINT32(mac_reg[RDLEN], E1000State),
153749ab747fSPaolo Bonzini VMSTATE_UINT32(mac_reg[RDT], E1000State),
153849ab747fSPaolo Bonzini VMSTATE_UINT32(mac_reg[STATUS], E1000State),
153949ab747fSPaolo Bonzini VMSTATE_UINT32(mac_reg[SWSM], E1000State),
154049ab747fSPaolo Bonzini VMSTATE_UINT32(mac_reg[TCTL], E1000State),
154149ab747fSPaolo Bonzini VMSTATE_UINT32(mac_reg[TDBAH], E1000State),
154249ab747fSPaolo Bonzini VMSTATE_UINT32(mac_reg[TDBAL], E1000State),
154349ab747fSPaolo Bonzini VMSTATE_UINT32(mac_reg[TDH], E1000State),
154449ab747fSPaolo Bonzini VMSTATE_UINT32(mac_reg[TDLEN], E1000State),
154549ab747fSPaolo Bonzini VMSTATE_UINT32(mac_reg[TDT], E1000State),
154649ab747fSPaolo Bonzini VMSTATE_UINT32(mac_reg[TORH], E1000State),
154749ab747fSPaolo Bonzini VMSTATE_UINT32(mac_reg[TORL], E1000State),
154849ab747fSPaolo Bonzini VMSTATE_UINT32(mac_reg[TOTH], E1000State),
154949ab747fSPaolo Bonzini VMSTATE_UINT32(mac_reg[TOTL], E1000State),
155049ab747fSPaolo Bonzini VMSTATE_UINT32(mac_reg[TPR], E1000State),
155149ab747fSPaolo Bonzini VMSTATE_UINT32(mac_reg[TPT], E1000State),
155249ab747fSPaolo Bonzini VMSTATE_UINT32(mac_reg[TXDCTL], E1000State),
155349ab747fSPaolo Bonzini VMSTATE_UINT32(mac_reg[WUFC], E1000State),
155449ab747fSPaolo Bonzini VMSTATE_UINT32(mac_reg[VET], E1000State),
155549ab747fSPaolo Bonzini VMSTATE_UINT32_SUB_ARRAY(mac_reg, E1000State, RA, 32),
15562fe63579SAkihiko Odaki VMSTATE_UINT32_SUB_ARRAY(mac_reg, E1000State, MTA, E1000_MC_TBL_SIZE),
15572fe63579SAkihiko Odaki VMSTATE_UINT32_SUB_ARRAY(mac_reg, E1000State, VFTA,
15582fe63579SAkihiko Odaki E1000_VLAN_FILTER_TBL_SIZE),
155949ab747fSPaolo Bonzini VMSTATE_END_OF_LIST()
1560e9845f09SVincenzo Maffione },
15611de81b42SRichard Henderson .subsections = (const VMStateDescription * const []) {
15625cd8cadaSJuan Quintela &vmstate_e1000_mit_state,
15639e117734SLeonid Bloch &vmstate_e1000_full_mac_state,
15644ae4bf5bSDr. David Alan Gilbert &vmstate_e1000_tx_tso_state,
15655cd8cadaSJuan Quintela NULL
156649ab747fSPaolo Bonzini }
156749ab747fSPaolo Bonzini };
156849ab747fSPaolo Bonzini
15698597f2e1SGabriel L. Somlo /*
15708597f2e1SGabriel L. Somlo * EEPROM contents documented in Tables 5-2 and 5-3, pp. 98-102.
157180867bdbSPhilippe Mathieu-Daudé * Note: A valid DevId will be inserted during pci_e1000_realize().
15728597f2e1SGabriel L. Somlo */
157349ab747fSPaolo Bonzini static const uint16_t e1000_eeprom_template[64] = {
157449ab747fSPaolo Bonzini 0x0000, 0x0000, 0x0000, 0x0000, 0xffff, 0x0000, 0x0000, 0x0000,
15758597f2e1SGabriel L. Somlo 0x3000, 0x1000, 0x6403, 0 /*DevId*/, 0x8086, 0 /*DevId*/, 0x8086, 0x3040,
157649ab747fSPaolo Bonzini 0x0008, 0x2000, 0x7e14, 0x0048, 0x1000, 0x00d8, 0x0000, 0x2700,
157749ab747fSPaolo Bonzini 0x6cc9, 0x3150, 0x0722, 0x040b, 0x0984, 0x0000, 0xc000, 0x0706,
157849ab747fSPaolo Bonzini 0x1008, 0x0000, 0x0f04, 0x7fff, 0x4d01, 0xffff, 0xffff, 0xffff,
157949ab747fSPaolo Bonzini 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
158049ab747fSPaolo Bonzini 0x0100, 0x4000, 0x121c, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
158149ab747fSPaolo Bonzini 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x0000,
158249ab747fSPaolo Bonzini };
158349ab747fSPaolo Bonzini
158449ab747fSPaolo Bonzini /* PCI interface */
158549ab747fSPaolo Bonzini
158649ab747fSPaolo Bonzini static void
e1000_mmio_setup(E1000State * d)158749ab747fSPaolo Bonzini e1000_mmio_setup(E1000State *d)
158849ab747fSPaolo Bonzini {
158949ab747fSPaolo Bonzini int i;
159049ab747fSPaolo Bonzini const uint32_t excluded_regs[] = {
159149ab747fSPaolo Bonzini E1000_MDIC, E1000_ICR, E1000_ICS, E1000_IMS,
159249ab747fSPaolo Bonzini E1000_IMC, E1000_TCTL, E1000_TDT, PNPMMIO_SIZE
159349ab747fSPaolo Bonzini };
159449ab747fSPaolo Bonzini
1595eedfac6fSPaolo Bonzini memory_region_init_io(&d->mmio, OBJECT(d), &e1000_mmio_ops, d,
1596eedfac6fSPaolo Bonzini "e1000-mmio", PNPMMIO_SIZE);
159749ab747fSPaolo Bonzini memory_region_add_coalescing(&d->mmio, 0, excluded_regs[0]);
159849ab747fSPaolo Bonzini for (i = 0; excluded_regs[i] != PNPMMIO_SIZE; i++)
159949ab747fSPaolo Bonzini memory_region_add_coalescing(&d->mmio, excluded_regs[i] + 4,
160049ab747fSPaolo Bonzini excluded_regs[i+1] - excluded_regs[i] - 4);
1601eedfac6fSPaolo Bonzini memory_region_init_io(&d->io, OBJECT(d), &e1000_io_ops, d, "e1000-io", IOPORT_SIZE);
160249ab747fSPaolo Bonzini }
160349ab747fSPaolo Bonzini
160449ab747fSPaolo Bonzini static void
pci_e1000_uninit(PCIDevice * dev)160549ab747fSPaolo Bonzini pci_e1000_uninit(PCIDevice *dev)
160649ab747fSPaolo Bonzini {
1607567a3c9eSPeter Crosthwaite E1000State *d = E1000(dev);
160849ab747fSPaolo Bonzini
1609bc72ad67SAlex Bligh timer_free(d->autoneg_timer);
1610e9845f09SVincenzo Maffione timer_free(d->mit_timer);
1611157628d0Syuchenlin timer_free(d->flush_queue_timer);
161249ab747fSPaolo Bonzini qemu_del_nic(d->nic);
161349ab747fSPaolo Bonzini }
161449ab747fSPaolo Bonzini
161549ab747fSPaolo Bonzini static NetClientInfo net_e1000_info = {
1616f394b2e2SEric Blake .type = NET_CLIENT_DRIVER_NIC,
161749ab747fSPaolo Bonzini .size = sizeof(NICState),
161849ab747fSPaolo Bonzini .can_receive = e1000_can_receive,
161949ab747fSPaolo Bonzini .receive = e1000_receive,
162097410ddeSVincenzo Maffione .receive_iov = e1000_receive_iov,
162149ab747fSPaolo Bonzini .link_status_changed = e1000_set_link_status,
162249ab747fSPaolo Bonzini };
162349ab747fSPaolo Bonzini
e1000_write_config(PCIDevice * pci_dev,uint32_t address,uint32_t val,int len)162420302e71SMichael S. Tsirkin static void e1000_write_config(PCIDevice *pci_dev, uint32_t address,
162520302e71SMichael S. Tsirkin uint32_t val, int len)
162620302e71SMichael S. Tsirkin {
162720302e71SMichael S. Tsirkin E1000State *s = E1000(pci_dev);
162820302e71SMichael S. Tsirkin
162920302e71SMichael S. Tsirkin pci_default_write_config(pci_dev, address, val, len);
163020302e71SMichael S. Tsirkin
163120302e71SMichael S. Tsirkin if (range_covers_byte(address, len, PCI_COMMAND) &&
163220302e71SMichael S. Tsirkin (pci_dev->config[PCI_COMMAND] & PCI_COMMAND_MASTER)) {
163320302e71SMichael S. Tsirkin qemu_flush_queued_packets(qemu_get_queue(s->nic));
163420302e71SMichael S. Tsirkin }
163520302e71SMichael S. Tsirkin }
163620302e71SMichael S. Tsirkin
pci_e1000_realize(PCIDevice * pci_dev,Error ** errp)16379af21dbeSMarkus Armbruster static void pci_e1000_realize(PCIDevice *pci_dev, Error **errp)
163849ab747fSPaolo Bonzini {
1639567a3c9eSPeter Crosthwaite DeviceState *dev = DEVICE(pci_dev);
1640567a3c9eSPeter Crosthwaite E1000State *d = E1000(pci_dev);
164149ab747fSPaolo Bonzini uint8_t *pci_conf;
164249ab747fSPaolo Bonzini uint8_t *macaddr;
164349ab747fSPaolo Bonzini
164420302e71SMichael S. Tsirkin pci_dev->config_write = e1000_write_config;
164520302e71SMichael S. Tsirkin
1646b08340d5SAndreas Färber pci_conf = pci_dev->config;
164749ab747fSPaolo Bonzini
164849ab747fSPaolo Bonzini /* TODO: RST# value should be 0, PCI spec 6.2.4 */
164949ab747fSPaolo Bonzini pci_conf[PCI_CACHE_LINE_SIZE] = 0x10;
165049ab747fSPaolo Bonzini
165149ab747fSPaolo Bonzini pci_conf[PCI_INTERRUPT_PIN] = 1; /* interrupt pin A */
165249ab747fSPaolo Bonzini
165349ab747fSPaolo Bonzini e1000_mmio_setup(d);
165449ab747fSPaolo Bonzini
1655b08340d5SAndreas Färber pci_register_bar(pci_dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &d->mmio);
165649ab747fSPaolo Bonzini
1657b08340d5SAndreas Färber pci_register_bar(pci_dev, 1, PCI_BASE_ADDRESS_SPACE_IO, &d->io);
165849ab747fSPaolo Bonzini
165949ab747fSPaolo Bonzini qemu_macaddr_default_if_unset(&d->conf.macaddr);
166049ab747fSPaolo Bonzini macaddr = d->conf.macaddr.a;
1661093454e2SDmitry Fleytman
1662093454e2SDmitry Fleytman e1000x_core_prepare_eeprom(d->eeprom_data,
1663093454e2SDmitry Fleytman e1000_eeprom_template,
1664093454e2SDmitry Fleytman sizeof(e1000_eeprom_template),
1665093454e2SDmitry Fleytman PCI_DEVICE_GET_CLASS(pci_dev)->device_id,
1666093454e2SDmitry Fleytman macaddr);
166749ab747fSPaolo Bonzini
166849ab747fSPaolo Bonzini d->nic = qemu_new_nic(&net_e1000_info, &d->conf,
16697d0fefdfSAkihiko Odaki object_get_typename(OBJECT(d)), dev->id,
16707d0fefdfSAkihiko Odaki &dev->mem_reentrancy_guard, d);
167149ab747fSPaolo Bonzini
167249ab747fSPaolo Bonzini qemu_format_nic_info_str(qemu_get_queue(d->nic), macaddr);
167349ab747fSPaolo Bonzini
1674bc72ad67SAlex Bligh d->autoneg_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, e1000_autoneg_timer, d);
1675e9845f09SVincenzo Maffione d->mit_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, e1000_mit_timer, d);
1676157628d0Syuchenlin d->flush_queue_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL,
1677157628d0Syuchenlin e1000_flush_queue_timer, d);
167849ab747fSPaolo Bonzini }
167949ab747fSPaolo Bonzini
168049ab747fSPaolo Bonzini static Property e1000_properties[] = {
168149ab747fSPaolo Bonzini DEFINE_NIC_PROPERTIES(E1000State, conf),
1682ba63ec85SLeonid Bloch DEFINE_PROP_BIT("extra_mac_registers", E1000State,
1683ba63ec85SLeonid Bloch compat_flags, E1000_FLAG_MAC_BIT, true),
168446f2a9ecSDr. David Alan Gilbert DEFINE_PROP_BIT("migrate_tso_props", E1000State,
168546f2a9ecSDr. David Alan Gilbert compat_flags, E1000_FLAG_TSO_BIT, true),
1686a1d7e475SChristina Wang DEFINE_PROP_BIT("init-vet", E1000State,
1687a1d7e475SChristina Wang compat_flags, E1000_FLAG_VET_BIT, true),
168849ab747fSPaolo Bonzini DEFINE_PROP_END_OF_LIST(),
168949ab747fSPaolo Bonzini };
169049ab747fSPaolo Bonzini
16918597f2e1SGabriel L. Somlo typedef struct E1000Info {
16928597f2e1SGabriel L. Somlo const char *name;
16938597f2e1SGabriel L. Somlo uint16_t device_id;
16948597f2e1SGabriel L. Somlo uint8_t revision;
16958597f2e1SGabriel L. Somlo uint16_t phy_id2;
16968597f2e1SGabriel L. Somlo } E1000Info;
16978597f2e1SGabriel L. Somlo
e1000_class_init(ObjectClass * klass,void * data)169849ab747fSPaolo Bonzini static void e1000_class_init(ObjectClass *klass, void *data)
169949ab747fSPaolo Bonzini {
170049ab747fSPaolo Bonzini DeviceClass *dc = DEVICE_CLASS(klass);
17019d465053SAkihiko Odaki ResettableClass *rc = RESETTABLE_CLASS(klass);
170249ab747fSPaolo Bonzini PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
1703c51325d8SEduardo Habkost E1000BaseClass *e = E1000_CLASS(klass);
17048597f2e1SGabriel L. Somlo const E1000Info *info = data;
170549ab747fSPaolo Bonzini
17069af21dbeSMarkus Armbruster k->realize = pci_e1000_realize;
170749ab747fSPaolo Bonzini k->exit = pci_e1000_uninit;
170849ab747fSPaolo Bonzini k->romfile = "efi-e1000.rom";
170949ab747fSPaolo Bonzini k->vendor_id = PCI_VENDOR_ID_INTEL;
17108597f2e1SGabriel L. Somlo k->device_id = info->device_id;
17118597f2e1SGabriel L. Somlo k->revision = info->revision;
17128597f2e1SGabriel L. Somlo e->phy_id2 = info->phy_id2;
171349ab747fSPaolo Bonzini k->class_id = PCI_CLASS_NETWORK_ETHERNET;
17149d465053SAkihiko Odaki rc->phases.hold = e1000_reset_hold;
1715125ee0edSMarcel Apfelbaum set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
171649ab747fSPaolo Bonzini dc->desc = "Intel Gigabit Ethernet";
171749ab747fSPaolo Bonzini dc->vmsd = &vmstate_e1000;
17184f67d30bSMarc-André Lureau device_class_set_props(dc, e1000_properties);
171949ab747fSPaolo Bonzini }
172049ab747fSPaolo Bonzini
e1000_instance_init(Object * obj)17215df3bf62SGonglei static void e1000_instance_init(Object *obj)
17225df3bf62SGonglei {
17235df3bf62SGonglei E1000State *n = E1000(obj);
17245df3bf62SGonglei device_add_bootindex_property(obj, &n->conf.bootindex,
17255df3bf62SGonglei "bootindex", "/ethernet-phy@0",
172640c2281cSMarkus Armbruster DEVICE(n));
17275df3bf62SGonglei }
17285df3bf62SGonglei
17298597f2e1SGabriel L. Somlo static const TypeInfo e1000_base_info = {
17308597f2e1SGabriel L. Somlo .name = TYPE_E1000_BASE,
173149ab747fSPaolo Bonzini .parent = TYPE_PCI_DEVICE,
173249ab747fSPaolo Bonzini .instance_size = sizeof(E1000State),
17335df3bf62SGonglei .instance_init = e1000_instance_init,
17348597f2e1SGabriel L. Somlo .class_size = sizeof(E1000BaseClass),
17358597f2e1SGabriel L. Somlo .abstract = true,
1736fd3b02c8SEduardo Habkost .interfaces = (InterfaceInfo[]) {
1737fd3b02c8SEduardo Habkost { INTERFACE_CONVENTIONAL_PCI_DEVICE },
1738fd3b02c8SEduardo Habkost { },
1739fd3b02c8SEduardo Habkost },
17408597f2e1SGabriel L. Somlo };
17418597f2e1SGabriel L. Somlo
17428597f2e1SGabriel L. Somlo static const E1000Info e1000_devices[] = {
17438597f2e1SGabriel L. Somlo {
174483044020SJason Wang .name = "e1000",
17458597f2e1SGabriel L. Somlo .device_id = E1000_DEV_ID_82540EM,
17468597f2e1SGabriel L. Somlo .revision = 0x03,
17478597f2e1SGabriel L. Somlo .phy_id2 = E1000_PHY_ID2_8254xx_DEFAULT,
17488597f2e1SGabriel L. Somlo },
17498597f2e1SGabriel L. Somlo {
17508597f2e1SGabriel L. Somlo .name = "e1000-82544gc",
17518597f2e1SGabriel L. Somlo .device_id = E1000_DEV_ID_82544GC_COPPER,
17528597f2e1SGabriel L. Somlo .revision = 0x03,
17538597f2e1SGabriel L. Somlo .phy_id2 = E1000_PHY_ID2_82544x,
17548597f2e1SGabriel L. Somlo },
17558597f2e1SGabriel L. Somlo {
17568597f2e1SGabriel L. Somlo .name = "e1000-82545em",
17578597f2e1SGabriel L. Somlo .device_id = E1000_DEV_ID_82545EM_COPPER,
17588597f2e1SGabriel L. Somlo .revision = 0x03,
17598597f2e1SGabriel L. Somlo .phy_id2 = E1000_PHY_ID2_8254xx_DEFAULT,
17608597f2e1SGabriel L. Somlo },
17618597f2e1SGabriel L. Somlo };
17628597f2e1SGabriel L. Somlo
e1000_register_types(void)176349ab747fSPaolo Bonzini static void e1000_register_types(void)
176449ab747fSPaolo Bonzini {
17658597f2e1SGabriel L. Somlo int i;
17668597f2e1SGabriel L. Somlo
17678597f2e1SGabriel L. Somlo type_register_static(&e1000_base_info);
17688597f2e1SGabriel L. Somlo for (i = 0; i < ARRAY_SIZE(e1000_devices); i++) {
17698597f2e1SGabriel L. Somlo const E1000Info *info = &e1000_devices[i];
17708597f2e1SGabriel L. Somlo TypeInfo type_info = {};
17718597f2e1SGabriel L. Somlo
17728597f2e1SGabriel L. Somlo type_info.name = info->name;
17738597f2e1SGabriel L. Somlo type_info.parent = TYPE_E1000_BASE;
17748597f2e1SGabriel L. Somlo type_info.class_data = (void *)info;
17758597f2e1SGabriel L. Somlo type_info.class_init = e1000_class_init;
17768597f2e1SGabriel L. Somlo
17778597f2e1SGabriel L. Somlo type_register(&type_info);
17788597f2e1SGabriel L. Somlo }
177949ab747fSPaolo Bonzini }
178049ab747fSPaolo Bonzini
178149ab747fSPaolo Bonzini type_init(e1000_register_types)
1782