xref: /openbmc/qemu/hw/net/e1000.c (revision 83baec642a13a69398a2643a1f905606c13cd363)
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