xref: /qemu/hw/net/e1000.c (revision e8d40465592716cb209f0ae5de6b4cbe9ea2f8ba)
17c23b892Sbalrog /*
27c23b892Sbalrog  * QEMU e1000 emulation
37c23b892Sbalrog  *
42758aa52SMichael S. Tsirkin  * Software developer's manual:
52758aa52SMichael S. Tsirkin  * http://download.intel.com/design/network/manuals/8254x_GBe_SDM.pdf
62758aa52SMichael S. Tsirkin  *
77c23b892Sbalrog  * Nir Peleg, Tutis Systems Ltd. for Qumranet Inc.
87c23b892Sbalrog  * Copyright (c) 2008 Qumranet
97c23b892Sbalrog  * Based on work done by:
107c23b892Sbalrog  * Copyright (c) 2007 Dan Aloni
117c23b892Sbalrog  * Copyright (c) 2004 Antony T Curtis
127c23b892Sbalrog  *
137c23b892Sbalrog  * This library is free software; you can redistribute it and/or
147c23b892Sbalrog  * modify it under the terms of the GNU Lesser General Public
157c23b892Sbalrog  * License as published by the Free Software Foundation; either
167c23b892Sbalrog  * version 2 of the License, or (at your option) any later version.
177c23b892Sbalrog  *
187c23b892Sbalrog  * This library is distributed in the hope that it will be useful,
197c23b892Sbalrog  * but WITHOUT ANY WARRANTY; without even the implied warranty of
207c23b892Sbalrog  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
217c23b892Sbalrog  * Lesser General Public License for more details.
227c23b892Sbalrog  *
237c23b892Sbalrog  * You should have received a copy of the GNU Lesser General Public
248167ee88SBlue Swirl  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
257c23b892Sbalrog  */
267c23b892Sbalrog 
277c23b892Sbalrog 
28*e8d40465SPeter Maydell #include "qemu/osdep.h"
2983c9f4caSPaolo Bonzini #include "hw/hw.h"
3083c9f4caSPaolo Bonzini #include "hw/pci/pci.h"
311422e32dSPaolo Bonzini #include "net/net.h"
327200ac3cSMark McLoughlin #include "net/checksum.h"
3383c9f4caSPaolo Bonzini #include "hw/loader.h"
349c17d615SPaolo Bonzini #include "sysemu/sysemu.h"
359c17d615SPaolo Bonzini #include "sysemu/dma.h"
3697410ddeSVincenzo Maffione #include "qemu/iov.h"
3720302e71SMichael S. Tsirkin #include "qemu/range.h"
387c23b892Sbalrog 
3947b43a1fSPaolo Bonzini #include "e1000_regs.h"
407c23b892Sbalrog 
413b274301SLeonid Bloch static const uint8_t bcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
423b274301SLeonid Bloch 
4327124888SJes Sorensen #define E1000_DEBUG
447c23b892Sbalrog 
4527124888SJes Sorensen #ifdef E1000_DEBUG
467c23b892Sbalrog enum {
477c23b892Sbalrog     DEBUG_GENERAL,      DEBUG_IO,       DEBUG_MMIO,     DEBUG_INTERRUPT,
487c23b892Sbalrog     DEBUG_RX,           DEBUG_TX,       DEBUG_MDIC,     DEBUG_EEPROM,
497c23b892Sbalrog     DEBUG_UNKNOWN,      DEBUG_TXSUM,    DEBUG_TXERR,    DEBUG_RXERR,
50f9c1cdf4SJason Wang     DEBUG_RXFILTER,     DEBUG_PHY,      DEBUG_NOTYET,
517c23b892Sbalrog };
527c23b892Sbalrog #define DBGBIT(x)    (1<<DEBUG_##x)
537c23b892Sbalrog static int debugflags = DBGBIT(TXERR) | DBGBIT(GENERAL);
547c23b892Sbalrog 
556c7f4b47SBlue Swirl #define DBGOUT(what, fmt, ...) do { \
567c23b892Sbalrog     if (debugflags & DBGBIT(what)) \
576c7f4b47SBlue Swirl         fprintf(stderr, "e1000: " fmt, ## __VA_ARGS__); \
587c23b892Sbalrog     } while (0)
597c23b892Sbalrog #else
606c7f4b47SBlue Swirl #define DBGOUT(what, fmt, ...) do {} while (0)
617c23b892Sbalrog #endif
627c23b892Sbalrog 
637c23b892Sbalrog #define IOPORT_SIZE       0x40
64e94bbefeSaurel32 #define PNPMMIO_SIZE      0x20000
6578aeb23eSStefan Hajnoczi #define MIN_BUF_SIZE      60 /* Min. octets in an ethernet frame sans FCS */
667c23b892Sbalrog 
67b0d9ffcdSMichael Contreras /* this is the size past which hardware will drop packets when setting LPE=0 */
68b0d9ffcdSMichael Contreras #define MAXIMUM_ETHERNET_VLAN_SIZE 1522
692c0331f4SMichael Contreras /* this is the size past which hardware will drop packets when setting LPE=1 */
702c0331f4SMichael Contreras #define MAXIMUM_ETHERNET_LPE_SIZE 16384
71b0d9ffcdSMichael Contreras 
7297410ddeSVincenzo Maffione #define MAXIMUM_ETHERNET_HDR_LEN (14+4)
7397410ddeSVincenzo Maffione 
747c23b892Sbalrog /*
757c23b892Sbalrog  * HW models:
768597f2e1SGabriel L. Somlo  *  E1000_DEV_ID_82540EM works with Windows, Linux, and OS X <= 10.8
777c23b892Sbalrog  *  E1000_DEV_ID_82544GC_COPPER appears to work; not well tested
788597f2e1SGabriel L. Somlo  *  E1000_DEV_ID_82545EM_COPPER works with Linux and OS X >= 10.6
797c23b892Sbalrog  *  Others never tested
807c23b892Sbalrog  */
817c23b892Sbalrog 
827c23b892Sbalrog typedef struct E1000State_st {
83b08340d5SAndreas Färber     /*< private >*/
84b08340d5SAndreas Färber     PCIDevice parent_obj;
85b08340d5SAndreas Färber     /*< public >*/
86b08340d5SAndreas Färber 
87a03e2aecSMark McLoughlin     NICState *nic;
88fbdaa002SGerd Hoffmann     NICConf conf;
89ad00a9b9SAvi Kivity     MemoryRegion mmio;
90ad00a9b9SAvi Kivity     MemoryRegion io;
917c23b892Sbalrog 
927c23b892Sbalrog     uint32_t mac_reg[0x8000];
937c23b892Sbalrog     uint16_t phy_reg[0x20];
947c23b892Sbalrog     uint16_t eeprom_data[64];
957c23b892Sbalrog 
967c23b892Sbalrog     uint32_t rxbuf_size;
977c23b892Sbalrog     uint32_t rxbuf_min_shift;
987c23b892Sbalrog     struct e1000_tx {
997c23b892Sbalrog         unsigned char header[256];
1008f2e8d1fSaliguori         unsigned char vlan_header[4];
101b10fec9bSStefan Weil         /* Fields vlan and data must not be reordered or separated. */
1028f2e8d1fSaliguori         unsigned char vlan[4];
1037c23b892Sbalrog         unsigned char data[0x10000];
1047c23b892Sbalrog         uint16_t size;
1057c23b892Sbalrog         unsigned char sum_needed;
1068f2e8d1fSaliguori         unsigned char vlan_needed;
1077c23b892Sbalrog         uint8_t ipcss;
1087c23b892Sbalrog         uint8_t ipcso;
1097c23b892Sbalrog         uint16_t ipcse;
1107c23b892Sbalrog         uint8_t tucss;
1117c23b892Sbalrog         uint8_t tucso;
1127c23b892Sbalrog         uint16_t tucse;
1137c23b892Sbalrog         uint8_t hdr_len;
1147c23b892Sbalrog         uint16_t mss;
1157c23b892Sbalrog         uint32_t paylen;
1167c23b892Sbalrog         uint16_t tso_frames;
1177c23b892Sbalrog         char tse;
118b6c4f71fSblueswir1         int8_t ip;
119b6c4f71fSblueswir1         int8_t tcp;
1201b0009dbSbalrog         char cptse;     // current packet tse bit
1217c23b892Sbalrog     } tx;
1227c23b892Sbalrog 
1237c23b892Sbalrog     struct {
12420f3e863SLeonid Bloch         uint32_t val_in;    /* shifted in from guest driver */
1257c23b892Sbalrog         uint16_t bitnum_in;
1267c23b892Sbalrog         uint16_t bitnum_out;
1277c23b892Sbalrog         uint16_t reading;
1287c23b892Sbalrog         uint32_t old_eecd;
1297c23b892Sbalrog     } eecd_state;
130b9d03e35SJason Wang 
131b9d03e35SJason Wang     QEMUTimer *autoneg_timer;
1322af234e6SMichael S. Tsirkin 
133e9845f09SVincenzo Maffione     QEMUTimer *mit_timer;      /* Mitigation timer. */
134e9845f09SVincenzo Maffione     bool mit_timer_on;         /* Mitigation timer is running. */
135e9845f09SVincenzo Maffione     bool mit_irq_level;        /* Tracks interrupt pin level. */
136e9845f09SVincenzo Maffione     uint32_t mit_ide;          /* Tracks E1000_TXD_CMD_IDE bit. */
137e9845f09SVincenzo Maffione 
1382af234e6SMichael S. Tsirkin /* Compatibility flags for migration to/from qemu 1.3.0 and older */
1392af234e6SMichael S. Tsirkin #define E1000_FLAG_AUTONEG_BIT 0
140e9845f09SVincenzo Maffione #define E1000_FLAG_MIT_BIT 1
1419e117734SLeonid Bloch #define E1000_FLAG_MAC_BIT 2
1422af234e6SMichael S. Tsirkin #define E1000_FLAG_AUTONEG (1 << E1000_FLAG_AUTONEG_BIT)
143e9845f09SVincenzo Maffione #define E1000_FLAG_MIT (1 << E1000_FLAG_MIT_BIT)
1449e117734SLeonid Bloch #define E1000_FLAG_MAC (1 << E1000_FLAG_MAC_BIT)
1452af234e6SMichael S. Tsirkin     uint32_t compat_flags;
1467c23b892Sbalrog } E1000State;
1477c23b892Sbalrog 
148bc0f0674SLeonid Bloch #define chkflag(x)     (s->compat_flags & E1000_FLAG_##x)
149bc0f0674SLeonid Bloch 
1508597f2e1SGabriel L. Somlo typedef struct E1000BaseClass {
1518597f2e1SGabriel L. Somlo     PCIDeviceClass parent_class;
1528597f2e1SGabriel L. Somlo     uint16_t phy_id2;
1538597f2e1SGabriel L. Somlo } E1000BaseClass;
1548597f2e1SGabriel L. Somlo 
1558597f2e1SGabriel L. Somlo #define TYPE_E1000_BASE "e1000-base"
156567a3c9eSPeter Crosthwaite 
157567a3c9eSPeter Crosthwaite #define E1000(obj) \
1588597f2e1SGabriel L. Somlo     OBJECT_CHECK(E1000State, (obj), TYPE_E1000_BASE)
1598597f2e1SGabriel L. Somlo 
1608597f2e1SGabriel L. Somlo #define E1000_DEVICE_CLASS(klass) \
1618597f2e1SGabriel L. Somlo      OBJECT_CLASS_CHECK(E1000BaseClass, (klass), TYPE_E1000_BASE)
1628597f2e1SGabriel L. Somlo #define E1000_DEVICE_GET_CLASS(obj) \
1638597f2e1SGabriel L. Somlo     OBJECT_GET_CLASS(E1000BaseClass, (obj), TYPE_E1000_BASE)
164567a3c9eSPeter Crosthwaite 
1657c23b892Sbalrog #define defreg(x)    x = (E1000_##x>>2)
1667c23b892Sbalrog enum {
1677c23b892Sbalrog     defreg(CTRL),    defreg(EECD),    defreg(EERD),    defreg(GPRC),
1687c23b892Sbalrog     defreg(GPTC),    defreg(ICR),     defreg(ICS),     defreg(IMC),
1697c23b892Sbalrog     defreg(IMS),     defreg(LEDCTL),  defreg(MANC),    defreg(MDIC),
1707c23b892Sbalrog     defreg(MPC),     defreg(PBA),     defreg(RCTL),    defreg(RDBAH),
1717c23b892Sbalrog     defreg(RDBAL),   defreg(RDH),     defreg(RDLEN),   defreg(RDT),
1727c23b892Sbalrog     defreg(STATUS),  defreg(SWSM),    defreg(TCTL),    defreg(TDBAH),
1737c23b892Sbalrog     defreg(TDBAL),   defreg(TDH),     defreg(TDLEN),   defreg(TDT),
1747c23b892Sbalrog     defreg(TORH),    defreg(TORL),    defreg(TOTH),    defreg(TOTL),
1757c23b892Sbalrog     defreg(TPR),     defreg(TPT),     defreg(TXDCTL),  defreg(WUFC),
1768f2e8d1fSaliguori     defreg(RA),      defreg(MTA),     defreg(CRCERRS), defreg(VFTA),
177e9845f09SVincenzo Maffione     defreg(VET),     defreg(RDTR),    defreg(RADV),    defreg(TADV),
17872ea771cSLeonid Bloch     defreg(ITR),     defreg(FCRUC),   defreg(TDFH),    defreg(TDFT),
17972ea771cSLeonid Bloch     defreg(TDFHS),   defreg(TDFTS),   defreg(TDFPC),   defreg(RDFH),
18072ea771cSLeonid Bloch     defreg(RDFT),    defreg(RDFHS),   defreg(RDFTS),   defreg(RDFPC),
18172ea771cSLeonid Bloch     defreg(IPAV),    defreg(WUC),     defreg(WUS),     defreg(AIT),
18272ea771cSLeonid Bloch     defreg(IP6AT),   defreg(IP4AT),   defreg(FFLT),    defreg(FFMT),
18372ea771cSLeonid Bloch     defreg(FFVT),    defreg(WUPM),    defreg(PBM),     defreg(SCC),
18472ea771cSLeonid Bloch     defreg(ECOL),    defreg(MCC),     defreg(LATECOL), defreg(COLC),
18572ea771cSLeonid Bloch     defreg(DC),      defreg(TNCRS),   defreg(SEC),     defreg(CEXTERR),
18672ea771cSLeonid Bloch     defreg(RLEC),    defreg(XONRXC),  defreg(XONTXC),  defreg(XOFFRXC),
18772ea771cSLeonid Bloch     defreg(XOFFTXC), defreg(RFC),     defreg(RJC),     defreg(RNBC),
1883b274301SLeonid Bloch     defreg(TSCTFC),  defreg(MGTPRC),  defreg(MGTPDC),  defreg(MGTPTC),
1893b274301SLeonid Bloch     defreg(RUC),     defreg(ROC),     defreg(GORCL),   defreg(GORCH),
1903b274301SLeonid Bloch     defreg(GOTCL),   defreg(GOTCH),   defreg(BPRC),    defreg(MPRC),
1913b274301SLeonid Bloch     defreg(TSCTC),   defreg(PRC64),   defreg(PRC127),  defreg(PRC255),
1923b274301SLeonid Bloch     defreg(PRC511),  defreg(PRC1023), defreg(PRC1522), defreg(PTC64),
1933b274301SLeonid Bloch     defreg(PTC127),  defreg(PTC255),  defreg(PTC511),  defreg(PTC1023),
1943b274301SLeonid Bloch     defreg(PTC1522), defreg(MPTC),    defreg(BPTC)
1957c23b892Sbalrog };
1967c23b892Sbalrog 
19771aadd3cSJason Wang static void
19871aadd3cSJason Wang e1000_link_down(E1000State *s)
19971aadd3cSJason Wang {
20071aadd3cSJason Wang     s->mac_reg[STATUS] &= ~E1000_STATUS_LU;
20171aadd3cSJason Wang     s->phy_reg[PHY_STATUS] &= ~MII_SR_LINK_STATUS;
2026a2acedbSGabriel L. Somlo     s->phy_reg[PHY_STATUS] &= ~MII_SR_AUTONEG_COMPLETE;
2036883b591SGabriel L. Somlo     s->phy_reg[PHY_LP_ABILITY] &= ~MII_LPAR_LPACK;
20471aadd3cSJason Wang }
20571aadd3cSJason Wang 
20671aadd3cSJason Wang static void
20771aadd3cSJason Wang e1000_link_up(E1000State *s)
20871aadd3cSJason Wang {
20971aadd3cSJason Wang     s->mac_reg[STATUS] |= E1000_STATUS_LU;
21071aadd3cSJason Wang     s->phy_reg[PHY_STATUS] |= MII_SR_LINK_STATUS;
2115df6a185SStefan Hajnoczi 
2125df6a185SStefan Hajnoczi     /* E1000_STATUS_LU is tested by e1000_can_receive() */
2135df6a185SStefan Hajnoczi     qemu_flush_queued_packets(qemu_get_queue(s->nic));
21471aadd3cSJason Wang }
21571aadd3cSJason Wang 
2161195fed9SGabriel L. Somlo static bool
2171195fed9SGabriel L. Somlo have_autoneg(E1000State *s)
2181195fed9SGabriel L. Somlo {
219bc0f0674SLeonid Bloch     return chkflag(AUTONEG) && (s->phy_reg[PHY_CTRL] & MII_CR_AUTO_NEG_EN);
2201195fed9SGabriel L. Somlo }
2211195fed9SGabriel L. Somlo 
222b9d03e35SJason Wang static void
223b9d03e35SJason Wang set_phy_ctrl(E1000State *s, int index, uint16_t val)
224b9d03e35SJason Wang {
2251195fed9SGabriel L. Somlo     /* bits 0-5 reserved; MII_CR_[RESTART_AUTO_NEG,RESET] are self clearing */
2261195fed9SGabriel L. Somlo     s->phy_reg[PHY_CTRL] = val & ~(0x3f |
2271195fed9SGabriel L. Somlo                                    MII_CR_RESET |
2281195fed9SGabriel L. Somlo                                    MII_CR_RESTART_AUTO_NEG);
2291195fed9SGabriel L. Somlo 
2302af234e6SMichael S. Tsirkin     /*
2312af234e6SMichael S. Tsirkin      * QEMU 1.3 does not support link auto-negotiation emulation, so if we
2322af234e6SMichael S. Tsirkin      * migrate during auto negotiation, after migration the link will be
2332af234e6SMichael S. Tsirkin      * down.
2342af234e6SMichael S. Tsirkin      */
2351195fed9SGabriel L. Somlo     if (have_autoneg(s) && (val & MII_CR_RESTART_AUTO_NEG)) {
236b9d03e35SJason Wang         e1000_link_down(s);
237b9d03e35SJason Wang         DBGOUT(PHY, "Start link auto negotiation\n");
2381195fed9SGabriel L. Somlo         timer_mod(s->autoneg_timer,
2391195fed9SGabriel L. Somlo                   qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 500);
240b9d03e35SJason Wang     }
241b9d03e35SJason Wang }
242b9d03e35SJason Wang 
243b9d03e35SJason Wang static void (*phyreg_writeops[])(E1000State *, int, uint16_t) = {
244b9d03e35SJason Wang     [PHY_CTRL] = set_phy_ctrl,
245b9d03e35SJason Wang };
246b9d03e35SJason Wang 
247b9d03e35SJason Wang enum { NPHYWRITEOPS = ARRAY_SIZE(phyreg_writeops) };
248b9d03e35SJason Wang 
2497c23b892Sbalrog enum { PHY_R = 1, PHY_W = 2, PHY_RW = PHY_R | PHY_W };
25088b4e9dbSblueswir1 static const char phy_regcap[0x20] = {
2517c23b892Sbalrog     [PHY_STATUS]      = PHY_R,     [M88E1000_EXT_PHY_SPEC_CTRL] = PHY_RW,
2527c23b892Sbalrog     [PHY_ID1]         = PHY_R,     [M88E1000_PHY_SPEC_CTRL]     = PHY_RW,
2537c23b892Sbalrog     [PHY_CTRL]        = PHY_RW,    [PHY_1000T_CTRL]             = PHY_RW,
2547c23b892Sbalrog     [PHY_LP_ABILITY]  = PHY_R,     [PHY_1000T_STATUS]           = PHY_R,
2557c23b892Sbalrog     [PHY_AUTONEG_ADV] = PHY_RW,    [M88E1000_RX_ERR_CNTR]       = PHY_R,
2566883b591SGabriel L. Somlo     [PHY_ID2]         = PHY_R,     [M88E1000_PHY_SPEC_STATUS]   = PHY_R,
2576883b591SGabriel L. Somlo     [PHY_AUTONEG_EXP] = PHY_R,
2587c23b892Sbalrog };
2597c23b892Sbalrog 
2608597f2e1SGabriel L. Somlo /* PHY_ID2 documented in 8254x_GBe_SDM.pdf, pp. 250 */
261814cd3acSMichael S. Tsirkin static const uint16_t phy_reg_init[] = {
2629616c290SGabriel L. Somlo     [PHY_CTRL]   = MII_CR_SPEED_SELECT_MSB |
2639616c290SGabriel L. Somlo                    MII_CR_FULL_DUPLEX |
2649616c290SGabriel L. Somlo                    MII_CR_AUTO_NEG_EN,
2659616c290SGabriel L. Somlo 
2669616c290SGabriel L. Somlo     [PHY_STATUS] = MII_SR_EXTENDED_CAPS |
2679616c290SGabriel L. Somlo                    MII_SR_LINK_STATUS |   /* link initially up */
2689616c290SGabriel L. Somlo                    MII_SR_AUTONEG_CAPS |
2699616c290SGabriel L. Somlo                    /* MII_SR_AUTONEG_COMPLETE: initially NOT completed */
2709616c290SGabriel L. Somlo                    MII_SR_PREAMBLE_SUPPRESS |
2719616c290SGabriel L. Somlo                    MII_SR_EXTENDED_STATUS |
2729616c290SGabriel L. Somlo                    MII_SR_10T_HD_CAPS |
2739616c290SGabriel L. Somlo                    MII_SR_10T_FD_CAPS |
2749616c290SGabriel L. Somlo                    MII_SR_100X_HD_CAPS |
2759616c290SGabriel L. Somlo                    MII_SR_100X_FD_CAPS,
2769616c290SGabriel L. Somlo 
2779616c290SGabriel L. Somlo     [PHY_ID1] = 0x141,
2789616c290SGabriel L. Somlo     /* [PHY_ID2] configured per DevId, from e1000_reset() */
2799616c290SGabriel L. Somlo     [PHY_AUTONEG_ADV] = 0xde1,
2809616c290SGabriel L. Somlo     [PHY_LP_ABILITY] = 0x1e0,
2819616c290SGabriel L. Somlo     [PHY_1000T_CTRL] = 0x0e00,
2829616c290SGabriel L. Somlo     [PHY_1000T_STATUS] = 0x3c00,
2839616c290SGabriel L. Somlo     [M88E1000_PHY_SPEC_CTRL] = 0x360,
284814cd3acSMichael S. Tsirkin     [M88E1000_PHY_SPEC_STATUS] = 0xac00,
2859616c290SGabriel L. Somlo     [M88E1000_EXT_PHY_SPEC_CTRL] = 0x0d60,
286814cd3acSMichael S. Tsirkin };
287814cd3acSMichael S. Tsirkin 
288814cd3acSMichael S. Tsirkin static const uint32_t mac_reg_init[] = {
289814cd3acSMichael S. Tsirkin     [PBA]     = 0x00100030,
290814cd3acSMichael S. Tsirkin     [LEDCTL]  = 0x602,
291814cd3acSMichael S. Tsirkin     [CTRL]    = E1000_CTRL_SWDPIN2 | E1000_CTRL_SWDPIN0 |
292814cd3acSMichael S. Tsirkin                 E1000_CTRL_SPD_1000 | E1000_CTRL_SLU,
293814cd3acSMichael S. Tsirkin     [STATUS]  = 0x80000000 | E1000_STATUS_GIO_MASTER_ENABLE |
294814cd3acSMichael S. Tsirkin                 E1000_STATUS_ASDV | E1000_STATUS_MTXCKOK |
295814cd3acSMichael S. Tsirkin                 E1000_STATUS_SPEED_1000 | E1000_STATUS_FD |
296814cd3acSMichael S. Tsirkin                 E1000_STATUS_LU,
297814cd3acSMichael S. Tsirkin     [MANC]    = E1000_MANC_EN_MNG2HOST | E1000_MANC_RCV_TCO_EN |
298814cd3acSMichael S. Tsirkin                 E1000_MANC_ARP_EN | E1000_MANC_0298_EN |
299814cd3acSMichael S. Tsirkin                 E1000_MANC_RMCP_EN,
300814cd3acSMichael S. Tsirkin };
301814cd3acSMichael S. Tsirkin 
302e9845f09SVincenzo Maffione /* Helper function, *curr == 0 means the value is not set */
303e9845f09SVincenzo Maffione static inline void
304e9845f09SVincenzo Maffione mit_update_delay(uint32_t *curr, uint32_t value)
305e9845f09SVincenzo Maffione {
306e9845f09SVincenzo Maffione     if (value && (*curr == 0 || value < *curr)) {
307e9845f09SVincenzo Maffione         *curr = value;
308e9845f09SVincenzo Maffione     }
309e9845f09SVincenzo Maffione }
310e9845f09SVincenzo Maffione 
3117c23b892Sbalrog static void
3127c23b892Sbalrog set_interrupt_cause(E1000State *s, int index, uint32_t val)
3137c23b892Sbalrog {
314b08340d5SAndreas Färber     PCIDevice *d = PCI_DEVICE(s);
315e9845f09SVincenzo Maffione     uint32_t pending_ints;
316e9845f09SVincenzo Maffione     uint32_t mit_delay;
317b08340d5SAndreas Färber 
3187c23b892Sbalrog     s->mac_reg[ICR] = val;
319a52a8841SMichael S. Tsirkin 
320a52a8841SMichael S. Tsirkin     /*
321a52a8841SMichael S. Tsirkin      * Make sure ICR and ICS registers have the same value.
322a52a8841SMichael S. Tsirkin      * The spec says that the ICS register is write-only.  However in practice,
323a52a8841SMichael S. Tsirkin      * on real hardware ICS is readable, and for reads it has the same value as
324a52a8841SMichael S. Tsirkin      * ICR (except that ICS does not have the clear on read behaviour of ICR).
325a52a8841SMichael S. Tsirkin      *
326a52a8841SMichael S. Tsirkin      * The VxWorks PRO/1000 driver uses this behaviour.
327a52a8841SMichael S. Tsirkin      */
328b1332393SBill Paul     s->mac_reg[ICS] = val;
329a52a8841SMichael S. Tsirkin 
330e9845f09SVincenzo Maffione     pending_ints = (s->mac_reg[IMS] & s->mac_reg[ICR]);
331e9845f09SVincenzo Maffione     if (!s->mit_irq_level && pending_ints) {
332e9845f09SVincenzo Maffione         /*
333e9845f09SVincenzo Maffione          * Here we detect a potential raising edge. We postpone raising the
334e9845f09SVincenzo Maffione          * interrupt line if we are inside the mitigation delay window
335e9845f09SVincenzo Maffione          * (s->mit_timer_on == 1).
336e9845f09SVincenzo Maffione          * We provide a partial implementation of interrupt mitigation,
337e9845f09SVincenzo Maffione          * emulating only RADV, TADV and ITR (lower 16 bits, 1024ns units for
338e9845f09SVincenzo Maffione          * RADV and TADV, 256ns units for ITR). RDTR is only used to enable
339e9845f09SVincenzo Maffione          * RADV; relative timers based on TIDV and RDTR are not implemented.
340e9845f09SVincenzo Maffione          */
341e9845f09SVincenzo Maffione         if (s->mit_timer_on) {
342e9845f09SVincenzo Maffione             return;
343e9845f09SVincenzo Maffione         }
344bc0f0674SLeonid Bloch         if (chkflag(MIT)) {
345e9845f09SVincenzo Maffione             /* Compute the next mitigation delay according to pending
346e9845f09SVincenzo Maffione              * interrupts and the current values of RADV (provided
347e9845f09SVincenzo Maffione              * RDTR!=0), TADV and ITR.
348e9845f09SVincenzo Maffione              * Then rearm the timer.
349e9845f09SVincenzo Maffione              */
350e9845f09SVincenzo Maffione             mit_delay = 0;
351e9845f09SVincenzo Maffione             if (s->mit_ide &&
352e9845f09SVincenzo Maffione                     (pending_ints & (E1000_ICR_TXQE | E1000_ICR_TXDW))) {
353e9845f09SVincenzo Maffione                 mit_update_delay(&mit_delay, s->mac_reg[TADV] * 4);
354e9845f09SVincenzo Maffione             }
355e9845f09SVincenzo Maffione             if (s->mac_reg[RDTR] && (pending_ints & E1000_ICS_RXT0)) {
356e9845f09SVincenzo Maffione                 mit_update_delay(&mit_delay, s->mac_reg[RADV] * 4);
357e9845f09SVincenzo Maffione             }
358e9845f09SVincenzo Maffione             mit_update_delay(&mit_delay, s->mac_reg[ITR]);
359e9845f09SVincenzo Maffione 
360e9845f09SVincenzo Maffione             if (mit_delay) {
361e9845f09SVincenzo Maffione                 s->mit_timer_on = 1;
362e9845f09SVincenzo Maffione                 timer_mod(s->mit_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
363e9845f09SVincenzo Maffione                           mit_delay * 256);
364e9845f09SVincenzo Maffione             }
365e9845f09SVincenzo Maffione             s->mit_ide = 0;
366e9845f09SVincenzo Maffione         }
367e9845f09SVincenzo Maffione     }
368e9845f09SVincenzo Maffione 
369e9845f09SVincenzo Maffione     s->mit_irq_level = (pending_ints != 0);
3709e64f8a3SMarcel Apfelbaum     pci_set_irq(d, s->mit_irq_level);
371e9845f09SVincenzo Maffione }
372e9845f09SVincenzo Maffione 
373e9845f09SVincenzo Maffione static void
374e9845f09SVincenzo Maffione e1000_mit_timer(void *opaque)
375e9845f09SVincenzo Maffione {
376e9845f09SVincenzo Maffione     E1000State *s = opaque;
377e9845f09SVincenzo Maffione 
378e9845f09SVincenzo Maffione     s->mit_timer_on = 0;
379e9845f09SVincenzo Maffione     /* Call set_interrupt_cause to update the irq level (if necessary). */
380e9845f09SVincenzo Maffione     set_interrupt_cause(s, 0, s->mac_reg[ICR]);
3817c23b892Sbalrog }
3827c23b892Sbalrog 
3837c23b892Sbalrog static void
3847c23b892Sbalrog set_ics(E1000State *s, int index, uint32_t val)
3857c23b892Sbalrog {
3867c23b892Sbalrog     DBGOUT(INTERRUPT, "set_ics %x, ICR %x, IMR %x\n", val, s->mac_reg[ICR],
3877c23b892Sbalrog         s->mac_reg[IMS]);
3887c23b892Sbalrog     set_interrupt_cause(s, 0, val | s->mac_reg[ICR]);
3897c23b892Sbalrog }
3907c23b892Sbalrog 
391d52aec95SGabriel L. Somlo static void
392d52aec95SGabriel L. Somlo e1000_autoneg_timer(void *opaque)
393d52aec95SGabriel L. Somlo {
394d52aec95SGabriel L. Somlo     E1000State *s = opaque;
395d52aec95SGabriel L. Somlo     if (!qemu_get_queue(s->nic)->link_down) {
396d52aec95SGabriel L. Somlo         e1000_link_up(s);
397d52aec95SGabriel L. Somlo         s->phy_reg[PHY_LP_ABILITY] |= MII_LPAR_LPACK;
398d52aec95SGabriel L. Somlo         s->phy_reg[PHY_STATUS] |= MII_SR_AUTONEG_COMPLETE;
399d52aec95SGabriel L. Somlo         DBGOUT(PHY, "Auto negotiation is completed\n");
400d52aec95SGabriel L. Somlo         set_ics(s, 0, E1000_ICS_LSC); /* signal link status change to guest */
401d52aec95SGabriel L. Somlo     }
402d52aec95SGabriel L. Somlo }
403d52aec95SGabriel L. Somlo 
4047c23b892Sbalrog static int
4057c23b892Sbalrog rxbufsize(uint32_t v)
4067c23b892Sbalrog {
4077c23b892Sbalrog     v &= E1000_RCTL_BSEX | E1000_RCTL_SZ_16384 | E1000_RCTL_SZ_8192 |
4087c23b892Sbalrog          E1000_RCTL_SZ_4096 | E1000_RCTL_SZ_2048 | E1000_RCTL_SZ_1024 |
4097c23b892Sbalrog          E1000_RCTL_SZ_512 | E1000_RCTL_SZ_256;
4107c23b892Sbalrog     switch (v) {
4117c23b892Sbalrog     case E1000_RCTL_BSEX | E1000_RCTL_SZ_16384:
4127c23b892Sbalrog         return 16384;
4137c23b892Sbalrog     case E1000_RCTL_BSEX | E1000_RCTL_SZ_8192:
4147c23b892Sbalrog         return 8192;
4157c23b892Sbalrog     case E1000_RCTL_BSEX | E1000_RCTL_SZ_4096:
4167c23b892Sbalrog         return 4096;
4177c23b892Sbalrog     case E1000_RCTL_SZ_1024:
4187c23b892Sbalrog         return 1024;
4197c23b892Sbalrog     case E1000_RCTL_SZ_512:
4207c23b892Sbalrog         return 512;
4217c23b892Sbalrog     case E1000_RCTL_SZ_256:
4227c23b892Sbalrog         return 256;
4237c23b892Sbalrog     }
4247c23b892Sbalrog     return 2048;
4257c23b892Sbalrog }
4267c23b892Sbalrog 
427814cd3acSMichael S. Tsirkin static void e1000_reset(void *opaque)
428814cd3acSMichael S. Tsirkin {
429814cd3acSMichael S. Tsirkin     E1000State *d = opaque;
4308597f2e1SGabriel L. Somlo     E1000BaseClass *edc = E1000_DEVICE_GET_CLASS(d);
431372254c6SGabriel L. Somlo     uint8_t *macaddr = d->conf.macaddr.a;
432372254c6SGabriel L. Somlo     int i;
433814cd3acSMichael S. Tsirkin 
434bc72ad67SAlex Bligh     timer_del(d->autoneg_timer);
435e9845f09SVincenzo Maffione     timer_del(d->mit_timer);
436e9845f09SVincenzo Maffione     d->mit_timer_on = 0;
437e9845f09SVincenzo Maffione     d->mit_irq_level = 0;
438e9845f09SVincenzo Maffione     d->mit_ide = 0;
439814cd3acSMichael S. Tsirkin     memset(d->phy_reg, 0, sizeof d->phy_reg);
440814cd3acSMichael S. Tsirkin     memmove(d->phy_reg, phy_reg_init, sizeof phy_reg_init);
4418597f2e1SGabriel L. Somlo     d->phy_reg[PHY_ID2] = edc->phy_id2;
442814cd3acSMichael S. Tsirkin     memset(d->mac_reg, 0, sizeof d->mac_reg);
443814cd3acSMichael S. Tsirkin     memmove(d->mac_reg, mac_reg_init, sizeof mac_reg_init);
444814cd3acSMichael S. Tsirkin     d->rxbuf_min_shift = 1;
445814cd3acSMichael S. Tsirkin     memset(&d->tx, 0, sizeof d->tx);
446814cd3acSMichael S. Tsirkin 
447b356f76dSJason Wang     if (qemu_get_queue(d->nic)->link_down) {
44871aadd3cSJason Wang         e1000_link_down(d);
449814cd3acSMichael S. Tsirkin     }
450372254c6SGabriel L. Somlo 
4519596ef7cSDenis V. Lunev     /* Throttle interrupts to prevent guest (e.g Win 2012) from
4529596ef7cSDenis V. Lunev      * reinjecting interrupts endlessly. TODO: fix non ITR case.
4539596ef7cSDenis V. Lunev      */
4549596ef7cSDenis V. Lunev     d->mac_reg[ITR] = 250;
4559596ef7cSDenis V. Lunev 
456372254c6SGabriel L. Somlo     /* Some guests expect pre-initialized RAH/RAL (AddrValid flag + MACaddr) */
457372254c6SGabriel L. Somlo     d->mac_reg[RA] = 0;
458372254c6SGabriel L. Somlo     d->mac_reg[RA + 1] = E1000_RAH_AV;
459372254c6SGabriel L. Somlo     for (i = 0; i < 4; i++) {
460372254c6SGabriel L. Somlo         d->mac_reg[RA] |= macaddr[i] << (8 * i);
461372254c6SGabriel L. Somlo         d->mac_reg[RA + 1] |= (i < 2) ? macaddr[i + 4] << (8 * i) : 0;
462372254c6SGabriel L. Somlo     }
463655d3b63SAmos Kong     qemu_format_nic_info_str(qemu_get_queue(d->nic), macaddr);
464814cd3acSMichael S. Tsirkin }
465814cd3acSMichael S. Tsirkin 
4667c23b892Sbalrog static void
467cab3c825SKevin Wolf set_ctrl(E1000State *s, int index, uint32_t val)
468cab3c825SKevin Wolf {
469cab3c825SKevin Wolf     /* RST is self clearing */
470cab3c825SKevin Wolf     s->mac_reg[CTRL] = val & ~E1000_CTRL_RST;
471cab3c825SKevin Wolf }
472cab3c825SKevin Wolf 
473cab3c825SKevin Wolf static void
4747c23b892Sbalrog set_rx_control(E1000State *s, int index, uint32_t val)
4757c23b892Sbalrog {
4767c23b892Sbalrog     s->mac_reg[RCTL] = val;
4777c23b892Sbalrog     s->rxbuf_size = rxbufsize(val);
4787c23b892Sbalrog     s->rxbuf_min_shift = ((val / E1000_RCTL_RDMTS_QUAT) & 3) + 1;
4797c23b892Sbalrog     DBGOUT(RX, "RCTL: %d, mac_reg[RCTL] = 0x%x\n", s->mac_reg[RDT],
4807c23b892Sbalrog            s->mac_reg[RCTL]);
481b356f76dSJason Wang     qemu_flush_queued_packets(qemu_get_queue(s->nic));
4827c23b892Sbalrog }
4837c23b892Sbalrog 
4847c23b892Sbalrog static void
4857c23b892Sbalrog set_mdic(E1000State *s, int index, uint32_t val)
4867c23b892Sbalrog {
4877c23b892Sbalrog     uint32_t data = val & E1000_MDIC_DATA_MASK;
4887c23b892Sbalrog     uint32_t addr = ((val & E1000_MDIC_REG_MASK) >> E1000_MDIC_REG_SHIFT);
4897c23b892Sbalrog 
4907c23b892Sbalrog     if ((val & E1000_MDIC_PHY_MASK) >> E1000_MDIC_PHY_SHIFT != 1) // phy #
4917c23b892Sbalrog         val = s->mac_reg[MDIC] | E1000_MDIC_ERROR;
4927c23b892Sbalrog     else if (val & E1000_MDIC_OP_READ) {
4937c23b892Sbalrog         DBGOUT(MDIC, "MDIC read reg 0x%x\n", addr);
4947c23b892Sbalrog         if (!(phy_regcap[addr] & PHY_R)) {
4957c23b892Sbalrog             DBGOUT(MDIC, "MDIC read reg %x unhandled\n", addr);
4967c23b892Sbalrog             val |= E1000_MDIC_ERROR;
4977c23b892Sbalrog         } else
4987c23b892Sbalrog             val = (val ^ data) | s->phy_reg[addr];
4997c23b892Sbalrog     } else if (val & E1000_MDIC_OP_WRITE) {
5007c23b892Sbalrog         DBGOUT(MDIC, "MDIC write reg 0x%x, value 0x%x\n", addr, data);
5017c23b892Sbalrog         if (!(phy_regcap[addr] & PHY_W)) {
5027c23b892Sbalrog             DBGOUT(MDIC, "MDIC write reg %x unhandled\n", addr);
5037c23b892Sbalrog             val |= E1000_MDIC_ERROR;
504b9d03e35SJason Wang         } else {
505b9d03e35SJason Wang             if (addr < NPHYWRITEOPS && phyreg_writeops[addr]) {
506b9d03e35SJason Wang                 phyreg_writeops[addr](s, index, data);
5071195fed9SGabriel L. Somlo             } else {
5087c23b892Sbalrog                 s->phy_reg[addr] = data;
5097c23b892Sbalrog             }
510b9d03e35SJason Wang         }
5111195fed9SGabriel L. Somlo     }
5127c23b892Sbalrog     s->mac_reg[MDIC] = val | E1000_MDIC_READY;
51317fbbb0bSJason Wang 
51417fbbb0bSJason Wang     if (val & E1000_MDIC_INT_EN) {
5157c23b892Sbalrog         set_ics(s, 0, E1000_ICR_MDAC);
5167c23b892Sbalrog     }
51717fbbb0bSJason Wang }
5187c23b892Sbalrog 
5197c23b892Sbalrog static uint32_t
5207c23b892Sbalrog get_eecd(E1000State *s, int index)
5217c23b892Sbalrog {
5227c23b892Sbalrog     uint32_t ret = E1000_EECD_PRES|E1000_EECD_GNT | s->eecd_state.old_eecd;
5237c23b892Sbalrog 
5247c23b892Sbalrog     DBGOUT(EEPROM, "reading eeprom bit %d (reading %d)\n",
5257c23b892Sbalrog            s->eecd_state.bitnum_out, s->eecd_state.reading);
5267c23b892Sbalrog     if (!s->eecd_state.reading ||
5277c23b892Sbalrog         ((s->eeprom_data[(s->eecd_state.bitnum_out >> 4) & 0x3f] >>
5287c23b892Sbalrog           ((s->eecd_state.bitnum_out & 0xf) ^ 0xf))) & 1)
5297c23b892Sbalrog         ret |= E1000_EECD_DO;
5307c23b892Sbalrog     return ret;
5317c23b892Sbalrog }
5327c23b892Sbalrog 
5337c23b892Sbalrog static void
5347c23b892Sbalrog set_eecd(E1000State *s, int index, uint32_t val)
5357c23b892Sbalrog {
5367c23b892Sbalrog     uint32_t oldval = s->eecd_state.old_eecd;
5377c23b892Sbalrog 
5387c23b892Sbalrog     s->eecd_state.old_eecd = val & (E1000_EECD_SK | E1000_EECD_CS |
5397c23b892Sbalrog             E1000_EECD_DI|E1000_EECD_FWE_MASK|E1000_EECD_REQ);
54020f3e863SLeonid Bloch     if (!(E1000_EECD_CS & val)) {            /* CS inactive; nothing to do */
5419651ac55SIzumi Tsutsui         return;
54220f3e863SLeonid Bloch     }
54320f3e863SLeonid Bloch     if (E1000_EECD_CS & (val ^ oldval)) {    /* CS rise edge; reset state */
5449651ac55SIzumi Tsutsui         s->eecd_state.val_in = 0;
5459651ac55SIzumi Tsutsui         s->eecd_state.bitnum_in = 0;
5469651ac55SIzumi Tsutsui         s->eecd_state.bitnum_out = 0;
5479651ac55SIzumi Tsutsui         s->eecd_state.reading = 0;
5489651ac55SIzumi Tsutsui     }
54920f3e863SLeonid Bloch     if (!(E1000_EECD_SK & (val ^ oldval))) {    /* no clock edge */
5507c23b892Sbalrog         return;
55120f3e863SLeonid Bloch     }
55220f3e863SLeonid Bloch     if (!(E1000_EECD_SK & val)) {               /* falling edge */
5537c23b892Sbalrog         s->eecd_state.bitnum_out++;
5547c23b892Sbalrog         return;
5557c23b892Sbalrog     }
5567c23b892Sbalrog     s->eecd_state.val_in <<= 1;
5577c23b892Sbalrog     if (val & E1000_EECD_DI)
5587c23b892Sbalrog         s->eecd_state.val_in |= 1;
5597c23b892Sbalrog     if (++s->eecd_state.bitnum_in == 9 && !s->eecd_state.reading) {
5607c23b892Sbalrog         s->eecd_state.bitnum_out = ((s->eecd_state.val_in & 0x3f)<<4)-1;
5617c23b892Sbalrog         s->eecd_state.reading = (((s->eecd_state.val_in >> 6) & 7) ==
5627c23b892Sbalrog             EEPROM_READ_OPCODE_MICROWIRE);
5637c23b892Sbalrog     }
5647c23b892Sbalrog     DBGOUT(EEPROM, "eeprom bitnum in %d out %d, reading %d\n",
5657c23b892Sbalrog            s->eecd_state.bitnum_in, s->eecd_state.bitnum_out,
5667c23b892Sbalrog            s->eecd_state.reading);
5677c23b892Sbalrog }
5687c23b892Sbalrog 
5697c23b892Sbalrog static uint32_t
5707c23b892Sbalrog flash_eerd_read(E1000State *s, int x)
5717c23b892Sbalrog {
5727c23b892Sbalrog     unsigned int index, r = s->mac_reg[EERD] & ~E1000_EEPROM_RW_REG_START;
5737c23b892Sbalrog 
574b1332393SBill Paul     if ((s->mac_reg[EERD] & E1000_EEPROM_RW_REG_START) == 0)
575b1332393SBill Paul         return (s->mac_reg[EERD]);
576b1332393SBill Paul 
5777c23b892Sbalrog     if ((index = r >> E1000_EEPROM_RW_ADDR_SHIFT) > EEPROM_CHECKSUM_REG)
578b1332393SBill Paul         return (E1000_EEPROM_RW_REG_DONE | r);
579b1332393SBill Paul 
580b1332393SBill Paul     return ((s->eeprom_data[index] << E1000_EEPROM_RW_REG_DATA) |
581b1332393SBill Paul            E1000_EEPROM_RW_REG_DONE | r);
5827c23b892Sbalrog }
5837c23b892Sbalrog 
5847c23b892Sbalrog static void
5857c23b892Sbalrog putsum(uint8_t *data, uint32_t n, uint32_t sloc, uint32_t css, uint32_t cse)
5867c23b892Sbalrog {
587c6a6a5e3Saliguori     uint32_t sum;
588c6a6a5e3Saliguori 
5897c23b892Sbalrog     if (cse && cse < n)
5907c23b892Sbalrog         n = cse + 1;
591c6a6a5e3Saliguori     if (sloc < n-1) {
592c6a6a5e3Saliguori         sum = net_checksum_add(n-css, data+css);
593d8ee2591SPeter Maydell         stw_be_p(data + sloc, net_checksum_finish(sum));
594c6a6a5e3Saliguori     }
5957c23b892Sbalrog }
5967c23b892Sbalrog 
5971f67f92cSLeonid Bloch static inline void
5981f67f92cSLeonid Bloch inc_reg_if_not_full(E1000State *s, int index)
5991f67f92cSLeonid Bloch {
6001f67f92cSLeonid Bloch     if (s->mac_reg[index] != 0xffffffff) {
6011f67f92cSLeonid Bloch         s->mac_reg[index]++;
6021f67f92cSLeonid Bloch     }
6031f67f92cSLeonid Bloch }
6041f67f92cSLeonid Bloch 
6053b274301SLeonid Bloch static inline void
6063b274301SLeonid Bloch inc_tx_bcast_or_mcast_count(E1000State *s, const unsigned char *arr)
6073b274301SLeonid Bloch {
6083b274301SLeonid Bloch     if (!memcmp(arr, bcast, sizeof bcast)) {
6093b274301SLeonid Bloch         inc_reg_if_not_full(s, BPTC);
6103b274301SLeonid Bloch     } else if (arr[0] & 1) {
6113b274301SLeonid Bloch         inc_reg_if_not_full(s, MPTC);
6123b274301SLeonid Bloch     }
6133b274301SLeonid Bloch }
6143b274301SLeonid Bloch 
61545e93764SLeonid Bloch static void
61645e93764SLeonid Bloch grow_8reg_if_not_full(E1000State *s, int index, int size)
61745e93764SLeonid Bloch {
61845e93764SLeonid Bloch     uint64_t sum = s->mac_reg[index] | (uint64_t)s->mac_reg[index+1] << 32;
61945e93764SLeonid Bloch 
62045e93764SLeonid Bloch     if (sum + size < sum) {
62145e93764SLeonid Bloch         sum = ~0ULL;
62245e93764SLeonid Bloch     } else {
62345e93764SLeonid Bloch         sum += size;
62445e93764SLeonid Bloch     }
62545e93764SLeonid Bloch     s->mac_reg[index] = sum;
62645e93764SLeonid Bloch     s->mac_reg[index+1] = sum >> 32;
62745e93764SLeonid Bloch }
62845e93764SLeonid Bloch 
6293b274301SLeonid Bloch static void
6303b274301SLeonid Bloch increase_size_stats(E1000State *s, const int *size_regs, int size)
6313b274301SLeonid Bloch {
6323b274301SLeonid Bloch     if (size > 1023) {
6333b274301SLeonid Bloch         inc_reg_if_not_full(s, size_regs[5]);
6343b274301SLeonid Bloch     } else if (size > 511) {
6353b274301SLeonid Bloch         inc_reg_if_not_full(s, size_regs[4]);
6363b274301SLeonid Bloch     } else if (size > 255) {
6373b274301SLeonid Bloch         inc_reg_if_not_full(s, size_regs[3]);
6383b274301SLeonid Bloch     } else if (size > 127) {
6393b274301SLeonid Bloch         inc_reg_if_not_full(s, size_regs[2]);
6403b274301SLeonid Bloch     } else if (size > 64) {
6413b274301SLeonid Bloch         inc_reg_if_not_full(s, size_regs[1]);
6423b274301SLeonid Bloch     } else if (size == 64) {
6433b274301SLeonid Bloch         inc_reg_if_not_full(s, size_regs[0]);
6443b274301SLeonid Bloch     }
6453b274301SLeonid Bloch }
6463b274301SLeonid Bloch 
6478f2e8d1fSaliguori static inline int
6488f2e8d1fSaliguori vlan_enabled(E1000State *s)
6498f2e8d1fSaliguori {
6508f2e8d1fSaliguori     return ((s->mac_reg[CTRL] & E1000_CTRL_VME) != 0);
6518f2e8d1fSaliguori }
6528f2e8d1fSaliguori 
6538f2e8d1fSaliguori static inline int
6548f2e8d1fSaliguori vlan_rx_filter_enabled(E1000State *s)
6558f2e8d1fSaliguori {
6568f2e8d1fSaliguori     return ((s->mac_reg[RCTL] & E1000_RCTL_VFE) != 0);
6578f2e8d1fSaliguori }
6588f2e8d1fSaliguori 
6598f2e8d1fSaliguori static inline int
6608f2e8d1fSaliguori is_vlan_packet(E1000State *s, const uint8_t *buf)
6618f2e8d1fSaliguori {
6628f2e8d1fSaliguori     return (be16_to_cpup((uint16_t *)(buf + 12)) ==
6634e60a250SShannon Zhao                 le16_to_cpu(s->mac_reg[VET]));
6648f2e8d1fSaliguori }
6658f2e8d1fSaliguori 
6668f2e8d1fSaliguori static inline int
6678f2e8d1fSaliguori is_vlan_txd(uint32_t txd_lower)
6688f2e8d1fSaliguori {
6698f2e8d1fSaliguori     return ((txd_lower & E1000_TXD_CMD_VLE) != 0);
6708f2e8d1fSaliguori }
6718f2e8d1fSaliguori 
67255e8d1ceSMichael S. Tsirkin /* FCS aka Ethernet CRC-32. We don't get it from backends and can't
67355e8d1ceSMichael S. Tsirkin  * fill it in, just pad descriptor length by 4 bytes unless guest
674a05e8a6eSMichael S. Tsirkin  * told us to strip it off the packet. */
67555e8d1ceSMichael S. Tsirkin static inline int
67655e8d1ceSMichael S. Tsirkin fcs_len(E1000State *s)
67755e8d1ceSMichael S. Tsirkin {
67855e8d1ceSMichael S. Tsirkin     return (s->mac_reg[RCTL] & E1000_RCTL_SECRC) ? 0 : 4;
67955e8d1ceSMichael S. Tsirkin }
68055e8d1ceSMichael S. Tsirkin 
6817c23b892Sbalrog static void
68293e37d76SJason Wang e1000_send_packet(E1000State *s, const uint8_t *buf, int size)
68393e37d76SJason Wang {
6843b274301SLeonid Bloch     static const int PTCregs[6] = { PTC64, PTC127, PTC255, PTC511,
6853b274301SLeonid Bloch                                     PTC1023, PTC1522 };
6863b274301SLeonid Bloch 
687b356f76dSJason Wang     NetClientState *nc = qemu_get_queue(s->nic);
68893e37d76SJason Wang     if (s->phy_reg[PHY_CTRL] & MII_CR_LOOPBACK) {
689b356f76dSJason Wang         nc->info->receive(nc, buf, size);
69093e37d76SJason Wang     } else {
691b356f76dSJason Wang         qemu_send_packet(nc, buf, size);
69293e37d76SJason Wang     }
6933b274301SLeonid Bloch     inc_tx_bcast_or_mcast_count(s, buf);
6943b274301SLeonid Bloch     increase_size_stats(s, PTCregs, size);
69593e37d76SJason Wang }
69693e37d76SJason Wang 
69793e37d76SJason Wang static void
6987c23b892Sbalrog xmit_seg(E1000State *s)
6997c23b892Sbalrog {
7007c23b892Sbalrog     uint16_t len, *sp;
70145e93764SLeonid Bloch     unsigned int frames = s->tx.tso_frames, css, sofar;
7027c23b892Sbalrog     struct e1000_tx *tp = &s->tx;
7037c23b892Sbalrog 
7041b0009dbSbalrog     if (tp->tse && tp->cptse) {
7057c23b892Sbalrog         css = tp->ipcss;
7067c23b892Sbalrog         DBGOUT(TXSUM, "frames %d size %d ipcss %d\n",
7077c23b892Sbalrog                frames, tp->size, css);
70820f3e863SLeonid Bloch         if (tp->ip) {    /* IPv4 */
709d8ee2591SPeter Maydell             stw_be_p(tp->data+css+2, tp->size - css);
710d8ee2591SPeter Maydell             stw_be_p(tp->data+css+4,
7117c23b892Sbalrog                      be16_to_cpup((uint16_t *)(tp->data+css+4))+frames);
71220f3e863SLeonid Bloch         } else {         /* IPv6 */
713d8ee2591SPeter Maydell             stw_be_p(tp->data+css+4, tp->size - css);
71420f3e863SLeonid Bloch         }
7157c23b892Sbalrog         css = tp->tucss;
7167c23b892Sbalrog         len = tp->size - css;
7177c23b892Sbalrog         DBGOUT(TXSUM, "tcp %d tucss %d len %d\n", tp->tcp, css, len);
7187c23b892Sbalrog         if (tp->tcp) {
7197c23b892Sbalrog             sofar = frames * tp->mss;
7206bd194abSPeter Maydell             stl_be_p(tp->data+css+4, ldl_be_p(tp->data+css+4)+sofar); /* seq */
7213b274301SLeonid Bloch             if (tp->paylen - sofar > tp->mss) {
72220f3e863SLeonid Bloch                 tp->data[css + 13] &= ~9;    /* PSH, FIN */
7233b274301SLeonid Bloch             } else if (frames) {
7243b274301SLeonid Bloch                 inc_reg_if_not_full(s, TSCTC);
7253b274301SLeonid Bloch             }
72620f3e863SLeonid Bloch         } else    /* UDP */
727d8ee2591SPeter Maydell             stw_be_p(tp->data+css+4, len);
7287c23b892Sbalrog         if (tp->sum_needed & E1000_TXD_POPTS_TXSM) {
729e685b4ebSAlex Williamson             unsigned int phsum;
7307c23b892Sbalrog             // add pseudo-header length before checksum calculation
7317c23b892Sbalrog             sp = (uint16_t *)(tp->data + tp->tucso);
732e685b4ebSAlex Williamson             phsum = be16_to_cpup(sp) + len;
733e685b4ebSAlex Williamson             phsum = (phsum >> 16) + (phsum & 0xffff);
734d8ee2591SPeter Maydell             stw_be_p(sp, phsum);
7357c23b892Sbalrog         }
7367c23b892Sbalrog         tp->tso_frames++;
7377c23b892Sbalrog     }
7387c23b892Sbalrog 
7397c23b892Sbalrog     if (tp->sum_needed & E1000_TXD_POPTS_TXSM)
7407c23b892Sbalrog         putsum(tp->data, tp->size, tp->tucso, tp->tucss, tp->tucse);
7417c23b892Sbalrog     if (tp->sum_needed & E1000_TXD_POPTS_IXSM)
7427c23b892Sbalrog         putsum(tp->data, tp->size, tp->ipcso, tp->ipcss, tp->ipcse);
7438f2e8d1fSaliguori     if (tp->vlan_needed) {
744b10fec9bSStefan Weil         memmove(tp->vlan, tp->data, 4);
745b10fec9bSStefan Weil         memmove(tp->data, tp->data + 4, 8);
7468f2e8d1fSaliguori         memcpy(tp->data + 8, tp->vlan_header, 4);
74793e37d76SJason Wang         e1000_send_packet(s, tp->vlan, tp->size + 4);
74820f3e863SLeonid Bloch     } else {
74993e37d76SJason Wang         e1000_send_packet(s, tp->data, tp->size);
75020f3e863SLeonid Bloch     }
75120f3e863SLeonid Bloch 
7521f67f92cSLeonid Bloch     inc_reg_if_not_full(s, TPT);
75345e93764SLeonid Bloch     grow_8reg_if_not_full(s, TOTL, s->tx.size);
7541f67f92cSLeonid Bloch     s->mac_reg[GPTC] = s->mac_reg[TPT];
7553b274301SLeonid Bloch     s->mac_reg[GOTCL] = s->mac_reg[TOTL];
7563b274301SLeonid Bloch     s->mac_reg[GOTCH] = s->mac_reg[TOTH];
7577c23b892Sbalrog }
7587c23b892Sbalrog 
7597c23b892Sbalrog static void
7607c23b892Sbalrog process_tx_desc(E1000State *s, struct e1000_tx_desc *dp)
7617c23b892Sbalrog {
762b08340d5SAndreas Färber     PCIDevice *d = PCI_DEVICE(s);
7637c23b892Sbalrog     uint32_t txd_lower = le32_to_cpu(dp->lower.data);
7647c23b892Sbalrog     uint32_t dtype = txd_lower & (E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D);
7657c23b892Sbalrog     unsigned int split_size = txd_lower & 0xffff, bytes, sz, op;
766a0ae17a6SAndrew Jones     unsigned int msh = 0xfffff;
7677c23b892Sbalrog     uint64_t addr;
7687c23b892Sbalrog     struct e1000_context_desc *xp = (struct e1000_context_desc *)dp;
7697c23b892Sbalrog     struct e1000_tx *tp = &s->tx;
7707c23b892Sbalrog 
771e9845f09SVincenzo Maffione     s->mit_ide |= (txd_lower & E1000_TXD_CMD_IDE);
77220f3e863SLeonid Bloch     if (dtype == E1000_TXD_CMD_DEXT) {    /* context descriptor */
7737c23b892Sbalrog         op = le32_to_cpu(xp->cmd_and_length);
7747c23b892Sbalrog         tp->ipcss = xp->lower_setup.ip_fields.ipcss;
7757c23b892Sbalrog         tp->ipcso = xp->lower_setup.ip_fields.ipcso;
7767c23b892Sbalrog         tp->ipcse = le16_to_cpu(xp->lower_setup.ip_fields.ipcse);
7777c23b892Sbalrog         tp->tucss = xp->upper_setup.tcp_fields.tucss;
7787c23b892Sbalrog         tp->tucso = xp->upper_setup.tcp_fields.tucso;
7797c23b892Sbalrog         tp->tucse = le16_to_cpu(xp->upper_setup.tcp_fields.tucse);
7807c23b892Sbalrog         tp->paylen = op & 0xfffff;
7817c23b892Sbalrog         tp->hdr_len = xp->tcp_seg_setup.fields.hdr_len;
7827c23b892Sbalrog         tp->mss = le16_to_cpu(xp->tcp_seg_setup.fields.mss);
7837c23b892Sbalrog         tp->ip = (op & E1000_TXD_CMD_IP) ? 1 : 0;
7847c23b892Sbalrog         tp->tcp = (op & E1000_TXD_CMD_TCP) ? 1 : 0;
7857c23b892Sbalrog         tp->tse = (op & E1000_TXD_CMD_TSE) ? 1 : 0;
7867c23b892Sbalrog         tp->tso_frames = 0;
78720f3e863SLeonid Bloch         if (tp->tucso == 0) {    /* this is probably wrong */
7887c23b892Sbalrog             DBGOUT(TXSUM, "TCP/UDP: cso 0!\n");
7897c23b892Sbalrog             tp->tucso = tp->tucss + (tp->tcp ? 16 : 6);
7907c23b892Sbalrog         }
7917c23b892Sbalrog         return;
7921b0009dbSbalrog     } else if (dtype == (E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D)) {
7931b0009dbSbalrog         // data descriptor
794735e77ecSStefan Hajnoczi         if (tp->size == 0) {
7957c23b892Sbalrog             tp->sum_needed = le32_to_cpu(dp->upper.data) >> 8;
796735e77ecSStefan Hajnoczi         }
7971b0009dbSbalrog         tp->cptse = ( txd_lower & E1000_TXD_CMD_TSE ) ? 1 : 0;
79843ad7e3eSJes Sorensen     } else {
7991b0009dbSbalrog         // legacy descriptor
8001b0009dbSbalrog         tp->cptse = 0;
80143ad7e3eSJes Sorensen     }
8027c23b892Sbalrog 
8038f2e8d1fSaliguori     if (vlan_enabled(s) && is_vlan_txd(txd_lower) &&
8048f2e8d1fSaliguori         (tp->cptse || txd_lower & E1000_TXD_CMD_EOP)) {
8058f2e8d1fSaliguori         tp->vlan_needed = 1;
806d8ee2591SPeter Maydell         stw_be_p(tp->vlan_header,
8074e60a250SShannon Zhao                       le16_to_cpu(s->mac_reg[VET]));
808d8ee2591SPeter Maydell         stw_be_p(tp->vlan_header + 2,
8098f2e8d1fSaliguori                       le16_to_cpu(dp->upper.fields.special));
8108f2e8d1fSaliguori     }
8118f2e8d1fSaliguori 
8127c23b892Sbalrog     addr = le64_to_cpu(dp->buffer_addr);
8131b0009dbSbalrog     if (tp->tse && tp->cptse) {
814a0ae17a6SAndrew Jones         msh = tp->hdr_len + tp->mss;
8157c23b892Sbalrog         do {
8167c23b892Sbalrog             bytes = split_size;
8177c23b892Sbalrog             if (tp->size + bytes > msh)
8187c23b892Sbalrog                 bytes = msh - tp->size;
81965f82df0SAnthony Liguori 
82065f82df0SAnthony Liguori             bytes = MIN(sizeof(tp->data) - tp->size, bytes);
821b08340d5SAndreas Färber             pci_dma_read(d, addr, tp->data + tp->size, bytes);
822a0ae17a6SAndrew Jones             sz = tp->size + bytes;
823a0ae17a6SAndrew Jones             if (sz >= tp->hdr_len && tp->size < tp->hdr_len) {
824a0ae17a6SAndrew Jones                 memmove(tp->header, tp->data, tp->hdr_len);
825a0ae17a6SAndrew Jones             }
8267c23b892Sbalrog             tp->size = sz;
8277c23b892Sbalrog             addr += bytes;
8287c23b892Sbalrog             if (sz == msh) {
8297c23b892Sbalrog                 xmit_seg(s);
830a0ae17a6SAndrew Jones                 memmove(tp->data, tp->header, tp->hdr_len);
831a0ae17a6SAndrew Jones                 tp->size = tp->hdr_len;
8327c23b892Sbalrog             }
833b947ac2bSP J P             split_size -= bytes;
834b947ac2bSP J P         } while (bytes && split_size);
8351b0009dbSbalrog     } else if (!tp->tse && tp->cptse) {
8361b0009dbSbalrog         // context descriptor TSE is not set, while data descriptor TSE is set
837362f5fb5SStefan Weil         DBGOUT(TXERR, "TCP segmentation error\n");
8381b0009dbSbalrog     } else {
83965f82df0SAnthony Liguori         split_size = MIN(sizeof(tp->data) - tp->size, split_size);
840b08340d5SAndreas Färber         pci_dma_read(d, addr, tp->data + tp->size, split_size);
8411b0009dbSbalrog         tp->size += split_size;
8421b0009dbSbalrog     }
8437c23b892Sbalrog 
8447c23b892Sbalrog     if (!(txd_lower & E1000_TXD_CMD_EOP))
8457c23b892Sbalrog         return;
846a0ae17a6SAndrew Jones     if (!(tp->tse && tp->cptse && tp->size < tp->hdr_len)) {
8477c23b892Sbalrog         xmit_seg(s);
848a0ae17a6SAndrew Jones     }
8497c23b892Sbalrog     tp->tso_frames = 0;
8507c23b892Sbalrog     tp->sum_needed = 0;
8518f2e8d1fSaliguori     tp->vlan_needed = 0;
8527c23b892Sbalrog     tp->size = 0;
8531b0009dbSbalrog     tp->cptse = 0;
8547c23b892Sbalrog }
8557c23b892Sbalrog 
8567c23b892Sbalrog static uint32_t
85762ecbd35SEduard - Gabriel Munteanu txdesc_writeback(E1000State *s, dma_addr_t base, struct e1000_tx_desc *dp)
8587c23b892Sbalrog {
859b08340d5SAndreas Färber     PCIDevice *d = PCI_DEVICE(s);
8607c23b892Sbalrog     uint32_t txd_upper, txd_lower = le32_to_cpu(dp->lower.data);
8617c23b892Sbalrog 
8627c23b892Sbalrog     if (!(txd_lower & (E1000_TXD_CMD_RS|E1000_TXD_CMD_RPS)))
8637c23b892Sbalrog         return 0;
8647c23b892Sbalrog     txd_upper = (le32_to_cpu(dp->upper.data) | E1000_TXD_STAT_DD) &
8657c23b892Sbalrog                 ~(E1000_TXD_STAT_EC | E1000_TXD_STAT_LC | E1000_TXD_STAT_TU);
8667c23b892Sbalrog     dp->upper.data = cpu_to_le32(txd_upper);
867b08340d5SAndreas Färber     pci_dma_write(d, base + ((char *)&dp->upper - (char *)dp),
86800c3a05bSDavid Gibson                   &dp->upper, sizeof(dp->upper));
8697c23b892Sbalrog     return E1000_ICR_TXDW;
8707c23b892Sbalrog }
8717c23b892Sbalrog 
872d17161f6SKevin Wolf static uint64_t tx_desc_base(E1000State *s)
873d17161f6SKevin Wolf {
874d17161f6SKevin Wolf     uint64_t bah = s->mac_reg[TDBAH];
875d17161f6SKevin Wolf     uint64_t bal = s->mac_reg[TDBAL] & ~0xf;
876d17161f6SKevin Wolf 
877d17161f6SKevin Wolf     return (bah << 32) + bal;
878d17161f6SKevin Wolf }
879d17161f6SKevin Wolf 
8807c23b892Sbalrog static void
8817c23b892Sbalrog start_xmit(E1000State *s)
8827c23b892Sbalrog {
883b08340d5SAndreas Färber     PCIDevice *d = PCI_DEVICE(s);
88462ecbd35SEduard - Gabriel Munteanu     dma_addr_t base;
8857c23b892Sbalrog     struct e1000_tx_desc desc;
8867c23b892Sbalrog     uint32_t tdh_start = s->mac_reg[TDH], cause = E1000_ICS_TXQE;
8877c23b892Sbalrog 
8887c23b892Sbalrog     if (!(s->mac_reg[TCTL] & E1000_TCTL_EN)) {
8897c23b892Sbalrog         DBGOUT(TX, "tx disabled\n");
8907c23b892Sbalrog         return;
8917c23b892Sbalrog     }
8927c23b892Sbalrog 
8937c23b892Sbalrog     while (s->mac_reg[TDH] != s->mac_reg[TDT]) {
894d17161f6SKevin Wolf         base = tx_desc_base(s) +
8957c23b892Sbalrog                sizeof(struct e1000_tx_desc) * s->mac_reg[TDH];
896b08340d5SAndreas Färber         pci_dma_read(d, base, &desc, sizeof(desc));
8977c23b892Sbalrog 
8987c23b892Sbalrog         DBGOUT(TX, "index %d: %p : %x %x\n", s->mac_reg[TDH],
8996106075bSths                (void *)(intptr_t)desc.buffer_addr, desc.lower.data,
9007c23b892Sbalrog                desc.upper.data);
9017c23b892Sbalrog 
9027c23b892Sbalrog         process_tx_desc(s, &desc);
90362ecbd35SEduard - Gabriel Munteanu         cause |= txdesc_writeback(s, base, &desc);
9047c23b892Sbalrog 
9057c23b892Sbalrog         if (++s->mac_reg[TDH] * sizeof(desc) >= s->mac_reg[TDLEN])
9067c23b892Sbalrog             s->mac_reg[TDH] = 0;
9077c23b892Sbalrog         /*
9087c23b892Sbalrog          * the following could happen only if guest sw assigns
9097c23b892Sbalrog          * bogus values to TDT/TDLEN.
9107c23b892Sbalrog          * there's nothing too intelligent we could do about this.
9117c23b892Sbalrog          */
9127c23b892Sbalrog         if (s->mac_reg[TDH] == tdh_start) {
9137c23b892Sbalrog             DBGOUT(TXERR, "TDH wraparound @%x, TDT %x, TDLEN %x\n",
9147c23b892Sbalrog                    tdh_start, s->mac_reg[TDT], s->mac_reg[TDLEN]);
9157c23b892Sbalrog             break;
9167c23b892Sbalrog         }
9177c23b892Sbalrog     }
9187c23b892Sbalrog     set_ics(s, 0, cause);
9197c23b892Sbalrog }
9207c23b892Sbalrog 
9217c23b892Sbalrog static int
9227c23b892Sbalrog receive_filter(E1000State *s, const uint8_t *buf, int size)
9237c23b892Sbalrog {
924af2960f9SBlue Swirl     static const int mta_shift[] = {4, 3, 2, 0};
9257c23b892Sbalrog     uint32_t f, rctl = s->mac_reg[RCTL], ra[2], *rp;
9264aeea330SLeonid Bloch     int isbcast = !memcmp(buf, bcast, sizeof bcast), ismcast = (buf[0] & 1);
9277c23b892Sbalrog 
9288f2e8d1fSaliguori     if (is_vlan_packet(s, buf) && vlan_rx_filter_enabled(s)) {
9298f2e8d1fSaliguori         uint16_t vid = be16_to_cpup((uint16_t *)(buf + 14));
9308f2e8d1fSaliguori         uint32_t vfta = le32_to_cpup((uint32_t *)(s->mac_reg + VFTA) +
9318f2e8d1fSaliguori                                      ((vid >> 5) & 0x7f));
9328f2e8d1fSaliguori         if ((vfta & (1 << (vid & 0x1f))) == 0)
9338f2e8d1fSaliguori             return 0;
9348f2e8d1fSaliguori     }
9358f2e8d1fSaliguori 
9364aeea330SLeonid Bloch     if (!isbcast && !ismcast && (rctl & E1000_RCTL_UPE)) { /* promiscuous ucast */
9377c23b892Sbalrog         return 1;
9384aeea330SLeonid Bloch     }
9397c23b892Sbalrog 
9404aeea330SLeonid Bloch     if (ismcast && (rctl & E1000_RCTL_MPE)) {          /* promiscuous mcast */
9413b274301SLeonid Bloch         inc_reg_if_not_full(s, MPRC);
9427c23b892Sbalrog         return 1;
9434aeea330SLeonid Bloch     }
9447c23b892Sbalrog 
9454aeea330SLeonid Bloch     if (isbcast && (rctl & E1000_RCTL_BAM)) {          /* broadcast enabled */
9463b274301SLeonid Bloch         inc_reg_if_not_full(s, BPRC);
9477c23b892Sbalrog         return 1;
9484aeea330SLeonid Bloch     }
9497c23b892Sbalrog 
9507c23b892Sbalrog     for (rp = s->mac_reg + RA; rp < s->mac_reg + RA + 32; rp += 2) {
9517c23b892Sbalrog         if (!(rp[1] & E1000_RAH_AV))
9527c23b892Sbalrog             continue;
9537c23b892Sbalrog         ra[0] = cpu_to_le32(rp[0]);
9547c23b892Sbalrog         ra[1] = cpu_to_le32(rp[1]);
9557c23b892Sbalrog         if (!memcmp(buf, (uint8_t *)ra, 6)) {
9567c23b892Sbalrog             DBGOUT(RXFILTER,
9577c23b892Sbalrog                    "unicast match[%d]: %02x:%02x:%02x:%02x:%02x:%02x\n",
9587c23b892Sbalrog                    (int)(rp - s->mac_reg - RA)/2,
9597c23b892Sbalrog                    buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);
9607c23b892Sbalrog             return 1;
9617c23b892Sbalrog         }
9627c23b892Sbalrog     }
9637c23b892Sbalrog     DBGOUT(RXFILTER, "unicast mismatch: %02x:%02x:%02x:%02x:%02x:%02x\n",
9647c23b892Sbalrog            buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);
9657c23b892Sbalrog 
9667c23b892Sbalrog     f = mta_shift[(rctl >> E1000_RCTL_MO_SHIFT) & 3];
9677c23b892Sbalrog     f = (((buf[5] << 8) | buf[4]) >> f) & 0xfff;
9683b274301SLeonid Bloch     if (s->mac_reg[MTA + (f >> 5)] & (1 << (f & 0x1f))) {
9693b274301SLeonid Bloch         inc_reg_if_not_full(s, MPRC);
9707c23b892Sbalrog         return 1;
9713b274301SLeonid Bloch     }
9727c23b892Sbalrog     DBGOUT(RXFILTER,
9737c23b892Sbalrog            "dropping, inexact filter mismatch: %02x:%02x:%02x:%02x:%02x:%02x MO %d MTA[%d] %x\n",
9747c23b892Sbalrog            buf[0], buf[1], buf[2], buf[3], buf[4], buf[5],
9757c23b892Sbalrog            (rctl >> E1000_RCTL_MO_SHIFT) & 3, f >> 5,
9767c23b892Sbalrog            s->mac_reg[MTA + (f >> 5)]);
9777c23b892Sbalrog 
9787c23b892Sbalrog     return 0;
9797c23b892Sbalrog }
9807c23b892Sbalrog 
98199ed7e30Saliguori static void
9824e68f7a0SStefan Hajnoczi e1000_set_link_status(NetClientState *nc)
98399ed7e30Saliguori {
984cc1f0f45SJason Wang     E1000State *s = qemu_get_nic_opaque(nc);
98599ed7e30Saliguori     uint32_t old_status = s->mac_reg[STATUS];
98699ed7e30Saliguori 
987d4044c2aSBjørn Mork     if (nc->link_down) {
98871aadd3cSJason Wang         e1000_link_down(s);
989d4044c2aSBjørn Mork     } else {
990d7a41552SGabriel L. Somlo         if (have_autoneg(s) &&
9916a2acedbSGabriel L. Somlo             !(s->phy_reg[PHY_STATUS] & MII_SR_AUTONEG_COMPLETE)) {
9926a2acedbSGabriel L. Somlo             /* emulate auto-negotiation if supported */
9936a2acedbSGabriel L. Somlo             timer_mod(s->autoneg_timer,
9946a2acedbSGabriel L. Somlo                       qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 500);
9956a2acedbSGabriel L. Somlo         } else {
99671aadd3cSJason Wang             e1000_link_up(s);
997d4044c2aSBjørn Mork         }
9986a2acedbSGabriel L. Somlo     }
99999ed7e30Saliguori 
100099ed7e30Saliguori     if (s->mac_reg[STATUS] != old_status)
100199ed7e30Saliguori         set_ics(s, 0, E1000_ICR_LSC);
100299ed7e30Saliguori }
100399ed7e30Saliguori 
1004322fd48aSMichael S. Tsirkin static bool e1000_has_rxbufs(E1000State *s, size_t total_size)
1005322fd48aSMichael S. Tsirkin {
1006322fd48aSMichael S. Tsirkin     int bufs;
1007322fd48aSMichael S. Tsirkin     /* Fast-path short packets */
1008322fd48aSMichael S. Tsirkin     if (total_size <= s->rxbuf_size) {
1009e5b8b0d4SDmitry Fleytman         return s->mac_reg[RDH] != s->mac_reg[RDT];
1010322fd48aSMichael S. Tsirkin     }
1011322fd48aSMichael S. Tsirkin     if (s->mac_reg[RDH] < s->mac_reg[RDT]) {
1012322fd48aSMichael S. Tsirkin         bufs = s->mac_reg[RDT] - s->mac_reg[RDH];
1013e5b8b0d4SDmitry Fleytman     } else if (s->mac_reg[RDH] > s->mac_reg[RDT]) {
1014322fd48aSMichael S. Tsirkin         bufs = s->mac_reg[RDLEN] /  sizeof(struct e1000_rx_desc) +
1015322fd48aSMichael S. Tsirkin             s->mac_reg[RDT] - s->mac_reg[RDH];
1016322fd48aSMichael S. Tsirkin     } else {
1017322fd48aSMichael S. Tsirkin         return false;
1018322fd48aSMichael S. Tsirkin     }
1019322fd48aSMichael S. Tsirkin     return total_size <= bufs * s->rxbuf_size;
1020322fd48aSMichael S. Tsirkin }
1021322fd48aSMichael S. Tsirkin 
10226cdfab28SMichael S. Tsirkin static int
10234e68f7a0SStefan Hajnoczi e1000_can_receive(NetClientState *nc)
10246cdfab28SMichael S. Tsirkin {
1025cc1f0f45SJason Wang     E1000State *s = qemu_get_nic_opaque(nc);
10266cdfab28SMichael S. Tsirkin 
1027ddcb73b7SMichael S. Tsirkin     return (s->mac_reg[STATUS] & E1000_STATUS_LU) &&
102820302e71SMichael S. Tsirkin         (s->mac_reg[RCTL] & E1000_RCTL_EN) &&
102920302e71SMichael S. Tsirkin         (s->parent_obj.config[PCI_COMMAND] & PCI_COMMAND_MASTER) &&
103020302e71SMichael S. Tsirkin         e1000_has_rxbufs(s, 1);
10316cdfab28SMichael S. Tsirkin }
10326cdfab28SMichael S. Tsirkin 
1033d17161f6SKevin Wolf static uint64_t rx_desc_base(E1000State *s)
1034d17161f6SKevin Wolf {
1035d17161f6SKevin Wolf     uint64_t bah = s->mac_reg[RDBAH];
1036d17161f6SKevin Wolf     uint64_t bal = s->mac_reg[RDBAL] & ~0xf;
1037d17161f6SKevin Wolf 
1038d17161f6SKevin Wolf     return (bah << 32) + bal;
1039d17161f6SKevin Wolf }
1040d17161f6SKevin Wolf 
10414f1c942bSMark McLoughlin static ssize_t
104297410ddeSVincenzo Maffione e1000_receive_iov(NetClientState *nc, const struct iovec *iov, int iovcnt)
10437c23b892Sbalrog {
1044cc1f0f45SJason Wang     E1000State *s = qemu_get_nic_opaque(nc);
1045b08340d5SAndreas Färber     PCIDevice *d = PCI_DEVICE(s);
10467c23b892Sbalrog     struct e1000_rx_desc desc;
104762ecbd35SEduard - Gabriel Munteanu     dma_addr_t base;
10487c23b892Sbalrog     unsigned int n, rdt;
10497c23b892Sbalrog     uint32_t rdh_start;
10508f2e8d1fSaliguori     uint16_t vlan_special = 0;
105197410ddeSVincenzo Maffione     uint8_t vlan_status = 0;
105278aeb23eSStefan Hajnoczi     uint8_t min_buf[MIN_BUF_SIZE];
105397410ddeSVincenzo Maffione     struct iovec min_iov;
105497410ddeSVincenzo Maffione     uint8_t *filter_buf = iov->iov_base;
105597410ddeSVincenzo Maffione     size_t size = iov_size(iov, iovcnt);
105697410ddeSVincenzo Maffione     size_t iov_ofs = 0;
1057b19487e2SMichael S. Tsirkin     size_t desc_offset;
1058b19487e2SMichael S. Tsirkin     size_t desc_size;
1059b19487e2SMichael S. Tsirkin     size_t total_size;
10603b274301SLeonid Bloch     static const int PRCregs[6] = { PRC64, PRC127, PRC255, PRC511,
10613b274301SLeonid Bloch                                     PRC1023, PRC1522 };
10627c23b892Sbalrog 
1063ddcb73b7SMichael S. Tsirkin     if (!(s->mac_reg[STATUS] & E1000_STATUS_LU)) {
10644f1c942bSMark McLoughlin         return -1;
1065ddcb73b7SMichael S. Tsirkin     }
1066ddcb73b7SMichael S. Tsirkin 
1067ddcb73b7SMichael S. Tsirkin     if (!(s->mac_reg[RCTL] & E1000_RCTL_EN)) {
1068ddcb73b7SMichael S. Tsirkin         return -1;
1069ddcb73b7SMichael S. Tsirkin     }
10707c23b892Sbalrog 
107178aeb23eSStefan Hajnoczi     /* Pad to minimum Ethernet frame length */
107278aeb23eSStefan Hajnoczi     if (size < sizeof(min_buf)) {
107397410ddeSVincenzo Maffione         iov_to_buf(iov, iovcnt, 0, min_buf, size);
107478aeb23eSStefan Hajnoczi         memset(&min_buf[size], 0, sizeof(min_buf) - size);
10753b274301SLeonid Bloch         inc_reg_if_not_full(s, RUC);
107697410ddeSVincenzo Maffione         min_iov.iov_base = filter_buf = min_buf;
107797410ddeSVincenzo Maffione         min_iov.iov_len = size = sizeof(min_buf);
107897410ddeSVincenzo Maffione         iovcnt = 1;
107997410ddeSVincenzo Maffione         iov = &min_iov;
108097410ddeSVincenzo Maffione     } else if (iov->iov_len < MAXIMUM_ETHERNET_HDR_LEN) {
108197410ddeSVincenzo Maffione         /* This is very unlikely, but may happen. */
108297410ddeSVincenzo Maffione         iov_to_buf(iov, iovcnt, 0, min_buf, MAXIMUM_ETHERNET_HDR_LEN);
108397410ddeSVincenzo Maffione         filter_buf = min_buf;
108478aeb23eSStefan Hajnoczi     }
108578aeb23eSStefan Hajnoczi 
1086b0d9ffcdSMichael Contreras     /* Discard oversized packets if !LPE and !SBP. */
10872c0331f4SMichael Contreras     if ((size > MAXIMUM_ETHERNET_LPE_SIZE ||
10882c0331f4SMichael Contreras         (size > MAXIMUM_ETHERNET_VLAN_SIZE
10892c0331f4SMichael Contreras         && !(s->mac_reg[RCTL] & E1000_RCTL_LPE)))
1090b0d9ffcdSMichael Contreras         && !(s->mac_reg[RCTL] & E1000_RCTL_SBP)) {
10913b274301SLeonid Bloch         inc_reg_if_not_full(s, ROC);
1092b0d9ffcdSMichael Contreras         return size;
1093b0d9ffcdSMichael Contreras     }
1094b0d9ffcdSMichael Contreras 
109597410ddeSVincenzo Maffione     if (!receive_filter(s, filter_buf, size)) {
10964f1c942bSMark McLoughlin         return size;
109797410ddeSVincenzo Maffione     }
10987c23b892Sbalrog 
109997410ddeSVincenzo Maffione     if (vlan_enabled(s) && is_vlan_packet(s, filter_buf)) {
110097410ddeSVincenzo Maffione         vlan_special = cpu_to_le16(be16_to_cpup((uint16_t *)(filter_buf
110197410ddeSVincenzo Maffione                                                                 + 14)));
110297410ddeSVincenzo Maffione         iov_ofs = 4;
110397410ddeSVincenzo Maffione         if (filter_buf == iov->iov_base) {
110497410ddeSVincenzo Maffione             memmove(filter_buf + 4, filter_buf, 12);
110597410ddeSVincenzo Maffione         } else {
110697410ddeSVincenzo Maffione             iov_from_buf(iov, iovcnt, 4, filter_buf, 12);
110797410ddeSVincenzo Maffione             while (iov->iov_len <= iov_ofs) {
110897410ddeSVincenzo Maffione                 iov_ofs -= iov->iov_len;
110997410ddeSVincenzo Maffione                 iov++;
111097410ddeSVincenzo Maffione             }
111197410ddeSVincenzo Maffione         }
11128f2e8d1fSaliguori         vlan_status = E1000_RXD_STAT_VP;
11138f2e8d1fSaliguori         size -= 4;
11148f2e8d1fSaliguori     }
11158f2e8d1fSaliguori 
11167c23b892Sbalrog     rdh_start = s->mac_reg[RDH];
1117b19487e2SMichael S. Tsirkin     desc_offset = 0;
1118b19487e2SMichael S. Tsirkin     total_size = size + fcs_len(s);
1119322fd48aSMichael S. Tsirkin     if (!e1000_has_rxbufs(s, total_size)) {
1120322fd48aSMichael S. Tsirkin             set_ics(s, 0, E1000_ICS_RXO);
1121322fd48aSMichael S. Tsirkin             return -1;
1122322fd48aSMichael S. Tsirkin     }
11237c23b892Sbalrog     do {
1124b19487e2SMichael S. Tsirkin         desc_size = total_size - desc_offset;
1125b19487e2SMichael S. Tsirkin         if (desc_size > s->rxbuf_size) {
1126b19487e2SMichael S. Tsirkin             desc_size = s->rxbuf_size;
1127b19487e2SMichael S. Tsirkin         }
1128d17161f6SKevin Wolf         base = rx_desc_base(s) + sizeof(desc) * s->mac_reg[RDH];
1129b08340d5SAndreas Färber         pci_dma_read(d, base, &desc, sizeof(desc));
11308f2e8d1fSaliguori         desc.special = vlan_special;
11318f2e8d1fSaliguori         desc.status |= (vlan_status | E1000_RXD_STAT_DD);
11327c23b892Sbalrog         if (desc.buffer_addr) {
1133b19487e2SMichael S. Tsirkin             if (desc_offset < size) {
113497410ddeSVincenzo Maffione                 size_t iov_copy;
113597410ddeSVincenzo Maffione                 hwaddr ba = le64_to_cpu(desc.buffer_addr);
1136b19487e2SMichael S. Tsirkin                 size_t copy_size = size - desc_offset;
1137b19487e2SMichael S. Tsirkin                 if (copy_size > s->rxbuf_size) {
1138b19487e2SMichael S. Tsirkin                     copy_size = s->rxbuf_size;
1139b19487e2SMichael S. Tsirkin                 }
114097410ddeSVincenzo Maffione                 do {
114197410ddeSVincenzo Maffione                     iov_copy = MIN(copy_size, iov->iov_len - iov_ofs);
114297410ddeSVincenzo Maffione                     pci_dma_write(d, ba, iov->iov_base + iov_ofs, iov_copy);
114397410ddeSVincenzo Maffione                     copy_size -= iov_copy;
114497410ddeSVincenzo Maffione                     ba += iov_copy;
114597410ddeSVincenzo Maffione                     iov_ofs += iov_copy;
114697410ddeSVincenzo Maffione                     if (iov_ofs == iov->iov_len) {
114797410ddeSVincenzo Maffione                         iov++;
114897410ddeSVincenzo Maffione                         iov_ofs = 0;
114997410ddeSVincenzo Maffione                     }
115097410ddeSVincenzo Maffione                 } while (copy_size);
1151b19487e2SMichael S. Tsirkin             }
1152b19487e2SMichael S. Tsirkin             desc_offset += desc_size;
1153b19487e2SMichael S. Tsirkin             desc.length = cpu_to_le16(desc_size);
1154ee912ccfSMichael S. Tsirkin             if (desc_offset >= total_size) {
11557c23b892Sbalrog                 desc.status |= E1000_RXD_STAT_EOP | E1000_RXD_STAT_IXSM;
1156b19487e2SMichael S. Tsirkin             } else {
1157ee912ccfSMichael S. Tsirkin                 /* Guest zeroing out status is not a hardware requirement.
1158ee912ccfSMichael S. Tsirkin                    Clear EOP in case guest didn't do it. */
1159ee912ccfSMichael S. Tsirkin                 desc.status &= ~E1000_RXD_STAT_EOP;
1160b19487e2SMichael S. Tsirkin             }
116143ad7e3eSJes Sorensen         } else { // as per intel docs; skip descriptors with null buf addr
11627c23b892Sbalrog             DBGOUT(RX, "Null RX descriptor!!\n");
116343ad7e3eSJes Sorensen         }
1164b08340d5SAndreas Färber         pci_dma_write(d, base, &desc, sizeof(desc));
11657c23b892Sbalrog 
11667c23b892Sbalrog         if (++s->mac_reg[RDH] * sizeof(desc) >= s->mac_reg[RDLEN])
11677c23b892Sbalrog             s->mac_reg[RDH] = 0;
11687c23b892Sbalrog         /* see comment in start_xmit; same here */
11697c23b892Sbalrog         if (s->mac_reg[RDH] == rdh_start) {
11707c23b892Sbalrog             DBGOUT(RXERR, "RDH wraparound @%x, RDT %x, RDLEN %x\n",
11717c23b892Sbalrog                    rdh_start, s->mac_reg[RDT], s->mac_reg[RDLEN]);
11727c23b892Sbalrog             set_ics(s, 0, E1000_ICS_RXO);
11734f1c942bSMark McLoughlin             return -1;
11747c23b892Sbalrog         }
1175b19487e2SMichael S. Tsirkin     } while (desc_offset < total_size);
11767c23b892Sbalrog 
11773b274301SLeonid Bloch     increase_size_stats(s, PRCregs, total_size);
11781f67f92cSLeonid Bloch     inc_reg_if_not_full(s, TPR);
11791f67f92cSLeonid Bloch     s->mac_reg[GPRC] = s->mac_reg[TPR];
1180a05e8a6eSMichael S. Tsirkin     /* TOR - Total Octets Received:
1181a05e8a6eSMichael S. Tsirkin      * This register includes bytes received in a packet from the <Destination
1182a05e8a6eSMichael S. Tsirkin      * Address> field through the <CRC> field, inclusively.
118345e93764SLeonid Bloch      * Always include FCS length (4) in size.
1184a05e8a6eSMichael S. Tsirkin      */
118545e93764SLeonid Bloch     grow_8reg_if_not_full(s, TORL, size+4);
11863b274301SLeonid Bloch     s->mac_reg[GORCL] = s->mac_reg[TORL];
11873b274301SLeonid Bloch     s->mac_reg[GORCH] = s->mac_reg[TORH];
11887c23b892Sbalrog 
11897c23b892Sbalrog     n = E1000_ICS_RXT0;
11907c23b892Sbalrog     if ((rdt = s->mac_reg[RDT]) < s->mac_reg[RDH])
11917c23b892Sbalrog         rdt += s->mac_reg[RDLEN] / sizeof(desc);
1192bf16cc8fSaliguori     if (((rdt - s->mac_reg[RDH]) * sizeof(desc)) <= s->mac_reg[RDLEN] >>
1193bf16cc8fSaliguori         s->rxbuf_min_shift)
11947c23b892Sbalrog         n |= E1000_ICS_RXDMT0;
11957c23b892Sbalrog 
11967c23b892Sbalrog     set_ics(s, 0, n);
11974f1c942bSMark McLoughlin 
11984f1c942bSMark McLoughlin     return size;
11997c23b892Sbalrog }
12007c23b892Sbalrog 
120197410ddeSVincenzo Maffione static ssize_t
120297410ddeSVincenzo Maffione e1000_receive(NetClientState *nc, const uint8_t *buf, size_t size)
120397410ddeSVincenzo Maffione {
120497410ddeSVincenzo Maffione     const struct iovec iov = {
120597410ddeSVincenzo Maffione         .iov_base = (uint8_t *)buf,
120697410ddeSVincenzo Maffione         .iov_len = size
120797410ddeSVincenzo Maffione     };
120897410ddeSVincenzo Maffione 
120997410ddeSVincenzo Maffione     return e1000_receive_iov(nc, &iov, 1);
121097410ddeSVincenzo Maffione }
121197410ddeSVincenzo Maffione 
12127c23b892Sbalrog static uint32_t
12137c23b892Sbalrog mac_readreg(E1000State *s, int index)
12147c23b892Sbalrog {
12157c23b892Sbalrog     return s->mac_reg[index];
12167c23b892Sbalrog }
12177c23b892Sbalrog 
12187c23b892Sbalrog static uint32_t
121972ea771cSLeonid Bloch mac_low4_read(E1000State *s, int index)
122072ea771cSLeonid Bloch {
122172ea771cSLeonid Bloch     return s->mac_reg[index] & 0xf;
122272ea771cSLeonid Bloch }
122372ea771cSLeonid Bloch 
122472ea771cSLeonid Bloch static uint32_t
122572ea771cSLeonid Bloch mac_low11_read(E1000State *s, int index)
122672ea771cSLeonid Bloch {
122772ea771cSLeonid Bloch     return s->mac_reg[index] & 0x7ff;
122872ea771cSLeonid Bloch }
122972ea771cSLeonid Bloch 
123072ea771cSLeonid Bloch static uint32_t
123172ea771cSLeonid Bloch mac_low13_read(E1000State *s, int index)
123272ea771cSLeonid Bloch {
123372ea771cSLeonid Bloch     return s->mac_reg[index] & 0x1fff;
123472ea771cSLeonid Bloch }
123572ea771cSLeonid Bloch 
123672ea771cSLeonid Bloch static uint32_t
123772ea771cSLeonid Bloch mac_low16_read(E1000State *s, int index)
123872ea771cSLeonid Bloch {
123972ea771cSLeonid Bloch     return s->mac_reg[index] & 0xffff;
124072ea771cSLeonid Bloch }
124172ea771cSLeonid Bloch 
124272ea771cSLeonid Bloch static uint32_t
12437c23b892Sbalrog mac_icr_read(E1000State *s, int index)
12447c23b892Sbalrog {
12457c23b892Sbalrog     uint32_t ret = s->mac_reg[ICR];
12467c23b892Sbalrog 
12477c23b892Sbalrog     DBGOUT(INTERRUPT, "ICR read: %x\n", ret);
12487c23b892Sbalrog     set_interrupt_cause(s, 0, 0);
12497c23b892Sbalrog     return ret;
12507c23b892Sbalrog }
12517c23b892Sbalrog 
12527c23b892Sbalrog static uint32_t
12537c23b892Sbalrog mac_read_clr4(E1000State *s, int index)
12547c23b892Sbalrog {
12557c23b892Sbalrog     uint32_t ret = s->mac_reg[index];
12567c23b892Sbalrog 
12577c23b892Sbalrog     s->mac_reg[index] = 0;
12587c23b892Sbalrog     return ret;
12597c23b892Sbalrog }
12607c23b892Sbalrog 
12617c23b892Sbalrog static uint32_t
12627c23b892Sbalrog mac_read_clr8(E1000State *s, int index)
12637c23b892Sbalrog {
12647c23b892Sbalrog     uint32_t ret = s->mac_reg[index];
12657c23b892Sbalrog 
12667c23b892Sbalrog     s->mac_reg[index] = 0;
12677c23b892Sbalrog     s->mac_reg[index-1] = 0;
12687c23b892Sbalrog     return ret;
12697c23b892Sbalrog }
12707c23b892Sbalrog 
12717c23b892Sbalrog static void
12727c23b892Sbalrog mac_writereg(E1000State *s, int index, uint32_t val)
12737c23b892Sbalrog {
12747c36507cSAmos Kong     uint32_t macaddr[2];
12757c36507cSAmos Kong 
12767c23b892Sbalrog     s->mac_reg[index] = val;
12777c36507cSAmos Kong 
127890d131fbSMichael S. Tsirkin     if (index == RA + 1) {
12797c36507cSAmos Kong         macaddr[0] = cpu_to_le32(s->mac_reg[RA]);
12807c36507cSAmos Kong         macaddr[1] = cpu_to_le32(s->mac_reg[RA + 1]);
12817c36507cSAmos Kong         qemu_format_nic_info_str(qemu_get_queue(s->nic), (uint8_t *)macaddr);
12827c36507cSAmos Kong     }
12837c23b892Sbalrog }
12847c23b892Sbalrog 
12857c23b892Sbalrog static void
12867c23b892Sbalrog set_rdt(E1000State *s, int index, uint32_t val)
12877c23b892Sbalrog {
12887c23b892Sbalrog     s->mac_reg[index] = val & 0xffff;
1289e8b4c680SPaolo Bonzini     if (e1000_has_rxbufs(s, 1)) {
1290b356f76dSJason Wang         qemu_flush_queued_packets(qemu_get_queue(s->nic));
1291e8b4c680SPaolo Bonzini     }
12927c23b892Sbalrog }
12937c23b892Sbalrog 
12947c23b892Sbalrog static void
12957c23b892Sbalrog set_16bit(E1000State *s, int index, uint32_t val)
12967c23b892Sbalrog {
12977c23b892Sbalrog     s->mac_reg[index] = val & 0xffff;
12987c23b892Sbalrog }
12997c23b892Sbalrog 
13007c23b892Sbalrog static void
13017c23b892Sbalrog set_dlen(E1000State *s, int index, uint32_t val)
13027c23b892Sbalrog {
13037c23b892Sbalrog     s->mac_reg[index] = val & 0xfff80;
13047c23b892Sbalrog }
13057c23b892Sbalrog 
13067c23b892Sbalrog static void
13077c23b892Sbalrog set_tctl(E1000State *s, int index, uint32_t val)
13087c23b892Sbalrog {
13097c23b892Sbalrog     s->mac_reg[index] = val;
13107c23b892Sbalrog     s->mac_reg[TDT] &= 0xffff;
13117c23b892Sbalrog     start_xmit(s);
13127c23b892Sbalrog }
13137c23b892Sbalrog 
13147c23b892Sbalrog static void
13157c23b892Sbalrog set_icr(E1000State *s, int index, uint32_t val)
13167c23b892Sbalrog {
13177c23b892Sbalrog     DBGOUT(INTERRUPT, "set_icr %x\n", val);
13187c23b892Sbalrog     set_interrupt_cause(s, 0, s->mac_reg[ICR] & ~val);
13197c23b892Sbalrog }
13207c23b892Sbalrog 
13217c23b892Sbalrog static void
13227c23b892Sbalrog set_imc(E1000State *s, int index, uint32_t val)
13237c23b892Sbalrog {
13247c23b892Sbalrog     s->mac_reg[IMS] &= ~val;
13257c23b892Sbalrog     set_ics(s, 0, 0);
13267c23b892Sbalrog }
13277c23b892Sbalrog 
13287c23b892Sbalrog static void
13297c23b892Sbalrog set_ims(E1000State *s, int index, uint32_t val)
13307c23b892Sbalrog {
13317c23b892Sbalrog     s->mac_reg[IMS] |= val;
13327c23b892Sbalrog     set_ics(s, 0, 0);
13337c23b892Sbalrog }
13347c23b892Sbalrog 
13357c23b892Sbalrog #define getreg(x)    [x] = mac_readreg
13367c23b892Sbalrog static uint32_t (*macreg_readops[])(E1000State *, int) = {
13377c23b892Sbalrog     getreg(PBA),      getreg(RCTL),     getreg(TDH),      getreg(TXDCTL),
13387c23b892Sbalrog     getreg(WUFC),     getreg(TDT),      getreg(CTRL),     getreg(LEDCTL),
13397c23b892Sbalrog     getreg(MANC),     getreg(MDIC),     getreg(SWSM),     getreg(STATUS),
13407c23b892Sbalrog     getreg(TORL),     getreg(TOTL),     getreg(IMS),      getreg(TCTL),
1341b1332393SBill Paul     getreg(RDH),      getreg(RDT),      getreg(VET),      getreg(ICS),
1342a00b2335SKay Ackermann     getreg(TDBAL),    getreg(TDBAH),    getreg(RDBAH),    getreg(RDBAL),
1343e9845f09SVincenzo Maffione     getreg(TDLEN),    getreg(RDLEN),    getreg(RDTR),     getreg(RADV),
134472ea771cSLeonid Bloch     getreg(TADV),     getreg(ITR),      getreg(FCRUC),    getreg(IPAV),
134572ea771cSLeonid Bloch     getreg(WUC),      getreg(WUS),      getreg(SCC),      getreg(ECOL),
134672ea771cSLeonid Bloch     getreg(MCC),      getreg(LATECOL),  getreg(COLC),     getreg(DC),
134772ea771cSLeonid Bloch     getreg(TNCRS),    getreg(SEC),      getreg(CEXTERR),  getreg(RLEC),
134872ea771cSLeonid Bloch     getreg(XONRXC),   getreg(XONTXC),   getreg(XOFFRXC),  getreg(XOFFTXC),
134972ea771cSLeonid Bloch     getreg(RFC),      getreg(RJC),      getreg(RNBC),     getreg(TSCTFC),
13503b274301SLeonid Bloch     getreg(MGTPRC),   getreg(MGTPDC),   getreg(MGTPTC),   getreg(GORCL),
13513b274301SLeonid Bloch     getreg(GOTCL),
13527c23b892Sbalrog 
135320f3e863SLeonid Bloch     [TOTH]    = mac_read_clr8,      [TORH]    = mac_read_clr8,
13543b274301SLeonid Bloch     [GOTCH]   = mac_read_clr8,      [GORCH]   = mac_read_clr8,
13553b274301SLeonid Bloch     [PRC64]   = mac_read_clr4,      [PRC127]  = mac_read_clr4,
13563b274301SLeonid Bloch     [PRC255]  = mac_read_clr4,      [PRC511]  = mac_read_clr4,
13573b274301SLeonid Bloch     [PRC1023] = mac_read_clr4,      [PRC1522] = mac_read_clr4,
13583b274301SLeonid Bloch     [PTC64]   = mac_read_clr4,      [PTC127]  = mac_read_clr4,
13593b274301SLeonid Bloch     [PTC255]  = mac_read_clr4,      [PTC511]  = mac_read_clr4,
13603b274301SLeonid Bloch     [PTC1023] = mac_read_clr4,      [PTC1522] = mac_read_clr4,
136120f3e863SLeonid Bloch     [GPRC]    = mac_read_clr4,      [GPTC]    = mac_read_clr4,
136220f3e863SLeonid Bloch     [TPT]     = mac_read_clr4,      [TPR]     = mac_read_clr4,
13633b274301SLeonid Bloch     [RUC]     = mac_read_clr4,      [ROC]     = mac_read_clr4,
13643b274301SLeonid Bloch     [BPRC]    = mac_read_clr4,      [MPRC]    = mac_read_clr4,
13653b274301SLeonid Bloch     [TSCTC]   = mac_read_clr4,      [BPTC]    = mac_read_clr4,
13663b274301SLeonid Bloch     [MPTC]    = mac_read_clr4,
136720f3e863SLeonid Bloch     [ICR]     = mac_icr_read,       [EECD]    = get_eecd,
136820f3e863SLeonid Bloch     [EERD]    = flash_eerd_read,
136972ea771cSLeonid Bloch     [RDFH]    = mac_low13_read,     [RDFT]    = mac_low13_read,
137072ea771cSLeonid Bloch     [RDFHS]   = mac_low13_read,     [RDFTS]   = mac_low13_read,
137172ea771cSLeonid Bloch     [RDFPC]   = mac_low13_read,
137272ea771cSLeonid Bloch     [TDFH]    = mac_low11_read,     [TDFT]    = mac_low11_read,
137372ea771cSLeonid Bloch     [TDFHS]   = mac_low13_read,     [TDFTS]   = mac_low13_read,
137472ea771cSLeonid Bloch     [TDFPC]   = mac_low13_read,
137572ea771cSLeonid Bloch     [AIT]     = mac_low16_read,
137620f3e863SLeonid Bloch 
13777c23b892Sbalrog     [CRCERRS ... MPC]   = &mac_readreg,
137872ea771cSLeonid Bloch     [IP6AT ... IP6AT+3] = &mac_readreg,    [IP4AT ... IP4AT+6] = &mac_readreg,
137972ea771cSLeonid Bloch     [FFLT ... FFLT+6]   = &mac_low11_read,
13807c23b892Sbalrog     [RA ... RA+31]      = &mac_readreg,
138172ea771cSLeonid Bloch     [WUPM ... WUPM+31]  = &mac_readreg,
13827c23b892Sbalrog     [MTA ... MTA+127]   = &mac_readreg,
13838f2e8d1fSaliguori     [VFTA ... VFTA+127] = &mac_readreg,
138472ea771cSLeonid Bloch     [FFMT ... FFMT+254] = &mac_low4_read,
138572ea771cSLeonid Bloch     [FFVT ... FFVT+254] = &mac_readreg,
138672ea771cSLeonid Bloch     [PBM ... PBM+16383] = &mac_readreg,
13877c23b892Sbalrog };
1388b1503cdaSmalc enum { NREADOPS = ARRAY_SIZE(macreg_readops) };
13897c23b892Sbalrog 
13907c23b892Sbalrog #define putreg(x)    [x] = mac_writereg
13917c23b892Sbalrog static void (*macreg_writeops[])(E1000State *, int, uint32_t) = {
13927c23b892Sbalrog     putreg(PBA),      putreg(EERD),     putreg(SWSM),     putreg(WUFC),
13937c23b892Sbalrog     putreg(TDBAL),    putreg(TDBAH),    putreg(TXDCTL),   putreg(RDBAH),
139472ea771cSLeonid Bloch     putreg(RDBAL),    putreg(LEDCTL),   putreg(VET),      putreg(FCRUC),
139572ea771cSLeonid Bloch     putreg(TDFH),     putreg(TDFT),     putreg(TDFHS),    putreg(TDFTS),
139672ea771cSLeonid Bloch     putreg(TDFPC),    putreg(RDFH),     putreg(RDFT),     putreg(RDFHS),
139772ea771cSLeonid Bloch     putreg(RDFTS),    putreg(RDFPC),    putreg(IPAV),     putreg(WUC),
139872ea771cSLeonid Bloch     putreg(WUS),      putreg(AIT),
139920f3e863SLeonid Bloch 
14007c23b892Sbalrog     [TDLEN]  = set_dlen,   [RDLEN]  = set_dlen,       [TCTL] = set_tctl,
14017c23b892Sbalrog     [TDT]    = set_tctl,   [MDIC]   = set_mdic,       [ICS]  = set_ics,
14027c23b892Sbalrog     [TDH]    = set_16bit,  [RDH]    = set_16bit,      [RDT]  = set_rdt,
14037c23b892Sbalrog     [IMC]    = set_imc,    [IMS]    = set_ims,        [ICR]  = set_icr,
1404cab3c825SKevin Wolf     [EECD]   = set_eecd,   [RCTL]   = set_rx_control, [CTRL] = set_ctrl,
1405e9845f09SVincenzo Maffione     [RDTR]   = set_16bit,  [RADV]   = set_16bit,      [TADV] = set_16bit,
1406e9845f09SVincenzo Maffione     [ITR]    = set_16bit,
140720f3e863SLeonid Bloch 
140872ea771cSLeonid Bloch     [IP6AT ... IP6AT+3] = &mac_writereg, [IP4AT ... IP4AT+6] = &mac_writereg,
140972ea771cSLeonid Bloch     [FFLT ... FFLT+6]   = &mac_writereg,
14107c23b892Sbalrog     [RA ... RA+31]      = &mac_writereg,
141172ea771cSLeonid Bloch     [WUPM ... WUPM+31]  = &mac_writereg,
14127c23b892Sbalrog     [MTA ... MTA+127]   = &mac_writereg,
14138f2e8d1fSaliguori     [VFTA ... VFTA+127] = &mac_writereg,
141472ea771cSLeonid Bloch     [FFMT ... FFMT+254] = &mac_writereg, [FFVT ... FFVT+254] = &mac_writereg,
141572ea771cSLeonid Bloch     [PBM ... PBM+16383] = &mac_writereg,
14167c23b892Sbalrog };
1417b9d03e35SJason Wang 
1418b1503cdaSmalc enum { NWRITEOPS = ARRAY_SIZE(macreg_writeops) };
14197c23b892Sbalrog 
1420bc0f0674SLeonid Bloch enum { MAC_ACCESS_PARTIAL = 1, MAC_ACCESS_FLAG_NEEDED = 2 };
1421bc0f0674SLeonid Bloch 
1422bc0f0674SLeonid Bloch #define markflag(x)    ((E1000_FLAG_##x << 2) | MAC_ACCESS_FLAG_NEEDED)
1423bc0f0674SLeonid Bloch /* In the array below the meaning of the bits is: [f|f|f|f|f|f|n|p]
1424bc0f0674SLeonid Bloch  * f - flag bits (up to 6 possible flags)
1425bc0f0674SLeonid Bloch  * n - flag needed
1426bc0f0674SLeonid Bloch  * p - partially implenented */
1427bc0f0674SLeonid Bloch static const uint8_t mac_reg_access[0x8000] = {
1428bc0f0674SLeonid Bloch     [RDTR]    = markflag(MIT),    [TADV]    = markflag(MIT),
1429bc0f0674SLeonid Bloch     [RADV]    = markflag(MIT),    [ITR]     = markflag(MIT),
143072ea771cSLeonid Bloch 
143172ea771cSLeonid Bloch     [IPAV]    = markflag(MAC),    [WUC]     = markflag(MAC),
143272ea771cSLeonid Bloch     [IP6AT]   = markflag(MAC),    [IP4AT]   = markflag(MAC),
143372ea771cSLeonid Bloch     [FFVT]    = markflag(MAC),    [WUPM]    = markflag(MAC),
143472ea771cSLeonid Bloch     [ECOL]    = markflag(MAC),    [MCC]     = markflag(MAC),
143572ea771cSLeonid Bloch     [DC]      = markflag(MAC),    [TNCRS]   = markflag(MAC),
143672ea771cSLeonid Bloch     [RLEC]    = markflag(MAC),    [XONRXC]  = markflag(MAC),
143772ea771cSLeonid Bloch     [XOFFTXC] = markflag(MAC),    [RFC]     = markflag(MAC),
143872ea771cSLeonid Bloch     [TSCTFC]  = markflag(MAC),    [MGTPRC]  = markflag(MAC),
143972ea771cSLeonid Bloch     [WUS]     = markflag(MAC),    [AIT]     = markflag(MAC),
144072ea771cSLeonid Bloch     [FFLT]    = markflag(MAC),    [FFMT]    = markflag(MAC),
144172ea771cSLeonid Bloch     [SCC]     = markflag(MAC),    [FCRUC]   = markflag(MAC),
144272ea771cSLeonid Bloch     [LATECOL] = markflag(MAC),    [COLC]    = markflag(MAC),
144372ea771cSLeonid Bloch     [SEC]     = markflag(MAC),    [CEXTERR] = markflag(MAC),
144472ea771cSLeonid Bloch     [XONTXC]  = markflag(MAC),    [XOFFRXC] = markflag(MAC),
144572ea771cSLeonid Bloch     [RJC]     = markflag(MAC),    [RNBC]    = markflag(MAC),
144672ea771cSLeonid Bloch     [MGTPDC]  = markflag(MAC),    [MGTPTC]  = markflag(MAC),
14473b274301SLeonid Bloch     [RUC]     = markflag(MAC),    [ROC]     = markflag(MAC),
14483b274301SLeonid Bloch     [GORCL]   = markflag(MAC),    [GORCH]   = markflag(MAC),
14493b274301SLeonid Bloch     [GOTCL]   = markflag(MAC),    [GOTCH]   = markflag(MAC),
14503b274301SLeonid Bloch     [BPRC]    = markflag(MAC),    [MPRC]    = markflag(MAC),
14513b274301SLeonid Bloch     [TSCTC]   = markflag(MAC),    [PRC64]   = markflag(MAC),
14523b274301SLeonid Bloch     [PRC127]  = markflag(MAC),    [PRC255]  = markflag(MAC),
14533b274301SLeonid Bloch     [PRC511]  = markflag(MAC),    [PRC1023] = markflag(MAC),
14543b274301SLeonid Bloch     [PRC1522] = markflag(MAC),    [PTC64]   = markflag(MAC),
14553b274301SLeonid Bloch     [PTC127]  = markflag(MAC),    [PTC255]  = markflag(MAC),
14563b274301SLeonid Bloch     [PTC511]  = markflag(MAC),    [PTC1023] = markflag(MAC),
14573b274301SLeonid Bloch     [PTC1522] = markflag(MAC),    [MPTC]    = markflag(MAC),
14583b274301SLeonid Bloch     [BPTC]    = markflag(MAC),
145972ea771cSLeonid Bloch 
146072ea771cSLeonid Bloch     [TDFH]  = markflag(MAC) | MAC_ACCESS_PARTIAL,
146172ea771cSLeonid Bloch     [TDFT]  = markflag(MAC) | MAC_ACCESS_PARTIAL,
146272ea771cSLeonid Bloch     [TDFHS] = markflag(MAC) | MAC_ACCESS_PARTIAL,
146372ea771cSLeonid Bloch     [TDFTS] = markflag(MAC) | MAC_ACCESS_PARTIAL,
146472ea771cSLeonid Bloch     [TDFPC] = markflag(MAC) | MAC_ACCESS_PARTIAL,
146572ea771cSLeonid Bloch     [RDFH]  = markflag(MAC) | MAC_ACCESS_PARTIAL,
146672ea771cSLeonid Bloch     [RDFT]  = markflag(MAC) | MAC_ACCESS_PARTIAL,
146772ea771cSLeonid Bloch     [RDFHS] = markflag(MAC) | MAC_ACCESS_PARTIAL,
146872ea771cSLeonid Bloch     [RDFTS] = markflag(MAC) | MAC_ACCESS_PARTIAL,
146972ea771cSLeonid Bloch     [RDFPC] = markflag(MAC) | MAC_ACCESS_PARTIAL,
147072ea771cSLeonid Bloch     [PBM]   = markflag(MAC) | MAC_ACCESS_PARTIAL,
1471bc0f0674SLeonid Bloch };
1472bc0f0674SLeonid Bloch 
14737c23b892Sbalrog static void
1474a8170e5eSAvi Kivity e1000_mmio_write(void *opaque, hwaddr addr, uint64_t val,
1475ad00a9b9SAvi Kivity                  unsigned size)
14767c23b892Sbalrog {
14777c23b892Sbalrog     E1000State *s = opaque;
14788da3ff18Spbrook     unsigned int index = (addr & 0x1ffff) >> 2;
14797c23b892Sbalrog 
148043ad7e3eSJes Sorensen     if (index < NWRITEOPS && macreg_writeops[index]) {
1481bc0f0674SLeonid Bloch         if (!(mac_reg_access[index] & MAC_ACCESS_FLAG_NEEDED)
1482bc0f0674SLeonid Bloch             || (s->compat_flags & (mac_reg_access[index] >> 2))) {
1483bc0f0674SLeonid Bloch             if (mac_reg_access[index] & MAC_ACCESS_PARTIAL) {
1484bc0f0674SLeonid Bloch                 DBGOUT(GENERAL, "Writing to register at offset: 0x%08x. "
1485bc0f0674SLeonid Bloch                        "It is not fully implemented.\n", index<<2);
1486bc0f0674SLeonid Bloch             }
14876b59fc74Saurel32             macreg_writeops[index](s, index, val);
1488bc0f0674SLeonid Bloch         } else {    /* "flag needed" bit is set, but the flag is not active */
1489bc0f0674SLeonid Bloch             DBGOUT(MMIO, "MMIO write attempt to disabled reg. addr=0x%08x\n",
1490bc0f0674SLeonid Bloch                    index<<2);
1491bc0f0674SLeonid Bloch         }
149243ad7e3eSJes Sorensen     } else if (index < NREADOPS && macreg_readops[index]) {
1493bc0f0674SLeonid Bloch         DBGOUT(MMIO, "e1000_mmio_writel RO %x: 0x%04"PRIx64"\n",
1494bc0f0674SLeonid Bloch                index<<2, val);
149543ad7e3eSJes Sorensen     } else {
1496ad00a9b9SAvi Kivity         DBGOUT(UNKNOWN, "MMIO unknown write addr=0x%08x,val=0x%08"PRIx64"\n",
14977c23b892Sbalrog                index<<2, val);
14987c23b892Sbalrog     }
149943ad7e3eSJes Sorensen }
15007c23b892Sbalrog 
1501ad00a9b9SAvi Kivity static uint64_t
1502a8170e5eSAvi Kivity e1000_mmio_read(void *opaque, hwaddr addr, unsigned size)
15037c23b892Sbalrog {
15047c23b892Sbalrog     E1000State *s = opaque;
15058da3ff18Spbrook     unsigned int index = (addr & 0x1ffff) >> 2;
15067c23b892Sbalrog 
1507bc0f0674SLeonid Bloch     if (index < NREADOPS && macreg_readops[index]) {
1508bc0f0674SLeonid Bloch         if (!(mac_reg_access[index] & MAC_ACCESS_FLAG_NEEDED)
1509bc0f0674SLeonid Bloch             || (s->compat_flags & (mac_reg_access[index] >> 2))) {
1510bc0f0674SLeonid Bloch             if (mac_reg_access[index] & MAC_ACCESS_PARTIAL) {
1511bc0f0674SLeonid Bloch                 DBGOUT(GENERAL, "Reading register at offset: 0x%08x. "
1512bc0f0674SLeonid Bloch                        "It is not fully implemented.\n", index<<2);
15136b59fc74Saurel32             }
1514bc0f0674SLeonid Bloch             return macreg_readops[index](s, index);
1515bc0f0674SLeonid Bloch         } else {    /* "flag needed" bit is set, but the flag is not active */
1516bc0f0674SLeonid Bloch             DBGOUT(MMIO, "MMIO read attempt of disabled reg. addr=0x%08x\n",
1517bc0f0674SLeonid Bloch                    index<<2);
1518bc0f0674SLeonid Bloch         }
1519bc0f0674SLeonid Bloch     } else {
15207c23b892Sbalrog         DBGOUT(UNKNOWN, "MMIO unknown read addr=0x%08x\n", index<<2);
1521bc0f0674SLeonid Bloch     }
15227c23b892Sbalrog     return 0;
15237c23b892Sbalrog }
15247c23b892Sbalrog 
1525ad00a9b9SAvi Kivity static const MemoryRegionOps e1000_mmio_ops = {
1526ad00a9b9SAvi Kivity     .read = e1000_mmio_read,
1527ad00a9b9SAvi Kivity     .write = e1000_mmio_write,
1528ad00a9b9SAvi Kivity     .endianness = DEVICE_LITTLE_ENDIAN,
1529ad00a9b9SAvi Kivity     .impl = {
1530ad00a9b9SAvi Kivity         .min_access_size = 4,
1531ad00a9b9SAvi Kivity         .max_access_size = 4,
1532ad00a9b9SAvi Kivity     },
1533ad00a9b9SAvi Kivity };
1534ad00a9b9SAvi Kivity 
1535a8170e5eSAvi Kivity static uint64_t e1000_io_read(void *opaque, hwaddr addr,
1536ad00a9b9SAvi Kivity                               unsigned size)
15377c23b892Sbalrog {
1538ad00a9b9SAvi Kivity     E1000State *s = opaque;
1539ad00a9b9SAvi Kivity 
1540ad00a9b9SAvi Kivity     (void)s;
1541ad00a9b9SAvi Kivity     return 0;
15427c23b892Sbalrog }
15437c23b892Sbalrog 
1544a8170e5eSAvi Kivity static void e1000_io_write(void *opaque, hwaddr addr,
1545ad00a9b9SAvi Kivity                            uint64_t val, unsigned size)
15467c23b892Sbalrog {
1547ad00a9b9SAvi Kivity     E1000State *s = opaque;
1548ad00a9b9SAvi Kivity 
1549ad00a9b9SAvi Kivity     (void)s;
15507c23b892Sbalrog }
15517c23b892Sbalrog 
1552ad00a9b9SAvi Kivity static const MemoryRegionOps e1000_io_ops = {
1553ad00a9b9SAvi Kivity     .read = e1000_io_read,
1554ad00a9b9SAvi Kivity     .write = e1000_io_write,
1555ad00a9b9SAvi Kivity     .endianness = DEVICE_LITTLE_ENDIAN,
1556ad00a9b9SAvi Kivity };
1557ad00a9b9SAvi Kivity 
1558e482dc3eSJuan Quintela static bool is_version_1(void *opaque, int version_id)
15597c23b892Sbalrog {
1560e482dc3eSJuan Quintela     return version_id == 1;
15617c23b892Sbalrog }
15627c23b892Sbalrog 
1563ddcb73b7SMichael S. Tsirkin static void e1000_pre_save(void *opaque)
1564ddcb73b7SMichael S. Tsirkin {
1565ddcb73b7SMichael S. Tsirkin     E1000State *s = opaque;
1566ddcb73b7SMichael S. Tsirkin     NetClientState *nc = qemu_get_queue(s->nic);
15672af234e6SMichael S. Tsirkin 
1568e9845f09SVincenzo Maffione     /* If the mitigation timer is active, emulate a timeout now. */
1569e9845f09SVincenzo Maffione     if (s->mit_timer_on) {
1570e9845f09SVincenzo Maffione         e1000_mit_timer(s);
1571e9845f09SVincenzo Maffione     }
1572e9845f09SVincenzo Maffione 
1573ddcb73b7SMichael S. Tsirkin     /*
15746a2acedbSGabriel L. Somlo      * If link is down and auto-negotiation is supported and ongoing,
15756a2acedbSGabriel L. Somlo      * complete auto-negotiation immediately. This allows us to look
15766a2acedbSGabriel L. Somlo      * at MII_SR_AUTONEG_COMPLETE to infer link status on load.
1577ddcb73b7SMichael S. Tsirkin      */
1578d7a41552SGabriel L. Somlo     if (nc->link_down && have_autoneg(s)) {
1579ddcb73b7SMichael S. Tsirkin         s->phy_reg[PHY_STATUS] |= MII_SR_AUTONEG_COMPLETE;
1580ddcb73b7SMichael S. Tsirkin     }
1581ddcb73b7SMichael S. Tsirkin }
1582ddcb73b7SMichael S. Tsirkin 
1583e4b82364SAmos Kong static int e1000_post_load(void *opaque, int version_id)
1584e4b82364SAmos Kong {
1585e4b82364SAmos Kong     E1000State *s = opaque;
1586b356f76dSJason Wang     NetClientState *nc = qemu_get_queue(s->nic);
1587e4b82364SAmos Kong 
1588bc0f0674SLeonid Bloch     if (!chkflag(MIT)) {
1589e9845f09SVincenzo Maffione         s->mac_reg[ITR] = s->mac_reg[RDTR] = s->mac_reg[RADV] =
1590e9845f09SVincenzo Maffione             s->mac_reg[TADV] = 0;
1591e9845f09SVincenzo Maffione         s->mit_irq_level = false;
1592e9845f09SVincenzo Maffione     }
1593e9845f09SVincenzo Maffione     s->mit_ide = 0;
1594e9845f09SVincenzo Maffione     s->mit_timer_on = false;
1595e9845f09SVincenzo Maffione 
1596e4b82364SAmos Kong     /* nc.link_down can't be migrated, so infer link_down according
1597ddcb73b7SMichael S. Tsirkin      * to link status bit in mac_reg[STATUS].
1598ddcb73b7SMichael S. Tsirkin      * Alternatively, restart link negotiation if it was in progress. */
1599b356f76dSJason Wang     nc->link_down = (s->mac_reg[STATUS] & E1000_STATUS_LU) == 0;
16002af234e6SMichael S. Tsirkin 
1601d7a41552SGabriel L. Somlo     if (have_autoneg(s) &&
1602ddcb73b7SMichael S. Tsirkin         !(s->phy_reg[PHY_STATUS] & MII_SR_AUTONEG_COMPLETE)) {
1603ddcb73b7SMichael S. Tsirkin         nc->link_down = false;
1604d7a41552SGabriel L. Somlo         timer_mod(s->autoneg_timer,
1605d7a41552SGabriel L. Somlo                   qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 500);
1606ddcb73b7SMichael S. Tsirkin     }
1607e4b82364SAmos Kong 
1608e4b82364SAmos Kong     return 0;
1609e4b82364SAmos Kong }
1610e4b82364SAmos Kong 
1611e9845f09SVincenzo Maffione static bool e1000_mit_state_needed(void *opaque)
1612e9845f09SVincenzo Maffione {
1613e9845f09SVincenzo Maffione     E1000State *s = opaque;
1614e9845f09SVincenzo Maffione 
1615bc0f0674SLeonid Bloch     return chkflag(MIT);
1616e9845f09SVincenzo Maffione }
1617e9845f09SVincenzo Maffione 
16189e117734SLeonid Bloch static bool e1000_full_mac_needed(void *opaque)
16199e117734SLeonid Bloch {
16209e117734SLeonid Bloch     E1000State *s = opaque;
16219e117734SLeonid Bloch 
1622bc0f0674SLeonid Bloch     return chkflag(MAC);
16239e117734SLeonid Bloch }
16249e117734SLeonid Bloch 
1625e9845f09SVincenzo Maffione static const VMStateDescription vmstate_e1000_mit_state = {
1626e9845f09SVincenzo Maffione     .name = "e1000/mit_state",
1627e9845f09SVincenzo Maffione     .version_id = 1,
1628e9845f09SVincenzo Maffione     .minimum_version_id = 1,
16295cd8cadaSJuan Quintela     .needed = e1000_mit_state_needed,
1630e9845f09SVincenzo Maffione     .fields = (VMStateField[]) {
1631e9845f09SVincenzo Maffione         VMSTATE_UINT32(mac_reg[RDTR], E1000State),
1632e9845f09SVincenzo Maffione         VMSTATE_UINT32(mac_reg[RADV], E1000State),
1633e9845f09SVincenzo Maffione         VMSTATE_UINT32(mac_reg[TADV], E1000State),
1634e9845f09SVincenzo Maffione         VMSTATE_UINT32(mac_reg[ITR], E1000State),
1635e9845f09SVincenzo Maffione         VMSTATE_BOOL(mit_irq_level, E1000State),
1636e9845f09SVincenzo Maffione         VMSTATE_END_OF_LIST()
1637e9845f09SVincenzo Maffione     }
1638e9845f09SVincenzo Maffione };
1639e9845f09SVincenzo Maffione 
16409e117734SLeonid Bloch static const VMStateDescription vmstate_e1000_full_mac_state = {
16419e117734SLeonid Bloch     .name = "e1000/full_mac_state",
16429e117734SLeonid Bloch     .version_id = 1,
16439e117734SLeonid Bloch     .minimum_version_id = 1,
16449e117734SLeonid Bloch     .needed = e1000_full_mac_needed,
16459e117734SLeonid Bloch     .fields = (VMStateField[]) {
16469e117734SLeonid Bloch         VMSTATE_UINT32_ARRAY(mac_reg, E1000State, 0x8000),
16479e117734SLeonid Bloch         VMSTATE_END_OF_LIST()
16489e117734SLeonid Bloch     }
16499e117734SLeonid Bloch };
16509e117734SLeonid Bloch 
1651e482dc3eSJuan Quintela static const VMStateDescription vmstate_e1000 = {
1652e482dc3eSJuan Quintela     .name = "e1000",
1653e482dc3eSJuan Quintela     .version_id = 2,
1654e482dc3eSJuan Quintela     .minimum_version_id = 1,
1655ddcb73b7SMichael S. Tsirkin     .pre_save = e1000_pre_save,
1656e4b82364SAmos Kong     .post_load = e1000_post_load,
1657e482dc3eSJuan Quintela     .fields = (VMStateField[]) {
1658b08340d5SAndreas Färber         VMSTATE_PCI_DEVICE(parent_obj, E1000State),
1659e482dc3eSJuan Quintela         VMSTATE_UNUSED_TEST(is_version_1, 4), /* was instance id */
1660e482dc3eSJuan Quintela         VMSTATE_UNUSED(4), /* Was mmio_base.  */
1661e482dc3eSJuan Quintela         VMSTATE_UINT32(rxbuf_size, E1000State),
1662e482dc3eSJuan Quintela         VMSTATE_UINT32(rxbuf_min_shift, E1000State),
1663e482dc3eSJuan Quintela         VMSTATE_UINT32(eecd_state.val_in, E1000State),
1664e482dc3eSJuan Quintela         VMSTATE_UINT16(eecd_state.bitnum_in, E1000State),
1665e482dc3eSJuan Quintela         VMSTATE_UINT16(eecd_state.bitnum_out, E1000State),
1666e482dc3eSJuan Quintela         VMSTATE_UINT16(eecd_state.reading, E1000State),
1667e482dc3eSJuan Quintela         VMSTATE_UINT32(eecd_state.old_eecd, E1000State),
1668e482dc3eSJuan Quintela         VMSTATE_UINT8(tx.ipcss, E1000State),
1669e482dc3eSJuan Quintela         VMSTATE_UINT8(tx.ipcso, E1000State),
1670e482dc3eSJuan Quintela         VMSTATE_UINT16(tx.ipcse, E1000State),
1671e482dc3eSJuan Quintela         VMSTATE_UINT8(tx.tucss, E1000State),
1672e482dc3eSJuan Quintela         VMSTATE_UINT8(tx.tucso, E1000State),
1673e482dc3eSJuan Quintela         VMSTATE_UINT16(tx.tucse, E1000State),
1674e482dc3eSJuan Quintela         VMSTATE_UINT32(tx.paylen, E1000State),
1675e482dc3eSJuan Quintela         VMSTATE_UINT8(tx.hdr_len, E1000State),
1676e482dc3eSJuan Quintela         VMSTATE_UINT16(tx.mss, E1000State),
1677e482dc3eSJuan Quintela         VMSTATE_UINT16(tx.size, E1000State),
1678e482dc3eSJuan Quintela         VMSTATE_UINT16(tx.tso_frames, E1000State),
1679e482dc3eSJuan Quintela         VMSTATE_UINT8(tx.sum_needed, E1000State),
1680e482dc3eSJuan Quintela         VMSTATE_INT8(tx.ip, E1000State),
1681e482dc3eSJuan Quintela         VMSTATE_INT8(tx.tcp, E1000State),
1682e482dc3eSJuan Quintela         VMSTATE_BUFFER(tx.header, E1000State),
1683e482dc3eSJuan Quintela         VMSTATE_BUFFER(tx.data, E1000State),
1684e482dc3eSJuan Quintela         VMSTATE_UINT16_ARRAY(eeprom_data, E1000State, 64),
1685e482dc3eSJuan Quintela         VMSTATE_UINT16_ARRAY(phy_reg, E1000State, 0x20),
1686e482dc3eSJuan Quintela         VMSTATE_UINT32(mac_reg[CTRL], E1000State),
1687e482dc3eSJuan Quintela         VMSTATE_UINT32(mac_reg[EECD], E1000State),
1688e482dc3eSJuan Quintela         VMSTATE_UINT32(mac_reg[EERD], E1000State),
1689e482dc3eSJuan Quintela         VMSTATE_UINT32(mac_reg[GPRC], E1000State),
1690e482dc3eSJuan Quintela         VMSTATE_UINT32(mac_reg[GPTC], E1000State),
1691e482dc3eSJuan Quintela         VMSTATE_UINT32(mac_reg[ICR], E1000State),
1692e482dc3eSJuan Quintela         VMSTATE_UINT32(mac_reg[ICS], E1000State),
1693e482dc3eSJuan Quintela         VMSTATE_UINT32(mac_reg[IMC], E1000State),
1694e482dc3eSJuan Quintela         VMSTATE_UINT32(mac_reg[IMS], E1000State),
1695e482dc3eSJuan Quintela         VMSTATE_UINT32(mac_reg[LEDCTL], E1000State),
1696e482dc3eSJuan Quintela         VMSTATE_UINT32(mac_reg[MANC], E1000State),
1697e482dc3eSJuan Quintela         VMSTATE_UINT32(mac_reg[MDIC], E1000State),
1698e482dc3eSJuan Quintela         VMSTATE_UINT32(mac_reg[MPC], E1000State),
1699e482dc3eSJuan Quintela         VMSTATE_UINT32(mac_reg[PBA], E1000State),
1700e482dc3eSJuan Quintela         VMSTATE_UINT32(mac_reg[RCTL], E1000State),
1701e482dc3eSJuan Quintela         VMSTATE_UINT32(mac_reg[RDBAH], E1000State),
1702e482dc3eSJuan Quintela         VMSTATE_UINT32(mac_reg[RDBAL], E1000State),
1703e482dc3eSJuan Quintela         VMSTATE_UINT32(mac_reg[RDH], E1000State),
1704e482dc3eSJuan Quintela         VMSTATE_UINT32(mac_reg[RDLEN], E1000State),
1705e482dc3eSJuan Quintela         VMSTATE_UINT32(mac_reg[RDT], E1000State),
1706e482dc3eSJuan Quintela         VMSTATE_UINT32(mac_reg[STATUS], E1000State),
1707e482dc3eSJuan Quintela         VMSTATE_UINT32(mac_reg[SWSM], E1000State),
1708e482dc3eSJuan Quintela         VMSTATE_UINT32(mac_reg[TCTL], E1000State),
1709e482dc3eSJuan Quintela         VMSTATE_UINT32(mac_reg[TDBAH], E1000State),
1710e482dc3eSJuan Quintela         VMSTATE_UINT32(mac_reg[TDBAL], E1000State),
1711e482dc3eSJuan Quintela         VMSTATE_UINT32(mac_reg[TDH], E1000State),
1712e482dc3eSJuan Quintela         VMSTATE_UINT32(mac_reg[TDLEN], E1000State),
1713e482dc3eSJuan Quintela         VMSTATE_UINT32(mac_reg[TDT], E1000State),
1714e482dc3eSJuan Quintela         VMSTATE_UINT32(mac_reg[TORH], E1000State),
1715e482dc3eSJuan Quintela         VMSTATE_UINT32(mac_reg[TORL], E1000State),
1716e482dc3eSJuan Quintela         VMSTATE_UINT32(mac_reg[TOTH], E1000State),
1717e482dc3eSJuan Quintela         VMSTATE_UINT32(mac_reg[TOTL], E1000State),
1718e482dc3eSJuan Quintela         VMSTATE_UINT32(mac_reg[TPR], E1000State),
1719e482dc3eSJuan Quintela         VMSTATE_UINT32(mac_reg[TPT], E1000State),
1720e482dc3eSJuan Quintela         VMSTATE_UINT32(mac_reg[TXDCTL], E1000State),
1721e482dc3eSJuan Quintela         VMSTATE_UINT32(mac_reg[WUFC], E1000State),
1722e482dc3eSJuan Quintela         VMSTATE_UINT32(mac_reg[VET], E1000State),
1723e482dc3eSJuan Quintela         VMSTATE_UINT32_SUB_ARRAY(mac_reg, E1000State, RA, 32),
1724e482dc3eSJuan Quintela         VMSTATE_UINT32_SUB_ARRAY(mac_reg, E1000State, MTA, 128),
1725e482dc3eSJuan Quintela         VMSTATE_UINT32_SUB_ARRAY(mac_reg, E1000State, VFTA, 128),
1726e482dc3eSJuan Quintela         VMSTATE_END_OF_LIST()
1727e9845f09SVincenzo Maffione     },
17285cd8cadaSJuan Quintela     .subsections = (const VMStateDescription*[]) {
17295cd8cadaSJuan Quintela         &vmstate_e1000_mit_state,
17309e117734SLeonid Bloch         &vmstate_e1000_full_mac_state,
17315cd8cadaSJuan Quintela         NULL
17327c23b892Sbalrog     }
1733e482dc3eSJuan Quintela };
17347c23b892Sbalrog 
17358597f2e1SGabriel L. Somlo /*
17368597f2e1SGabriel L. Somlo  * EEPROM contents documented in Tables 5-2 and 5-3, pp. 98-102.
17378597f2e1SGabriel L. Somlo  * Note: A valid DevId will be inserted during pci_e1000_init().
17388597f2e1SGabriel L. Somlo  */
173988b4e9dbSblueswir1 static const uint16_t e1000_eeprom_template[64] = {
17407c23b892Sbalrog     0x0000, 0x0000, 0x0000, 0x0000,      0xffff, 0x0000,      0x0000, 0x0000,
17418597f2e1SGabriel L. Somlo     0x3000, 0x1000, 0x6403, 0 /*DevId*/, 0x8086, 0 /*DevId*/, 0x8086, 0x3040,
17427c23b892Sbalrog     0x0008, 0x2000, 0x7e14, 0x0048,      0x1000, 0x00d8,      0x0000, 0x2700,
17437c23b892Sbalrog     0x6cc9, 0x3150, 0x0722, 0x040b,      0x0984, 0x0000,      0xc000, 0x0706,
17447c23b892Sbalrog     0x1008, 0x0000, 0x0f04, 0x7fff,      0x4d01, 0xffff,      0xffff, 0xffff,
17457c23b892Sbalrog     0xffff, 0xffff, 0xffff, 0xffff,      0xffff, 0xffff,      0xffff, 0xffff,
17467c23b892Sbalrog     0x0100, 0x4000, 0x121c, 0xffff,      0xffff, 0xffff,      0xffff, 0xffff,
17477c23b892Sbalrog     0xffff, 0xffff, 0xffff, 0xffff,      0xffff, 0xffff,      0xffff, 0x0000,
17487c23b892Sbalrog };
17497c23b892Sbalrog 
17507c23b892Sbalrog /* PCI interface */
17517c23b892Sbalrog 
17527c23b892Sbalrog static void
1753ad00a9b9SAvi Kivity e1000_mmio_setup(E1000State *d)
17547c23b892Sbalrog {
1755f65ed4c1Saliguori     int i;
1756f65ed4c1Saliguori     const uint32_t excluded_regs[] = {
1757f65ed4c1Saliguori         E1000_MDIC, E1000_ICR, E1000_ICS, E1000_IMS,
1758f65ed4c1Saliguori         E1000_IMC, E1000_TCTL, E1000_TDT, PNPMMIO_SIZE
1759f65ed4c1Saliguori     };
1760f65ed4c1Saliguori 
1761eedfac6fSPaolo Bonzini     memory_region_init_io(&d->mmio, OBJECT(d), &e1000_mmio_ops, d,
1762eedfac6fSPaolo Bonzini                           "e1000-mmio", PNPMMIO_SIZE);
1763ad00a9b9SAvi Kivity     memory_region_add_coalescing(&d->mmio, 0, excluded_regs[0]);
1764f65ed4c1Saliguori     for (i = 0; excluded_regs[i] != PNPMMIO_SIZE; i++)
1765ad00a9b9SAvi Kivity         memory_region_add_coalescing(&d->mmio, excluded_regs[i] + 4,
1766ad00a9b9SAvi Kivity                                      excluded_regs[i+1] - excluded_regs[i] - 4);
1767eedfac6fSPaolo Bonzini     memory_region_init_io(&d->io, OBJECT(d), &e1000_io_ops, d, "e1000-io", IOPORT_SIZE);
17687c23b892Sbalrog }
17697c23b892Sbalrog 
1770b946a153Saliguori static void
17714b09be85Saliguori pci_e1000_uninit(PCIDevice *dev)
17724b09be85Saliguori {
1773567a3c9eSPeter Crosthwaite     E1000State *d = E1000(dev);
17744b09be85Saliguori 
1775bc72ad67SAlex Bligh     timer_del(d->autoneg_timer);
1776bc72ad67SAlex Bligh     timer_free(d->autoneg_timer);
1777e9845f09SVincenzo Maffione     timer_del(d->mit_timer);
1778e9845f09SVincenzo Maffione     timer_free(d->mit_timer);
1779948ecf21SJason Wang     qemu_del_nic(d->nic);
17804b09be85Saliguori }
17814b09be85Saliguori 
1782a03e2aecSMark McLoughlin static NetClientInfo net_e1000_info = {
17832be64a68SLaszlo Ersek     .type = NET_CLIENT_OPTIONS_KIND_NIC,
1784a03e2aecSMark McLoughlin     .size = sizeof(NICState),
1785a03e2aecSMark McLoughlin     .can_receive = e1000_can_receive,
1786a03e2aecSMark McLoughlin     .receive = e1000_receive,
178797410ddeSVincenzo Maffione     .receive_iov = e1000_receive_iov,
1788a03e2aecSMark McLoughlin     .link_status_changed = e1000_set_link_status,
1789a03e2aecSMark McLoughlin };
1790a03e2aecSMark McLoughlin 
179120302e71SMichael S. Tsirkin static void e1000_write_config(PCIDevice *pci_dev, uint32_t address,
179220302e71SMichael S. Tsirkin                                 uint32_t val, int len)
179320302e71SMichael S. Tsirkin {
179420302e71SMichael S. Tsirkin     E1000State *s = E1000(pci_dev);
179520302e71SMichael S. Tsirkin 
179620302e71SMichael S. Tsirkin     pci_default_write_config(pci_dev, address, val, len);
179720302e71SMichael S. Tsirkin 
179820302e71SMichael S. Tsirkin     if (range_covers_byte(address, len, PCI_COMMAND) &&
179920302e71SMichael S. Tsirkin         (pci_dev->config[PCI_COMMAND] & PCI_COMMAND_MASTER)) {
180020302e71SMichael S. Tsirkin         qemu_flush_queued_packets(qemu_get_queue(s->nic));
180120302e71SMichael S. Tsirkin     }
180220302e71SMichael S. Tsirkin }
180320302e71SMichael S. Tsirkin 
180420302e71SMichael S. Tsirkin 
18059af21dbeSMarkus Armbruster static void pci_e1000_realize(PCIDevice *pci_dev, Error **errp)
18067c23b892Sbalrog {
1807567a3c9eSPeter Crosthwaite     DeviceState *dev = DEVICE(pci_dev);
1808567a3c9eSPeter Crosthwaite     E1000State *d = E1000(pci_dev);
18098597f2e1SGabriel L. Somlo     PCIDeviceClass *pdc = PCI_DEVICE_GET_CLASS(pci_dev);
18107c23b892Sbalrog     uint8_t *pci_conf;
18117c23b892Sbalrog     uint16_t checksum = 0;
18127c23b892Sbalrog     int i;
1813fbdaa002SGerd Hoffmann     uint8_t *macaddr;
1814aff427a1SChris Wright 
181520302e71SMichael S. Tsirkin     pci_dev->config_write = e1000_write_config;
181620302e71SMichael S. Tsirkin 
1817b08340d5SAndreas Färber     pci_conf = pci_dev->config;
18187c23b892Sbalrog 
1819a9cbacb0SMichael S. Tsirkin     /* TODO: RST# value should be 0, PCI spec 6.2.4 */
1820a9cbacb0SMichael S. Tsirkin     pci_conf[PCI_CACHE_LINE_SIZE] = 0x10;
18217c23b892Sbalrog 
1822817e0b6fSMichael S. Tsirkin     pci_conf[PCI_INTERRUPT_PIN] = 1; /* interrupt pin A */
18237c23b892Sbalrog 
1824ad00a9b9SAvi Kivity     e1000_mmio_setup(d);
18257c23b892Sbalrog 
1826b08340d5SAndreas Färber     pci_register_bar(pci_dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &d->mmio);
18277c23b892Sbalrog 
1828b08340d5SAndreas Färber     pci_register_bar(pci_dev, 1, PCI_BASE_ADDRESS_SPACE_IO, &d->io);
18297c23b892Sbalrog 
18307c23b892Sbalrog     memmove(d->eeprom_data, e1000_eeprom_template,
18317c23b892Sbalrog         sizeof e1000_eeprom_template);
1832fbdaa002SGerd Hoffmann     qemu_macaddr_default_if_unset(&d->conf.macaddr);
1833fbdaa002SGerd Hoffmann     macaddr = d->conf.macaddr.a;
18347c23b892Sbalrog     for (i = 0; i < 3; i++)
18359d07d757SPaul Brook         d->eeprom_data[i] = (macaddr[2*i+1]<<8) | macaddr[2*i];
18368597f2e1SGabriel L. Somlo     d->eeprom_data[11] = d->eeprom_data[13] = pdc->device_id;
18377c23b892Sbalrog     for (i = 0; i < EEPROM_CHECKSUM_REG; i++)
18387c23b892Sbalrog         checksum += d->eeprom_data[i];
18397c23b892Sbalrog     checksum = (uint16_t) EEPROM_SUM - checksum;
18407c23b892Sbalrog     d->eeprom_data[EEPROM_CHECKSUM_REG] = checksum;
18417c23b892Sbalrog 
1842a03e2aecSMark McLoughlin     d->nic = qemu_new_nic(&net_e1000_info, &d->conf,
1843567a3c9eSPeter Crosthwaite                           object_get_typename(OBJECT(d)), dev->id, d);
18447c23b892Sbalrog 
1845b356f76dSJason Wang     qemu_format_nic_info_str(qemu_get_queue(d->nic), macaddr);
18461ca4d09aSGleb Natapov 
1847bc72ad67SAlex Bligh     d->autoneg_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, e1000_autoneg_timer, d);
1848e9845f09SVincenzo Maffione     d->mit_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, e1000_mit_timer, d);
18497c23b892Sbalrog }
18509d07d757SPaul Brook 
1851fbdaa002SGerd Hoffmann static void qdev_e1000_reset(DeviceState *dev)
1852fbdaa002SGerd Hoffmann {
1853567a3c9eSPeter Crosthwaite     E1000State *d = E1000(dev);
1854fbdaa002SGerd Hoffmann     e1000_reset(d);
1855fbdaa002SGerd Hoffmann }
1856fbdaa002SGerd Hoffmann 
185740021f08SAnthony Liguori static Property e1000_properties[] = {
1858fbdaa002SGerd Hoffmann     DEFINE_NIC_PROPERTIES(E1000State, conf),
18592af234e6SMichael S. Tsirkin     DEFINE_PROP_BIT("autonegotiation", E1000State,
18602af234e6SMichael S. Tsirkin                     compat_flags, E1000_FLAG_AUTONEG_BIT, true),
1861e9845f09SVincenzo Maffione     DEFINE_PROP_BIT("mitigation", E1000State,
1862e9845f09SVincenzo Maffione                     compat_flags, E1000_FLAG_MIT_BIT, true),
1863ba63ec85SLeonid Bloch     DEFINE_PROP_BIT("extra_mac_registers", E1000State,
1864ba63ec85SLeonid Bloch                     compat_flags, E1000_FLAG_MAC_BIT, true),
1865fbdaa002SGerd Hoffmann     DEFINE_PROP_END_OF_LIST(),
186640021f08SAnthony Liguori };
186740021f08SAnthony Liguori 
18688597f2e1SGabriel L. Somlo typedef struct E1000Info {
18698597f2e1SGabriel L. Somlo     const char *name;
18708597f2e1SGabriel L. Somlo     uint16_t   device_id;
18718597f2e1SGabriel L. Somlo     uint8_t    revision;
18728597f2e1SGabriel L. Somlo     uint16_t   phy_id2;
18738597f2e1SGabriel L. Somlo } E1000Info;
18748597f2e1SGabriel L. Somlo 
187540021f08SAnthony Liguori static void e1000_class_init(ObjectClass *klass, void *data)
187640021f08SAnthony Liguori {
187739bffca2SAnthony Liguori     DeviceClass *dc = DEVICE_CLASS(klass);
187840021f08SAnthony Liguori     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
18798597f2e1SGabriel L. Somlo     E1000BaseClass *e = E1000_DEVICE_CLASS(klass);
18808597f2e1SGabriel L. Somlo     const E1000Info *info = data;
188140021f08SAnthony Liguori 
18829af21dbeSMarkus Armbruster     k->realize = pci_e1000_realize;
188340021f08SAnthony Liguori     k->exit = pci_e1000_uninit;
1884c45e5b5bSGerd Hoffmann     k->romfile = "efi-e1000.rom";
188540021f08SAnthony Liguori     k->vendor_id = PCI_VENDOR_ID_INTEL;
18868597f2e1SGabriel L. Somlo     k->device_id = info->device_id;
18878597f2e1SGabriel L. Somlo     k->revision = info->revision;
18888597f2e1SGabriel L. Somlo     e->phy_id2 = info->phy_id2;
188940021f08SAnthony Liguori     k->class_id = PCI_CLASS_NETWORK_ETHERNET;
1890125ee0edSMarcel Apfelbaum     set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
189139bffca2SAnthony Liguori     dc->desc = "Intel Gigabit Ethernet";
189239bffca2SAnthony Liguori     dc->reset = qdev_e1000_reset;
189339bffca2SAnthony Liguori     dc->vmsd = &vmstate_e1000;
189439bffca2SAnthony Liguori     dc->props = e1000_properties;
1895fbdaa002SGerd Hoffmann }
189640021f08SAnthony Liguori 
18975df3bf62SGonglei static void e1000_instance_init(Object *obj)
18985df3bf62SGonglei {
18995df3bf62SGonglei     E1000State *n = E1000(obj);
19005df3bf62SGonglei     device_add_bootindex_property(obj, &n->conf.bootindex,
19015df3bf62SGonglei                                   "bootindex", "/ethernet-phy@0",
19025df3bf62SGonglei                                   DEVICE(n), NULL);
19035df3bf62SGonglei }
19045df3bf62SGonglei 
19058597f2e1SGabriel L. Somlo static const TypeInfo e1000_base_info = {
19068597f2e1SGabriel L. Somlo     .name          = TYPE_E1000_BASE,
190739bffca2SAnthony Liguori     .parent        = TYPE_PCI_DEVICE,
190839bffca2SAnthony Liguori     .instance_size = sizeof(E1000State),
19095df3bf62SGonglei     .instance_init = e1000_instance_init,
19108597f2e1SGabriel L. Somlo     .class_size    = sizeof(E1000BaseClass),
19118597f2e1SGabriel L. Somlo     .abstract      = true,
19128597f2e1SGabriel L. Somlo };
19138597f2e1SGabriel L. Somlo 
19148597f2e1SGabriel L. Somlo static const E1000Info e1000_devices[] = {
19158597f2e1SGabriel L. Somlo     {
191683044020SJason Wang         .name      = "e1000",
19178597f2e1SGabriel L. Somlo         .device_id = E1000_DEV_ID_82540EM,
19188597f2e1SGabriel L. Somlo         .revision  = 0x03,
19198597f2e1SGabriel L. Somlo         .phy_id2   = E1000_PHY_ID2_8254xx_DEFAULT,
19208597f2e1SGabriel L. Somlo     },
19218597f2e1SGabriel L. Somlo     {
19228597f2e1SGabriel L. Somlo         .name      = "e1000-82544gc",
19238597f2e1SGabriel L. Somlo         .device_id = E1000_DEV_ID_82544GC_COPPER,
19248597f2e1SGabriel L. Somlo         .revision  = 0x03,
19258597f2e1SGabriel L. Somlo         .phy_id2   = E1000_PHY_ID2_82544x,
19268597f2e1SGabriel L. Somlo     },
19278597f2e1SGabriel L. Somlo     {
19288597f2e1SGabriel L. Somlo         .name      = "e1000-82545em",
19298597f2e1SGabriel L. Somlo         .device_id = E1000_DEV_ID_82545EM_COPPER,
19308597f2e1SGabriel L. Somlo         .revision  = 0x03,
19318597f2e1SGabriel L. Somlo         .phy_id2   = E1000_PHY_ID2_8254xx_DEFAULT,
19328597f2e1SGabriel L. Somlo     },
19338597f2e1SGabriel L. Somlo };
19348597f2e1SGabriel L. Somlo 
193583f7d43aSAndreas Färber static void e1000_register_types(void)
19369d07d757SPaul Brook {
19378597f2e1SGabriel L. Somlo     int i;
19388597f2e1SGabriel L. Somlo 
19398597f2e1SGabriel L. Somlo     type_register_static(&e1000_base_info);
19408597f2e1SGabriel L. Somlo     for (i = 0; i < ARRAY_SIZE(e1000_devices); i++) {
19418597f2e1SGabriel L. Somlo         const E1000Info *info = &e1000_devices[i];
19428597f2e1SGabriel L. Somlo         TypeInfo type_info = {};
19438597f2e1SGabriel L. Somlo 
19448597f2e1SGabriel L. Somlo         type_info.name = info->name;
19458597f2e1SGabriel L. Somlo         type_info.parent = TYPE_E1000_BASE;
19468597f2e1SGabriel L. Somlo         type_info.class_data = (void *)info;
19478597f2e1SGabriel L. Somlo         type_info.class_init = e1000_class_init;
19485df3bf62SGonglei         type_info.instance_init = e1000_instance_init;
19498597f2e1SGabriel L. Somlo 
19508597f2e1SGabriel L. Somlo         type_register(&type_info);
19518597f2e1SGabriel L. Somlo     }
19529d07d757SPaul Brook }
19539d07d757SPaul Brook 
195483f7d43aSAndreas Färber type_init(e1000_register_types)
1955