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