xref: /qemu/hw/net/e1000.c (revision eedfac6f38b2ba8be827088cd3facd19d21af1e1)
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 
2883c9f4caSPaolo Bonzini #include "hw/hw.h"
2983c9f4caSPaolo Bonzini #include "hw/pci/pci.h"
301422e32dSPaolo Bonzini #include "net/net.h"
317200ac3cSMark McLoughlin #include "net/checksum.h"
3283c9f4caSPaolo Bonzini #include "hw/loader.h"
339c17d615SPaolo Bonzini #include "sysemu/sysemu.h"
349c17d615SPaolo Bonzini #include "sysemu/dma.h"
357c23b892Sbalrog 
3647b43a1fSPaolo Bonzini #include "e1000_regs.h"
377c23b892Sbalrog 
3827124888SJes Sorensen #define E1000_DEBUG
397c23b892Sbalrog 
4027124888SJes Sorensen #ifdef E1000_DEBUG
417c23b892Sbalrog enum {
427c23b892Sbalrog     DEBUG_GENERAL,	DEBUG_IO,	DEBUG_MMIO,	DEBUG_INTERRUPT,
437c23b892Sbalrog     DEBUG_RX,		DEBUG_TX,	DEBUG_MDIC,	DEBUG_EEPROM,
447c23b892Sbalrog     DEBUG_UNKNOWN,	DEBUG_TXSUM,	DEBUG_TXERR,	DEBUG_RXERR,
45f9c1cdf4SJason Wang     DEBUG_RXFILTER,     DEBUG_PHY,      DEBUG_NOTYET,
467c23b892Sbalrog };
477c23b892Sbalrog #define DBGBIT(x)	(1<<DEBUG_##x)
487c23b892Sbalrog static int debugflags = DBGBIT(TXERR) | DBGBIT(GENERAL);
497c23b892Sbalrog 
506c7f4b47SBlue Swirl #define	DBGOUT(what, fmt, ...) do { \
517c23b892Sbalrog     if (debugflags & DBGBIT(what)) \
526c7f4b47SBlue Swirl         fprintf(stderr, "e1000: " fmt, ## __VA_ARGS__); \
537c23b892Sbalrog     } while (0)
547c23b892Sbalrog #else
556c7f4b47SBlue Swirl #define	DBGOUT(what, fmt, ...) do {} while (0)
567c23b892Sbalrog #endif
577c23b892Sbalrog 
587c23b892Sbalrog #define IOPORT_SIZE       0x40
59e94bbefeSaurel32 #define PNPMMIO_SIZE      0x20000
6078aeb23eSStefan Hajnoczi #define MIN_BUF_SIZE      60 /* Min. octets in an ethernet frame sans FCS */
617c23b892Sbalrog 
62b0d9ffcdSMichael Contreras /* this is the size past which hardware will drop packets when setting LPE=0 */
63b0d9ffcdSMichael Contreras #define MAXIMUM_ETHERNET_VLAN_SIZE 1522
642c0331f4SMichael Contreras /* this is the size past which hardware will drop packets when setting LPE=1 */
652c0331f4SMichael Contreras #define MAXIMUM_ETHERNET_LPE_SIZE 16384
66b0d9ffcdSMichael Contreras 
677c23b892Sbalrog /*
687c23b892Sbalrog  * HW models:
697c23b892Sbalrog  *  E1000_DEV_ID_82540EM works with Windows and Linux
707c23b892Sbalrog  *  E1000_DEV_ID_82573L OK with windoze and Linux 2.6.22,
717c23b892Sbalrog  *	appears to perform better than 82540EM, but breaks with Linux 2.6.18
727c23b892Sbalrog  *  E1000_DEV_ID_82544GC_COPPER appears to work; not well tested
737c23b892Sbalrog  *  Others never tested
747c23b892Sbalrog  */
757c23b892Sbalrog enum { E1000_DEVID = E1000_DEV_ID_82540EM };
767c23b892Sbalrog 
777c23b892Sbalrog /*
787c23b892Sbalrog  * May need to specify additional MAC-to-PHY entries --
797c23b892Sbalrog  * Intel's Windows driver refuses to initialize unless they match
807c23b892Sbalrog  */
817c23b892Sbalrog enum {
827c23b892Sbalrog     PHY_ID2_INIT = E1000_DEVID == E1000_DEV_ID_82573L ?		0xcc2 :
837c23b892Sbalrog                    E1000_DEVID == E1000_DEV_ID_82544GC_COPPER ?	0xc30 :
847c23b892Sbalrog                    /* default to E1000_DEV_ID_82540EM */	0xc20
857c23b892Sbalrog };
867c23b892Sbalrog 
877c23b892Sbalrog typedef struct E1000State_st {
887c23b892Sbalrog     PCIDevice dev;
89a03e2aecSMark McLoughlin     NICState *nic;
90fbdaa002SGerd Hoffmann     NICConf conf;
91ad00a9b9SAvi Kivity     MemoryRegion mmio;
92ad00a9b9SAvi Kivity     MemoryRegion io;
937c23b892Sbalrog 
947c23b892Sbalrog     uint32_t mac_reg[0x8000];
957c23b892Sbalrog     uint16_t phy_reg[0x20];
967c23b892Sbalrog     uint16_t eeprom_data[64];
977c23b892Sbalrog 
987c23b892Sbalrog     uint32_t rxbuf_size;
997c23b892Sbalrog     uint32_t rxbuf_min_shift;
1007c23b892Sbalrog     struct e1000_tx {
1017c23b892Sbalrog         unsigned char header[256];
1028f2e8d1fSaliguori         unsigned char vlan_header[4];
103b10fec9bSStefan Weil         /* Fields vlan and data must not be reordered or separated. */
1048f2e8d1fSaliguori         unsigned char vlan[4];
1057c23b892Sbalrog         unsigned char data[0x10000];
1067c23b892Sbalrog         uint16_t size;
1077c23b892Sbalrog         unsigned char sum_needed;
1088f2e8d1fSaliguori         unsigned char vlan_needed;
1097c23b892Sbalrog         uint8_t ipcss;
1107c23b892Sbalrog         uint8_t ipcso;
1117c23b892Sbalrog         uint16_t ipcse;
1127c23b892Sbalrog         uint8_t tucss;
1137c23b892Sbalrog         uint8_t tucso;
1147c23b892Sbalrog         uint16_t tucse;
1157c23b892Sbalrog         uint8_t hdr_len;
1167c23b892Sbalrog         uint16_t mss;
1177c23b892Sbalrog         uint32_t paylen;
1187c23b892Sbalrog         uint16_t tso_frames;
1197c23b892Sbalrog         char tse;
120b6c4f71fSblueswir1         int8_t ip;
121b6c4f71fSblueswir1         int8_t tcp;
1221b0009dbSbalrog         char cptse;     // current packet tse bit
1237c23b892Sbalrog     } tx;
1247c23b892Sbalrog 
1257c23b892Sbalrog     struct {
1267c23b892Sbalrog         uint32_t val_in;	// shifted in from guest driver
1277c23b892Sbalrog         uint16_t bitnum_in;
1287c23b892Sbalrog         uint16_t bitnum_out;
1297c23b892Sbalrog         uint16_t reading;
1307c23b892Sbalrog         uint32_t old_eecd;
1317c23b892Sbalrog     } eecd_state;
132b9d03e35SJason Wang 
133b9d03e35SJason Wang     QEMUTimer *autoneg_timer;
1342af234e6SMichael S. Tsirkin 
1352af234e6SMichael S. Tsirkin /* Compatibility flags for migration to/from qemu 1.3.0 and older */
1362af234e6SMichael S. Tsirkin #define E1000_FLAG_AUTONEG_BIT 0
1372af234e6SMichael S. Tsirkin #define E1000_FLAG_AUTONEG (1 << E1000_FLAG_AUTONEG_BIT)
1382af234e6SMichael S. Tsirkin     uint32_t compat_flags;
1397c23b892Sbalrog } E1000State;
1407c23b892Sbalrog 
1417c23b892Sbalrog #define	defreg(x)	x = (E1000_##x>>2)
1427c23b892Sbalrog enum {
1437c23b892Sbalrog     defreg(CTRL),	defreg(EECD),	defreg(EERD),	defreg(GPRC),
1447c23b892Sbalrog     defreg(GPTC),	defreg(ICR),	defreg(ICS),	defreg(IMC),
1457c23b892Sbalrog     defreg(IMS),	defreg(LEDCTL),	defreg(MANC),	defreg(MDIC),
1467c23b892Sbalrog     defreg(MPC),	defreg(PBA),	defreg(RCTL),	defreg(RDBAH),
1477c23b892Sbalrog     defreg(RDBAL),	defreg(RDH),	defreg(RDLEN),	defreg(RDT),
1487c23b892Sbalrog     defreg(STATUS),	defreg(SWSM),	defreg(TCTL),	defreg(TDBAH),
1497c23b892Sbalrog     defreg(TDBAL),	defreg(TDH),	defreg(TDLEN),	defreg(TDT),
1507c23b892Sbalrog     defreg(TORH),	defreg(TORL),	defreg(TOTH),	defreg(TOTL),
1517c23b892Sbalrog     defreg(TPR),	defreg(TPT),	defreg(TXDCTL),	defreg(WUFC),
1528f2e8d1fSaliguori     defreg(RA),		defreg(MTA),	defreg(CRCERRS),defreg(VFTA),
1538f2e8d1fSaliguori     defreg(VET),
1547c23b892Sbalrog };
1557c23b892Sbalrog 
15671aadd3cSJason Wang static void
15771aadd3cSJason Wang e1000_link_down(E1000State *s)
15871aadd3cSJason Wang {
15971aadd3cSJason Wang     s->mac_reg[STATUS] &= ~E1000_STATUS_LU;
16071aadd3cSJason Wang     s->phy_reg[PHY_STATUS] &= ~MII_SR_LINK_STATUS;
16171aadd3cSJason Wang }
16271aadd3cSJason Wang 
16371aadd3cSJason Wang static void
16471aadd3cSJason Wang e1000_link_up(E1000State *s)
16571aadd3cSJason Wang {
16671aadd3cSJason Wang     s->mac_reg[STATUS] |= E1000_STATUS_LU;
16771aadd3cSJason Wang     s->phy_reg[PHY_STATUS] |= MII_SR_LINK_STATUS;
16871aadd3cSJason Wang }
16971aadd3cSJason Wang 
170b9d03e35SJason Wang static void
171b9d03e35SJason Wang set_phy_ctrl(E1000State *s, int index, uint16_t val)
172b9d03e35SJason Wang {
1732af234e6SMichael S. Tsirkin     /*
1742af234e6SMichael S. Tsirkin      * QEMU 1.3 does not support link auto-negotiation emulation, so if we
1752af234e6SMichael S. Tsirkin      * migrate during auto negotiation, after migration the link will be
1762af234e6SMichael S. Tsirkin      * down.
1772af234e6SMichael S. Tsirkin      */
1782af234e6SMichael S. Tsirkin     if (!(s->compat_flags & E1000_FLAG_AUTONEG)) {
1792af234e6SMichael S. Tsirkin         return;
1802af234e6SMichael S. Tsirkin     }
181b9d03e35SJason Wang     if ((val & MII_CR_AUTO_NEG_EN) && (val & MII_CR_RESTART_AUTO_NEG)) {
182b9d03e35SJason Wang         e1000_link_down(s);
183b9d03e35SJason Wang         s->phy_reg[PHY_STATUS] &= ~MII_SR_AUTONEG_COMPLETE;
184b9d03e35SJason Wang         DBGOUT(PHY, "Start link auto negotiation\n");
185b9d03e35SJason Wang         qemu_mod_timer(s->autoneg_timer, qemu_get_clock_ms(vm_clock) + 500);
186b9d03e35SJason Wang     }
187b9d03e35SJason Wang }
188b9d03e35SJason Wang 
189b9d03e35SJason Wang static void
190b9d03e35SJason Wang e1000_autoneg_timer(void *opaque)
191b9d03e35SJason Wang {
192b9d03e35SJason Wang     E1000State *s = opaque;
193ddcb73b7SMichael S. Tsirkin     if (!qemu_get_queue(s->nic)->link_down) {
194b9d03e35SJason Wang         e1000_link_up(s);
195ddcb73b7SMichael S. Tsirkin     }
196b9d03e35SJason Wang     s->phy_reg[PHY_STATUS] |= MII_SR_AUTONEG_COMPLETE;
197b9d03e35SJason Wang     DBGOUT(PHY, "Auto negotiation is completed\n");
198b9d03e35SJason Wang }
199b9d03e35SJason Wang 
200b9d03e35SJason Wang static void (*phyreg_writeops[])(E1000State *, int, uint16_t) = {
201b9d03e35SJason Wang     [PHY_CTRL] = set_phy_ctrl,
202b9d03e35SJason Wang };
203b9d03e35SJason Wang 
204b9d03e35SJason Wang enum { NPHYWRITEOPS = ARRAY_SIZE(phyreg_writeops) };
205b9d03e35SJason Wang 
2067c23b892Sbalrog enum { PHY_R = 1, PHY_W = 2, PHY_RW = PHY_R | PHY_W };
20788b4e9dbSblueswir1 static const char phy_regcap[0x20] = {
2087c23b892Sbalrog     [PHY_STATUS] = PHY_R,	[M88E1000_EXT_PHY_SPEC_CTRL] = PHY_RW,
2097c23b892Sbalrog     [PHY_ID1] = PHY_R,		[M88E1000_PHY_SPEC_CTRL] = PHY_RW,
2107c23b892Sbalrog     [PHY_CTRL] = PHY_RW,	[PHY_1000T_CTRL] = PHY_RW,
2117c23b892Sbalrog     [PHY_LP_ABILITY] = PHY_R,	[PHY_1000T_STATUS] = PHY_R,
2127c23b892Sbalrog     [PHY_AUTONEG_ADV] = PHY_RW,	[M88E1000_RX_ERR_CNTR] = PHY_R,
213700f6e2cSaurel32     [PHY_ID2] = PHY_R,		[M88E1000_PHY_SPEC_STATUS] = PHY_R
2147c23b892Sbalrog };
2157c23b892Sbalrog 
216814cd3acSMichael S. Tsirkin static const uint16_t phy_reg_init[] = {
217b9d03e35SJason Wang     [PHY_CTRL] = 0x1140,
218b9d03e35SJason Wang     [PHY_STATUS] = 0x794d, /* link initially up with not completed autoneg */
219814cd3acSMichael S. Tsirkin     [PHY_ID1] = 0x141,				[PHY_ID2] = PHY_ID2_INIT,
220814cd3acSMichael S. Tsirkin     [PHY_1000T_CTRL] = 0x0e00,			[M88E1000_PHY_SPEC_CTRL] = 0x360,
221814cd3acSMichael S. Tsirkin     [M88E1000_EXT_PHY_SPEC_CTRL] = 0x0d60,	[PHY_AUTONEG_ADV] = 0xde1,
222814cd3acSMichael S. Tsirkin     [PHY_LP_ABILITY] = 0x1e0,			[PHY_1000T_STATUS] = 0x3c00,
223814cd3acSMichael S. Tsirkin     [M88E1000_PHY_SPEC_STATUS] = 0xac00,
224814cd3acSMichael S. Tsirkin };
225814cd3acSMichael S. Tsirkin 
226814cd3acSMichael S. Tsirkin static const uint32_t mac_reg_init[] = {
227814cd3acSMichael S. Tsirkin     [PBA] =     0x00100030,
228814cd3acSMichael S. Tsirkin     [LEDCTL] =  0x602,
229814cd3acSMichael S. Tsirkin     [CTRL] =    E1000_CTRL_SWDPIN2 | E1000_CTRL_SWDPIN0 |
230814cd3acSMichael S. Tsirkin                 E1000_CTRL_SPD_1000 | E1000_CTRL_SLU,
231814cd3acSMichael S. Tsirkin     [STATUS] =  0x80000000 | E1000_STATUS_GIO_MASTER_ENABLE |
232814cd3acSMichael S. Tsirkin                 E1000_STATUS_ASDV | E1000_STATUS_MTXCKOK |
233814cd3acSMichael S. Tsirkin                 E1000_STATUS_SPEED_1000 | E1000_STATUS_FD |
234814cd3acSMichael S. Tsirkin                 E1000_STATUS_LU,
235814cd3acSMichael S. Tsirkin     [MANC] =    E1000_MANC_EN_MNG2HOST | E1000_MANC_RCV_TCO_EN |
236814cd3acSMichael S. Tsirkin                 E1000_MANC_ARP_EN | E1000_MANC_0298_EN |
237814cd3acSMichael S. Tsirkin                 E1000_MANC_RMCP_EN,
238814cd3acSMichael S. Tsirkin };
239814cd3acSMichael S. Tsirkin 
2407c23b892Sbalrog static void
2417c23b892Sbalrog set_interrupt_cause(E1000State *s, int index, uint32_t val)
2427c23b892Sbalrog {
243f1219091SJason Wang     if (val && (E1000_DEVID >= E1000_DEV_ID_82547EI_MOBILE)) {
244f1219091SJason Wang         /* Only for 8257x */
2457c23b892Sbalrog         val |= E1000_ICR_INT_ASSERTED;
246f1219091SJason Wang     }
2477c23b892Sbalrog     s->mac_reg[ICR] = val;
248a52a8841SMichael S. Tsirkin 
249a52a8841SMichael S. Tsirkin     /*
250a52a8841SMichael S. Tsirkin      * Make sure ICR and ICS registers have the same value.
251a52a8841SMichael S. Tsirkin      * The spec says that the ICS register is write-only.  However in practice,
252a52a8841SMichael S. Tsirkin      * on real hardware ICS is readable, and for reads it has the same value as
253a52a8841SMichael S. Tsirkin      * ICR (except that ICS does not have the clear on read behaviour of ICR).
254a52a8841SMichael S. Tsirkin      *
255a52a8841SMichael S. Tsirkin      * The VxWorks PRO/1000 driver uses this behaviour.
256a52a8841SMichael S. Tsirkin      */
257b1332393SBill Paul     s->mac_reg[ICS] = val;
258a52a8841SMichael S. Tsirkin 
259bc26e55aSBlue Swirl     qemu_set_irq(s->dev.irq[0], (s->mac_reg[IMS] & s->mac_reg[ICR]) != 0);
2607c23b892Sbalrog }
2617c23b892Sbalrog 
2627c23b892Sbalrog static void
2637c23b892Sbalrog set_ics(E1000State *s, int index, uint32_t val)
2647c23b892Sbalrog {
2657c23b892Sbalrog     DBGOUT(INTERRUPT, "set_ics %x, ICR %x, IMR %x\n", val, s->mac_reg[ICR],
2667c23b892Sbalrog         s->mac_reg[IMS]);
2677c23b892Sbalrog     set_interrupt_cause(s, 0, val | s->mac_reg[ICR]);
2687c23b892Sbalrog }
2697c23b892Sbalrog 
2707c23b892Sbalrog static int
2717c23b892Sbalrog rxbufsize(uint32_t v)
2727c23b892Sbalrog {
2737c23b892Sbalrog     v &= E1000_RCTL_BSEX | E1000_RCTL_SZ_16384 | E1000_RCTL_SZ_8192 |
2747c23b892Sbalrog          E1000_RCTL_SZ_4096 | E1000_RCTL_SZ_2048 | E1000_RCTL_SZ_1024 |
2757c23b892Sbalrog          E1000_RCTL_SZ_512 | E1000_RCTL_SZ_256;
2767c23b892Sbalrog     switch (v) {
2777c23b892Sbalrog     case E1000_RCTL_BSEX | E1000_RCTL_SZ_16384:
2787c23b892Sbalrog         return 16384;
2797c23b892Sbalrog     case E1000_RCTL_BSEX | E1000_RCTL_SZ_8192:
2807c23b892Sbalrog         return 8192;
2817c23b892Sbalrog     case E1000_RCTL_BSEX | E1000_RCTL_SZ_4096:
2827c23b892Sbalrog         return 4096;
2837c23b892Sbalrog     case E1000_RCTL_SZ_1024:
2847c23b892Sbalrog         return 1024;
2857c23b892Sbalrog     case E1000_RCTL_SZ_512:
2867c23b892Sbalrog         return 512;
2877c23b892Sbalrog     case E1000_RCTL_SZ_256:
2887c23b892Sbalrog         return 256;
2897c23b892Sbalrog     }
2907c23b892Sbalrog     return 2048;
2917c23b892Sbalrog }
2927c23b892Sbalrog 
293814cd3acSMichael S. Tsirkin static void e1000_reset(void *opaque)
294814cd3acSMichael S. Tsirkin {
295814cd3acSMichael S. Tsirkin     E1000State *d = opaque;
296372254c6SGabriel L. Somlo     uint8_t *macaddr = d->conf.macaddr.a;
297372254c6SGabriel L. Somlo     int i;
298814cd3acSMichael S. Tsirkin 
299b9d03e35SJason Wang     qemu_del_timer(d->autoneg_timer);
300814cd3acSMichael S. Tsirkin     memset(d->phy_reg, 0, sizeof d->phy_reg);
301814cd3acSMichael S. Tsirkin     memmove(d->phy_reg, phy_reg_init, sizeof phy_reg_init);
302814cd3acSMichael S. Tsirkin     memset(d->mac_reg, 0, sizeof d->mac_reg);
303814cd3acSMichael S. Tsirkin     memmove(d->mac_reg, mac_reg_init, sizeof mac_reg_init);
304814cd3acSMichael S. Tsirkin     d->rxbuf_min_shift = 1;
305814cd3acSMichael S. Tsirkin     memset(&d->tx, 0, sizeof d->tx);
306814cd3acSMichael S. Tsirkin 
307b356f76dSJason Wang     if (qemu_get_queue(d->nic)->link_down) {
30871aadd3cSJason Wang         e1000_link_down(d);
309814cd3acSMichael S. Tsirkin     }
310372254c6SGabriel L. Somlo 
311372254c6SGabriel L. Somlo     /* Some guests expect pre-initialized RAH/RAL (AddrValid flag + MACaddr) */
312372254c6SGabriel L. Somlo     d->mac_reg[RA] = 0;
313372254c6SGabriel L. Somlo     d->mac_reg[RA + 1] = E1000_RAH_AV;
314372254c6SGabriel L. Somlo     for (i = 0; i < 4; i++) {
315372254c6SGabriel L. Somlo         d->mac_reg[RA] |= macaddr[i] << (8 * i);
316372254c6SGabriel L. Somlo         d->mac_reg[RA + 1] |= (i < 2) ? macaddr[i + 4] << (8 * i) : 0;
317372254c6SGabriel L. Somlo     }
318814cd3acSMichael S. Tsirkin }
319814cd3acSMichael S. Tsirkin 
3207c23b892Sbalrog static void
321cab3c825SKevin Wolf set_ctrl(E1000State *s, int index, uint32_t val)
322cab3c825SKevin Wolf {
323cab3c825SKevin Wolf     /* RST is self clearing */
324cab3c825SKevin Wolf     s->mac_reg[CTRL] = val & ~E1000_CTRL_RST;
325cab3c825SKevin Wolf }
326cab3c825SKevin Wolf 
327cab3c825SKevin Wolf static void
3287c23b892Sbalrog set_rx_control(E1000State *s, int index, uint32_t val)
3297c23b892Sbalrog {
3307c23b892Sbalrog     s->mac_reg[RCTL] = val;
3317c23b892Sbalrog     s->rxbuf_size = rxbufsize(val);
3327c23b892Sbalrog     s->rxbuf_min_shift = ((val / E1000_RCTL_RDMTS_QUAT) & 3) + 1;
3337c23b892Sbalrog     DBGOUT(RX, "RCTL: %d, mac_reg[RCTL] = 0x%x\n", s->mac_reg[RDT],
3347c23b892Sbalrog            s->mac_reg[RCTL]);
335b356f76dSJason Wang     qemu_flush_queued_packets(qemu_get_queue(s->nic));
3367c23b892Sbalrog }
3377c23b892Sbalrog 
3387c23b892Sbalrog static void
3397c23b892Sbalrog set_mdic(E1000State *s, int index, uint32_t val)
3407c23b892Sbalrog {
3417c23b892Sbalrog     uint32_t data = val & E1000_MDIC_DATA_MASK;
3427c23b892Sbalrog     uint32_t addr = ((val & E1000_MDIC_REG_MASK) >> E1000_MDIC_REG_SHIFT);
3437c23b892Sbalrog 
3447c23b892Sbalrog     if ((val & E1000_MDIC_PHY_MASK) >> E1000_MDIC_PHY_SHIFT != 1) // phy #
3457c23b892Sbalrog         val = s->mac_reg[MDIC] | E1000_MDIC_ERROR;
3467c23b892Sbalrog     else if (val & E1000_MDIC_OP_READ) {
3477c23b892Sbalrog         DBGOUT(MDIC, "MDIC read reg 0x%x\n", addr);
3487c23b892Sbalrog         if (!(phy_regcap[addr] & PHY_R)) {
3497c23b892Sbalrog             DBGOUT(MDIC, "MDIC read reg %x unhandled\n", addr);
3507c23b892Sbalrog             val |= E1000_MDIC_ERROR;
3517c23b892Sbalrog         } else
3527c23b892Sbalrog             val = (val ^ data) | s->phy_reg[addr];
3537c23b892Sbalrog     } else if (val & E1000_MDIC_OP_WRITE) {
3547c23b892Sbalrog         DBGOUT(MDIC, "MDIC write reg 0x%x, value 0x%x\n", addr, data);
3557c23b892Sbalrog         if (!(phy_regcap[addr] & PHY_W)) {
3567c23b892Sbalrog             DBGOUT(MDIC, "MDIC write reg %x unhandled\n", addr);
3577c23b892Sbalrog             val |= E1000_MDIC_ERROR;
358b9d03e35SJason Wang         } else {
359b9d03e35SJason Wang             if (addr < NPHYWRITEOPS && phyreg_writeops[addr]) {
360b9d03e35SJason Wang                 phyreg_writeops[addr](s, index, data);
361b9d03e35SJason Wang             }
3627c23b892Sbalrog             s->phy_reg[addr] = data;
3637c23b892Sbalrog         }
364b9d03e35SJason Wang     }
3657c23b892Sbalrog     s->mac_reg[MDIC] = val | E1000_MDIC_READY;
36617fbbb0bSJason Wang 
36717fbbb0bSJason Wang     if (val & E1000_MDIC_INT_EN) {
3687c23b892Sbalrog         set_ics(s, 0, E1000_ICR_MDAC);
3697c23b892Sbalrog     }
37017fbbb0bSJason Wang }
3717c23b892Sbalrog 
3727c23b892Sbalrog static uint32_t
3737c23b892Sbalrog get_eecd(E1000State *s, int index)
3747c23b892Sbalrog {
3757c23b892Sbalrog     uint32_t ret = E1000_EECD_PRES|E1000_EECD_GNT | s->eecd_state.old_eecd;
3767c23b892Sbalrog 
3777c23b892Sbalrog     DBGOUT(EEPROM, "reading eeprom bit %d (reading %d)\n",
3787c23b892Sbalrog            s->eecd_state.bitnum_out, s->eecd_state.reading);
3797c23b892Sbalrog     if (!s->eecd_state.reading ||
3807c23b892Sbalrog         ((s->eeprom_data[(s->eecd_state.bitnum_out >> 4) & 0x3f] >>
3817c23b892Sbalrog           ((s->eecd_state.bitnum_out & 0xf) ^ 0xf))) & 1)
3827c23b892Sbalrog         ret |= E1000_EECD_DO;
3837c23b892Sbalrog     return ret;
3847c23b892Sbalrog }
3857c23b892Sbalrog 
3867c23b892Sbalrog static void
3877c23b892Sbalrog set_eecd(E1000State *s, int index, uint32_t val)
3887c23b892Sbalrog {
3897c23b892Sbalrog     uint32_t oldval = s->eecd_state.old_eecd;
3907c23b892Sbalrog 
3917c23b892Sbalrog     s->eecd_state.old_eecd = val & (E1000_EECD_SK | E1000_EECD_CS |
3927c23b892Sbalrog             E1000_EECD_DI|E1000_EECD_FWE_MASK|E1000_EECD_REQ);
3939651ac55SIzumi Tsutsui     if (!(E1000_EECD_CS & val))			// CS inactive; nothing to do
3949651ac55SIzumi Tsutsui 	return;
3959651ac55SIzumi Tsutsui     if (E1000_EECD_CS & (val ^ oldval)) {	// CS rise edge; reset state
3969651ac55SIzumi Tsutsui 	s->eecd_state.val_in = 0;
3979651ac55SIzumi Tsutsui 	s->eecd_state.bitnum_in = 0;
3989651ac55SIzumi Tsutsui 	s->eecd_state.bitnum_out = 0;
3999651ac55SIzumi Tsutsui 	s->eecd_state.reading = 0;
4009651ac55SIzumi Tsutsui     }
4017c23b892Sbalrog     if (!(E1000_EECD_SK & (val ^ oldval)))	// no clock edge
4027c23b892Sbalrog         return;
4037c23b892Sbalrog     if (!(E1000_EECD_SK & val)) {		// falling edge
4047c23b892Sbalrog         s->eecd_state.bitnum_out++;
4057c23b892Sbalrog         return;
4067c23b892Sbalrog     }
4077c23b892Sbalrog     s->eecd_state.val_in <<= 1;
4087c23b892Sbalrog     if (val & E1000_EECD_DI)
4097c23b892Sbalrog         s->eecd_state.val_in |= 1;
4107c23b892Sbalrog     if (++s->eecd_state.bitnum_in == 9 && !s->eecd_state.reading) {
4117c23b892Sbalrog         s->eecd_state.bitnum_out = ((s->eecd_state.val_in & 0x3f)<<4)-1;
4127c23b892Sbalrog         s->eecd_state.reading = (((s->eecd_state.val_in >> 6) & 7) ==
4137c23b892Sbalrog             EEPROM_READ_OPCODE_MICROWIRE);
4147c23b892Sbalrog     }
4157c23b892Sbalrog     DBGOUT(EEPROM, "eeprom bitnum in %d out %d, reading %d\n",
4167c23b892Sbalrog            s->eecd_state.bitnum_in, s->eecd_state.bitnum_out,
4177c23b892Sbalrog            s->eecd_state.reading);
4187c23b892Sbalrog }
4197c23b892Sbalrog 
4207c23b892Sbalrog static uint32_t
4217c23b892Sbalrog flash_eerd_read(E1000State *s, int x)
4227c23b892Sbalrog {
4237c23b892Sbalrog     unsigned int index, r = s->mac_reg[EERD] & ~E1000_EEPROM_RW_REG_START;
4247c23b892Sbalrog 
425b1332393SBill Paul     if ((s->mac_reg[EERD] & E1000_EEPROM_RW_REG_START) == 0)
426b1332393SBill Paul         return (s->mac_reg[EERD]);
427b1332393SBill Paul 
4287c23b892Sbalrog     if ((index = r >> E1000_EEPROM_RW_ADDR_SHIFT) > EEPROM_CHECKSUM_REG)
429b1332393SBill Paul         return (E1000_EEPROM_RW_REG_DONE | r);
430b1332393SBill Paul 
431b1332393SBill Paul     return ((s->eeprom_data[index] << E1000_EEPROM_RW_REG_DATA) |
432b1332393SBill Paul            E1000_EEPROM_RW_REG_DONE | r);
4337c23b892Sbalrog }
4347c23b892Sbalrog 
4357c23b892Sbalrog static void
4367c23b892Sbalrog putsum(uint8_t *data, uint32_t n, uint32_t sloc, uint32_t css, uint32_t cse)
4377c23b892Sbalrog {
438c6a6a5e3Saliguori     uint32_t sum;
439c6a6a5e3Saliguori 
4407c23b892Sbalrog     if (cse && cse < n)
4417c23b892Sbalrog         n = cse + 1;
442c6a6a5e3Saliguori     if (sloc < n-1) {
443c6a6a5e3Saliguori         sum = net_checksum_add(n-css, data+css);
4447c23b892Sbalrog         cpu_to_be16wu((uint16_t *)(data + sloc),
445c6a6a5e3Saliguori                       net_checksum_finish(sum));
446c6a6a5e3Saliguori     }
4477c23b892Sbalrog }
4487c23b892Sbalrog 
4498f2e8d1fSaliguori static inline int
4508f2e8d1fSaliguori vlan_enabled(E1000State *s)
4518f2e8d1fSaliguori {
4528f2e8d1fSaliguori     return ((s->mac_reg[CTRL] & E1000_CTRL_VME) != 0);
4538f2e8d1fSaliguori }
4548f2e8d1fSaliguori 
4558f2e8d1fSaliguori static inline int
4568f2e8d1fSaliguori vlan_rx_filter_enabled(E1000State *s)
4578f2e8d1fSaliguori {
4588f2e8d1fSaliguori     return ((s->mac_reg[RCTL] & E1000_RCTL_VFE) != 0);
4598f2e8d1fSaliguori }
4608f2e8d1fSaliguori 
4618f2e8d1fSaliguori static inline int
4628f2e8d1fSaliguori is_vlan_packet(E1000State *s, const uint8_t *buf)
4638f2e8d1fSaliguori {
4648f2e8d1fSaliguori     return (be16_to_cpup((uint16_t *)(buf + 12)) ==
4658f2e8d1fSaliguori                 le16_to_cpup((uint16_t *)(s->mac_reg + VET)));
4668f2e8d1fSaliguori }
4678f2e8d1fSaliguori 
4688f2e8d1fSaliguori static inline int
4698f2e8d1fSaliguori is_vlan_txd(uint32_t txd_lower)
4708f2e8d1fSaliguori {
4718f2e8d1fSaliguori     return ((txd_lower & E1000_TXD_CMD_VLE) != 0);
4728f2e8d1fSaliguori }
4738f2e8d1fSaliguori 
47455e8d1ceSMichael S. Tsirkin /* FCS aka Ethernet CRC-32. We don't get it from backends and can't
47555e8d1ceSMichael S. Tsirkin  * fill it in, just pad descriptor length by 4 bytes unless guest
476a05e8a6eSMichael S. Tsirkin  * told us to strip it off the packet. */
47755e8d1ceSMichael S. Tsirkin static inline int
47855e8d1ceSMichael S. Tsirkin fcs_len(E1000State *s)
47955e8d1ceSMichael S. Tsirkin {
48055e8d1ceSMichael S. Tsirkin     return (s->mac_reg[RCTL] & E1000_RCTL_SECRC) ? 0 : 4;
48155e8d1ceSMichael S. Tsirkin }
48255e8d1ceSMichael S. Tsirkin 
4837c23b892Sbalrog static void
48493e37d76SJason Wang e1000_send_packet(E1000State *s, const uint8_t *buf, int size)
48593e37d76SJason Wang {
486b356f76dSJason Wang     NetClientState *nc = qemu_get_queue(s->nic);
48793e37d76SJason Wang     if (s->phy_reg[PHY_CTRL] & MII_CR_LOOPBACK) {
488b356f76dSJason Wang         nc->info->receive(nc, buf, size);
48993e37d76SJason Wang     } else {
490b356f76dSJason Wang         qemu_send_packet(nc, buf, size);
49193e37d76SJason Wang     }
49293e37d76SJason Wang }
49393e37d76SJason Wang 
49493e37d76SJason Wang static void
4957c23b892Sbalrog xmit_seg(E1000State *s)
4967c23b892Sbalrog {
4977c23b892Sbalrog     uint16_t len, *sp;
4987c23b892Sbalrog     unsigned int frames = s->tx.tso_frames, css, sofar, n;
4997c23b892Sbalrog     struct e1000_tx *tp = &s->tx;
5007c23b892Sbalrog 
5011b0009dbSbalrog     if (tp->tse && tp->cptse) {
5027c23b892Sbalrog         css = tp->ipcss;
5037c23b892Sbalrog         DBGOUT(TXSUM, "frames %d size %d ipcss %d\n",
5047c23b892Sbalrog                frames, tp->size, css);
5057c23b892Sbalrog         if (tp->ip) {		// IPv4
5067c23b892Sbalrog             cpu_to_be16wu((uint16_t *)(tp->data+css+2),
5077c23b892Sbalrog                           tp->size - css);
5087c23b892Sbalrog             cpu_to_be16wu((uint16_t *)(tp->data+css+4),
5097c23b892Sbalrog                           be16_to_cpup((uint16_t *)(tp->data+css+4))+frames);
5107c23b892Sbalrog         } else			// IPv6
5117c23b892Sbalrog             cpu_to_be16wu((uint16_t *)(tp->data+css+4),
5127c23b892Sbalrog                           tp->size - css);
5137c23b892Sbalrog         css = tp->tucss;
5147c23b892Sbalrog         len = tp->size - css;
5157c23b892Sbalrog         DBGOUT(TXSUM, "tcp %d tucss %d len %d\n", tp->tcp, css, len);
5167c23b892Sbalrog         if (tp->tcp) {
5177c23b892Sbalrog             sofar = frames * tp->mss;
5187c23b892Sbalrog             cpu_to_be32wu((uint32_t *)(tp->data+css+4),	// seq
51988738c09Saurel32                 be32_to_cpupu((uint32_t *)(tp->data+css+4))+sofar);
5207c23b892Sbalrog             if (tp->paylen - sofar > tp->mss)
5217c23b892Sbalrog                 tp->data[css + 13] &= ~9;		// PSH, FIN
5227c23b892Sbalrog         } else	// UDP
5237c23b892Sbalrog             cpu_to_be16wu((uint16_t *)(tp->data+css+4), len);
5247c23b892Sbalrog         if (tp->sum_needed & E1000_TXD_POPTS_TXSM) {
525e685b4ebSAlex Williamson             unsigned int phsum;
5267c23b892Sbalrog             // add pseudo-header length before checksum calculation
5277c23b892Sbalrog             sp = (uint16_t *)(tp->data + tp->tucso);
528e685b4ebSAlex Williamson             phsum = be16_to_cpup(sp) + len;
529e685b4ebSAlex Williamson             phsum = (phsum >> 16) + (phsum & 0xffff);
530e685b4ebSAlex Williamson             cpu_to_be16wu(sp, phsum);
5317c23b892Sbalrog         }
5327c23b892Sbalrog         tp->tso_frames++;
5337c23b892Sbalrog     }
5347c23b892Sbalrog 
5357c23b892Sbalrog     if (tp->sum_needed & E1000_TXD_POPTS_TXSM)
5367c23b892Sbalrog         putsum(tp->data, tp->size, tp->tucso, tp->tucss, tp->tucse);
5377c23b892Sbalrog     if (tp->sum_needed & E1000_TXD_POPTS_IXSM)
5387c23b892Sbalrog         putsum(tp->data, tp->size, tp->ipcso, tp->ipcss, tp->ipcse);
5398f2e8d1fSaliguori     if (tp->vlan_needed) {
540b10fec9bSStefan Weil         memmove(tp->vlan, tp->data, 4);
541b10fec9bSStefan Weil         memmove(tp->data, tp->data + 4, 8);
5428f2e8d1fSaliguori         memcpy(tp->data + 8, tp->vlan_header, 4);
54393e37d76SJason Wang         e1000_send_packet(s, tp->vlan, tp->size + 4);
5448f2e8d1fSaliguori     } else
54593e37d76SJason Wang         e1000_send_packet(s, tp->data, tp->size);
5467c23b892Sbalrog     s->mac_reg[TPT]++;
5477c23b892Sbalrog     s->mac_reg[GPTC]++;
5487c23b892Sbalrog     n = s->mac_reg[TOTL];
5497c23b892Sbalrog     if ((s->mac_reg[TOTL] += s->tx.size) < n)
5507c23b892Sbalrog         s->mac_reg[TOTH]++;
5517c23b892Sbalrog }
5527c23b892Sbalrog 
5537c23b892Sbalrog static void
5547c23b892Sbalrog process_tx_desc(E1000State *s, struct e1000_tx_desc *dp)
5557c23b892Sbalrog {
5567c23b892Sbalrog     uint32_t txd_lower = le32_to_cpu(dp->lower.data);
5577c23b892Sbalrog     uint32_t dtype = txd_lower & (E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D);
5587c23b892Sbalrog     unsigned int split_size = txd_lower & 0xffff, bytes, sz, op;
5597c23b892Sbalrog     unsigned int msh = 0xfffff, hdr = 0;
5607c23b892Sbalrog     uint64_t addr;
5617c23b892Sbalrog     struct e1000_context_desc *xp = (struct e1000_context_desc *)dp;
5627c23b892Sbalrog     struct e1000_tx *tp = &s->tx;
5637c23b892Sbalrog 
5647c23b892Sbalrog     if (dtype == E1000_TXD_CMD_DEXT) {	// context descriptor
5657c23b892Sbalrog         op = le32_to_cpu(xp->cmd_and_length);
5667c23b892Sbalrog         tp->ipcss = xp->lower_setup.ip_fields.ipcss;
5677c23b892Sbalrog         tp->ipcso = xp->lower_setup.ip_fields.ipcso;
5687c23b892Sbalrog         tp->ipcse = le16_to_cpu(xp->lower_setup.ip_fields.ipcse);
5697c23b892Sbalrog         tp->tucss = xp->upper_setup.tcp_fields.tucss;
5707c23b892Sbalrog         tp->tucso = xp->upper_setup.tcp_fields.tucso;
5717c23b892Sbalrog         tp->tucse = le16_to_cpu(xp->upper_setup.tcp_fields.tucse);
5727c23b892Sbalrog         tp->paylen = op & 0xfffff;
5737c23b892Sbalrog         tp->hdr_len = xp->tcp_seg_setup.fields.hdr_len;
5747c23b892Sbalrog         tp->mss = le16_to_cpu(xp->tcp_seg_setup.fields.mss);
5757c23b892Sbalrog         tp->ip = (op & E1000_TXD_CMD_IP) ? 1 : 0;
5767c23b892Sbalrog         tp->tcp = (op & E1000_TXD_CMD_TCP) ? 1 : 0;
5777c23b892Sbalrog         tp->tse = (op & E1000_TXD_CMD_TSE) ? 1 : 0;
5787c23b892Sbalrog         tp->tso_frames = 0;
5797c23b892Sbalrog         if (tp->tucso == 0) {	// this is probably wrong
5807c23b892Sbalrog             DBGOUT(TXSUM, "TCP/UDP: cso 0!\n");
5817c23b892Sbalrog             tp->tucso = tp->tucss + (tp->tcp ? 16 : 6);
5827c23b892Sbalrog         }
5837c23b892Sbalrog         return;
5841b0009dbSbalrog     } else if (dtype == (E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D)) {
5851b0009dbSbalrog         // data descriptor
586735e77ecSStefan Hajnoczi         if (tp->size == 0) {
5877c23b892Sbalrog             tp->sum_needed = le32_to_cpu(dp->upper.data) >> 8;
588735e77ecSStefan Hajnoczi         }
5891b0009dbSbalrog         tp->cptse = ( txd_lower & E1000_TXD_CMD_TSE ) ? 1 : 0;
59043ad7e3eSJes Sorensen     } else {
5911b0009dbSbalrog         // legacy descriptor
5921b0009dbSbalrog         tp->cptse = 0;
59343ad7e3eSJes Sorensen     }
5947c23b892Sbalrog 
5958f2e8d1fSaliguori     if (vlan_enabled(s) && is_vlan_txd(txd_lower) &&
5968f2e8d1fSaliguori         (tp->cptse || txd_lower & E1000_TXD_CMD_EOP)) {
5978f2e8d1fSaliguori         tp->vlan_needed = 1;
5988f2e8d1fSaliguori         cpu_to_be16wu((uint16_t *)(tp->vlan_header),
5998f2e8d1fSaliguori                       le16_to_cpup((uint16_t *)(s->mac_reg + VET)));
6008f2e8d1fSaliguori         cpu_to_be16wu((uint16_t *)(tp->vlan_header + 2),
6018f2e8d1fSaliguori                       le16_to_cpu(dp->upper.fields.special));
6028f2e8d1fSaliguori     }
6038f2e8d1fSaliguori 
6047c23b892Sbalrog     addr = le64_to_cpu(dp->buffer_addr);
6051b0009dbSbalrog     if (tp->tse && tp->cptse) {
6067c23b892Sbalrog         hdr = tp->hdr_len;
6077c23b892Sbalrog         msh = hdr + tp->mss;
6087c23b892Sbalrog         do {
6097c23b892Sbalrog             bytes = split_size;
6107c23b892Sbalrog             if (tp->size + bytes > msh)
6117c23b892Sbalrog                 bytes = msh - tp->size;
61265f82df0SAnthony Liguori 
61365f82df0SAnthony Liguori             bytes = MIN(sizeof(tp->data) - tp->size, bytes);
61462ecbd35SEduard - Gabriel Munteanu             pci_dma_read(&s->dev, addr, tp->data + tp->size, bytes);
6157c23b892Sbalrog             if ((sz = tp->size + bytes) >= hdr && tp->size < hdr)
6167c23b892Sbalrog                 memmove(tp->header, tp->data, hdr);
6177c23b892Sbalrog             tp->size = sz;
6187c23b892Sbalrog             addr += bytes;
6197c23b892Sbalrog             if (sz == msh) {
6207c23b892Sbalrog                 xmit_seg(s);
6217c23b892Sbalrog                 memmove(tp->data, tp->header, hdr);
6227c23b892Sbalrog                 tp->size = hdr;
6237c23b892Sbalrog             }
6247c23b892Sbalrog         } while (split_size -= bytes);
6251b0009dbSbalrog     } else if (!tp->tse && tp->cptse) {
6261b0009dbSbalrog         // context descriptor TSE is not set, while data descriptor TSE is set
627362f5fb5SStefan Weil         DBGOUT(TXERR, "TCP segmentation error\n");
6281b0009dbSbalrog     } else {
62965f82df0SAnthony Liguori         split_size = MIN(sizeof(tp->data) - tp->size, split_size);
63062ecbd35SEduard - Gabriel Munteanu         pci_dma_read(&s->dev, addr, tp->data + tp->size, split_size);
6311b0009dbSbalrog         tp->size += split_size;
6321b0009dbSbalrog     }
6337c23b892Sbalrog 
6347c23b892Sbalrog     if (!(txd_lower & E1000_TXD_CMD_EOP))
6357c23b892Sbalrog         return;
6361b0009dbSbalrog     if (!(tp->tse && tp->cptse && tp->size < hdr))
6377c23b892Sbalrog         xmit_seg(s);
6387c23b892Sbalrog     tp->tso_frames = 0;
6397c23b892Sbalrog     tp->sum_needed = 0;
6408f2e8d1fSaliguori     tp->vlan_needed = 0;
6417c23b892Sbalrog     tp->size = 0;
6421b0009dbSbalrog     tp->cptse = 0;
6437c23b892Sbalrog }
6447c23b892Sbalrog 
6457c23b892Sbalrog static uint32_t
64662ecbd35SEduard - Gabriel Munteanu txdesc_writeback(E1000State *s, dma_addr_t base, struct e1000_tx_desc *dp)
6477c23b892Sbalrog {
6487c23b892Sbalrog     uint32_t txd_upper, txd_lower = le32_to_cpu(dp->lower.data);
6497c23b892Sbalrog 
6507c23b892Sbalrog     if (!(txd_lower & (E1000_TXD_CMD_RS|E1000_TXD_CMD_RPS)))
6517c23b892Sbalrog         return 0;
6527c23b892Sbalrog     txd_upper = (le32_to_cpu(dp->upper.data) | E1000_TXD_STAT_DD) &
6537c23b892Sbalrog                 ~(E1000_TXD_STAT_EC | E1000_TXD_STAT_LC | E1000_TXD_STAT_TU);
6547c23b892Sbalrog     dp->upper.data = cpu_to_le32(txd_upper);
65562ecbd35SEduard - Gabriel Munteanu     pci_dma_write(&s->dev, base + ((char *)&dp->upper - (char *)dp),
65600c3a05bSDavid Gibson                   &dp->upper, sizeof(dp->upper));
6577c23b892Sbalrog     return E1000_ICR_TXDW;
6587c23b892Sbalrog }
6597c23b892Sbalrog 
660d17161f6SKevin Wolf static uint64_t tx_desc_base(E1000State *s)
661d17161f6SKevin Wolf {
662d17161f6SKevin Wolf     uint64_t bah = s->mac_reg[TDBAH];
663d17161f6SKevin Wolf     uint64_t bal = s->mac_reg[TDBAL] & ~0xf;
664d17161f6SKevin Wolf 
665d17161f6SKevin Wolf     return (bah << 32) + bal;
666d17161f6SKevin Wolf }
667d17161f6SKevin Wolf 
6687c23b892Sbalrog static void
6697c23b892Sbalrog start_xmit(E1000State *s)
6707c23b892Sbalrog {
67162ecbd35SEduard - Gabriel Munteanu     dma_addr_t base;
6727c23b892Sbalrog     struct e1000_tx_desc desc;
6737c23b892Sbalrog     uint32_t tdh_start = s->mac_reg[TDH], cause = E1000_ICS_TXQE;
6747c23b892Sbalrog 
6757c23b892Sbalrog     if (!(s->mac_reg[TCTL] & E1000_TCTL_EN)) {
6767c23b892Sbalrog         DBGOUT(TX, "tx disabled\n");
6777c23b892Sbalrog         return;
6787c23b892Sbalrog     }
6797c23b892Sbalrog 
6807c23b892Sbalrog     while (s->mac_reg[TDH] != s->mac_reg[TDT]) {
681d17161f6SKevin Wolf         base = tx_desc_base(s) +
6827c23b892Sbalrog                sizeof(struct e1000_tx_desc) * s->mac_reg[TDH];
68300c3a05bSDavid Gibson         pci_dma_read(&s->dev, base, &desc, sizeof(desc));
6847c23b892Sbalrog 
6857c23b892Sbalrog         DBGOUT(TX, "index %d: %p : %x %x\n", s->mac_reg[TDH],
6866106075bSths                (void *)(intptr_t)desc.buffer_addr, desc.lower.data,
6877c23b892Sbalrog                desc.upper.data);
6887c23b892Sbalrog 
6897c23b892Sbalrog         process_tx_desc(s, &desc);
69062ecbd35SEduard - Gabriel Munteanu         cause |= txdesc_writeback(s, base, &desc);
6917c23b892Sbalrog 
6927c23b892Sbalrog         if (++s->mac_reg[TDH] * sizeof(desc) >= s->mac_reg[TDLEN])
6937c23b892Sbalrog             s->mac_reg[TDH] = 0;
6947c23b892Sbalrog         /*
6957c23b892Sbalrog          * the following could happen only if guest sw assigns
6967c23b892Sbalrog          * bogus values to TDT/TDLEN.
6977c23b892Sbalrog          * there's nothing too intelligent we could do about this.
6987c23b892Sbalrog          */
6997c23b892Sbalrog         if (s->mac_reg[TDH] == tdh_start) {
7007c23b892Sbalrog             DBGOUT(TXERR, "TDH wraparound @%x, TDT %x, TDLEN %x\n",
7017c23b892Sbalrog                    tdh_start, s->mac_reg[TDT], s->mac_reg[TDLEN]);
7027c23b892Sbalrog             break;
7037c23b892Sbalrog         }
7047c23b892Sbalrog     }
7057c23b892Sbalrog     set_ics(s, 0, cause);
7067c23b892Sbalrog }
7077c23b892Sbalrog 
7087c23b892Sbalrog static int
7097c23b892Sbalrog receive_filter(E1000State *s, const uint8_t *buf, int size)
7107c23b892Sbalrog {
711af2960f9SBlue Swirl     static const uint8_t bcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
712af2960f9SBlue Swirl     static const int mta_shift[] = {4, 3, 2, 0};
7137c23b892Sbalrog     uint32_t f, rctl = s->mac_reg[RCTL], ra[2], *rp;
7147c23b892Sbalrog 
7158f2e8d1fSaliguori     if (is_vlan_packet(s, buf) && vlan_rx_filter_enabled(s)) {
7168f2e8d1fSaliguori         uint16_t vid = be16_to_cpup((uint16_t *)(buf + 14));
7178f2e8d1fSaliguori         uint32_t vfta = le32_to_cpup((uint32_t *)(s->mac_reg + VFTA) +
7188f2e8d1fSaliguori                                      ((vid >> 5) & 0x7f));
7198f2e8d1fSaliguori         if ((vfta & (1 << (vid & 0x1f))) == 0)
7208f2e8d1fSaliguori             return 0;
7218f2e8d1fSaliguori     }
7228f2e8d1fSaliguori 
7237c23b892Sbalrog     if (rctl & E1000_RCTL_UPE)			// promiscuous
7247c23b892Sbalrog         return 1;
7257c23b892Sbalrog 
7267c23b892Sbalrog     if ((buf[0] & 1) && (rctl & E1000_RCTL_MPE))	// promiscuous mcast
7277c23b892Sbalrog         return 1;
7287c23b892Sbalrog 
7297c23b892Sbalrog     if ((rctl & E1000_RCTL_BAM) && !memcmp(buf, bcast, sizeof bcast))
7307c23b892Sbalrog         return 1;
7317c23b892Sbalrog 
7327c23b892Sbalrog     for (rp = s->mac_reg + RA; rp < s->mac_reg + RA + 32; rp += 2) {
7337c23b892Sbalrog         if (!(rp[1] & E1000_RAH_AV))
7347c23b892Sbalrog             continue;
7357c23b892Sbalrog         ra[0] = cpu_to_le32(rp[0]);
7367c23b892Sbalrog         ra[1] = cpu_to_le32(rp[1]);
7377c23b892Sbalrog         if (!memcmp(buf, (uint8_t *)ra, 6)) {
7387c23b892Sbalrog             DBGOUT(RXFILTER,
7397c23b892Sbalrog                    "unicast match[%d]: %02x:%02x:%02x:%02x:%02x:%02x\n",
7407c23b892Sbalrog                    (int)(rp - s->mac_reg - RA)/2,
7417c23b892Sbalrog                    buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);
7427c23b892Sbalrog             return 1;
7437c23b892Sbalrog         }
7447c23b892Sbalrog     }
7457c23b892Sbalrog     DBGOUT(RXFILTER, "unicast mismatch: %02x:%02x:%02x:%02x:%02x:%02x\n",
7467c23b892Sbalrog            buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);
7477c23b892Sbalrog 
7487c23b892Sbalrog     f = mta_shift[(rctl >> E1000_RCTL_MO_SHIFT) & 3];
7497c23b892Sbalrog     f = (((buf[5] << 8) | buf[4]) >> f) & 0xfff;
7507c23b892Sbalrog     if (s->mac_reg[MTA + (f >> 5)] & (1 << (f & 0x1f)))
7517c23b892Sbalrog         return 1;
7527c23b892Sbalrog     DBGOUT(RXFILTER,
7537c23b892Sbalrog            "dropping, inexact filter mismatch: %02x:%02x:%02x:%02x:%02x:%02x MO %d MTA[%d] %x\n",
7547c23b892Sbalrog            buf[0], buf[1], buf[2], buf[3], buf[4], buf[5],
7557c23b892Sbalrog            (rctl >> E1000_RCTL_MO_SHIFT) & 3, f >> 5,
7567c23b892Sbalrog            s->mac_reg[MTA + (f >> 5)]);
7577c23b892Sbalrog 
7587c23b892Sbalrog     return 0;
7597c23b892Sbalrog }
7607c23b892Sbalrog 
76199ed7e30Saliguori static void
7624e68f7a0SStefan Hajnoczi e1000_set_link_status(NetClientState *nc)
76399ed7e30Saliguori {
764cc1f0f45SJason Wang     E1000State *s = qemu_get_nic_opaque(nc);
76599ed7e30Saliguori     uint32_t old_status = s->mac_reg[STATUS];
76699ed7e30Saliguori 
767d4044c2aSBjørn Mork     if (nc->link_down) {
76871aadd3cSJason Wang         e1000_link_down(s);
769d4044c2aSBjørn Mork     } else {
77071aadd3cSJason Wang         e1000_link_up(s);
771d4044c2aSBjørn Mork     }
77299ed7e30Saliguori 
77399ed7e30Saliguori     if (s->mac_reg[STATUS] != old_status)
77499ed7e30Saliguori         set_ics(s, 0, E1000_ICR_LSC);
77599ed7e30Saliguori }
77699ed7e30Saliguori 
777322fd48aSMichael S. Tsirkin static bool e1000_has_rxbufs(E1000State *s, size_t total_size)
778322fd48aSMichael S. Tsirkin {
779322fd48aSMichael S. Tsirkin     int bufs;
780322fd48aSMichael S. Tsirkin     /* Fast-path short packets */
781322fd48aSMichael S. Tsirkin     if (total_size <= s->rxbuf_size) {
782e5b8b0d4SDmitry Fleytman         return s->mac_reg[RDH] != s->mac_reg[RDT];
783322fd48aSMichael S. Tsirkin     }
784322fd48aSMichael S. Tsirkin     if (s->mac_reg[RDH] < s->mac_reg[RDT]) {
785322fd48aSMichael S. Tsirkin         bufs = s->mac_reg[RDT] - s->mac_reg[RDH];
786e5b8b0d4SDmitry Fleytman     } else if (s->mac_reg[RDH] > s->mac_reg[RDT]) {
787322fd48aSMichael S. Tsirkin         bufs = s->mac_reg[RDLEN] /  sizeof(struct e1000_rx_desc) +
788322fd48aSMichael S. Tsirkin             s->mac_reg[RDT] - s->mac_reg[RDH];
789322fd48aSMichael S. Tsirkin     } else {
790322fd48aSMichael S. Tsirkin         return false;
791322fd48aSMichael S. Tsirkin     }
792322fd48aSMichael S. Tsirkin     return total_size <= bufs * s->rxbuf_size;
793322fd48aSMichael S. Tsirkin }
794322fd48aSMichael S. Tsirkin 
7956cdfab28SMichael S. Tsirkin static int
7964e68f7a0SStefan Hajnoczi e1000_can_receive(NetClientState *nc)
7976cdfab28SMichael S. Tsirkin {
798cc1f0f45SJason Wang     E1000State *s = qemu_get_nic_opaque(nc);
7996cdfab28SMichael S. Tsirkin 
800ddcb73b7SMichael S. Tsirkin     return (s->mac_reg[STATUS] & E1000_STATUS_LU) &&
801ddcb73b7SMichael S. Tsirkin         (s->mac_reg[RCTL] & E1000_RCTL_EN) && e1000_has_rxbufs(s, 1);
8026cdfab28SMichael S. Tsirkin }
8036cdfab28SMichael S. Tsirkin 
804d17161f6SKevin Wolf static uint64_t rx_desc_base(E1000State *s)
805d17161f6SKevin Wolf {
806d17161f6SKevin Wolf     uint64_t bah = s->mac_reg[RDBAH];
807d17161f6SKevin Wolf     uint64_t bal = s->mac_reg[RDBAL] & ~0xf;
808d17161f6SKevin Wolf 
809d17161f6SKevin Wolf     return (bah << 32) + bal;
810d17161f6SKevin Wolf }
811d17161f6SKevin Wolf 
8124f1c942bSMark McLoughlin static ssize_t
8134e68f7a0SStefan Hajnoczi e1000_receive(NetClientState *nc, const uint8_t *buf, size_t size)
8147c23b892Sbalrog {
815cc1f0f45SJason Wang     E1000State *s = qemu_get_nic_opaque(nc);
8167c23b892Sbalrog     struct e1000_rx_desc desc;
81762ecbd35SEduard - Gabriel Munteanu     dma_addr_t base;
8187c23b892Sbalrog     unsigned int n, rdt;
8197c23b892Sbalrog     uint32_t rdh_start;
8208f2e8d1fSaliguori     uint16_t vlan_special = 0;
8218f2e8d1fSaliguori     uint8_t vlan_status = 0, vlan_offset = 0;
82278aeb23eSStefan Hajnoczi     uint8_t min_buf[MIN_BUF_SIZE];
823b19487e2SMichael S. Tsirkin     size_t desc_offset;
824b19487e2SMichael S. Tsirkin     size_t desc_size;
825b19487e2SMichael S. Tsirkin     size_t total_size;
8267c23b892Sbalrog 
827ddcb73b7SMichael S. Tsirkin     if (!(s->mac_reg[STATUS] & E1000_STATUS_LU)) {
8284f1c942bSMark McLoughlin         return -1;
829ddcb73b7SMichael S. Tsirkin     }
830ddcb73b7SMichael S. Tsirkin 
831ddcb73b7SMichael S. Tsirkin     if (!(s->mac_reg[RCTL] & E1000_RCTL_EN)) {
832ddcb73b7SMichael S. Tsirkin         return -1;
833ddcb73b7SMichael S. Tsirkin     }
8347c23b892Sbalrog 
83578aeb23eSStefan Hajnoczi     /* Pad to minimum Ethernet frame length */
83678aeb23eSStefan Hajnoczi     if (size < sizeof(min_buf)) {
83778aeb23eSStefan Hajnoczi         memcpy(min_buf, buf, size);
83878aeb23eSStefan Hajnoczi         memset(&min_buf[size], 0, sizeof(min_buf) - size);
83978aeb23eSStefan Hajnoczi         buf = min_buf;
84078aeb23eSStefan Hajnoczi         size = sizeof(min_buf);
84178aeb23eSStefan Hajnoczi     }
84278aeb23eSStefan Hajnoczi 
843b0d9ffcdSMichael Contreras     /* Discard oversized packets if !LPE and !SBP. */
8442c0331f4SMichael Contreras     if ((size > MAXIMUM_ETHERNET_LPE_SIZE ||
8452c0331f4SMichael Contreras         (size > MAXIMUM_ETHERNET_VLAN_SIZE
8462c0331f4SMichael Contreras         && !(s->mac_reg[RCTL] & E1000_RCTL_LPE)))
847b0d9ffcdSMichael Contreras         && !(s->mac_reg[RCTL] & E1000_RCTL_SBP)) {
848b0d9ffcdSMichael Contreras         return size;
849b0d9ffcdSMichael Contreras     }
850b0d9ffcdSMichael Contreras 
8517c23b892Sbalrog     if (!receive_filter(s, buf, size))
8524f1c942bSMark McLoughlin         return size;
8537c23b892Sbalrog 
8548f2e8d1fSaliguori     if (vlan_enabled(s) && is_vlan_packet(s, buf)) {
8558f2e8d1fSaliguori         vlan_special = cpu_to_le16(be16_to_cpup((uint16_t *)(buf + 14)));
85698835fe3SThomas Monjalon         memmove((uint8_t *)buf + 4, buf, 12);
8578f2e8d1fSaliguori         vlan_status = E1000_RXD_STAT_VP;
8588f2e8d1fSaliguori         vlan_offset = 4;
8598f2e8d1fSaliguori         size -= 4;
8608f2e8d1fSaliguori     }
8618f2e8d1fSaliguori 
8627c23b892Sbalrog     rdh_start = s->mac_reg[RDH];
863b19487e2SMichael S. Tsirkin     desc_offset = 0;
864b19487e2SMichael S. Tsirkin     total_size = size + fcs_len(s);
865322fd48aSMichael S. Tsirkin     if (!e1000_has_rxbufs(s, total_size)) {
866322fd48aSMichael S. Tsirkin             set_ics(s, 0, E1000_ICS_RXO);
867322fd48aSMichael S. Tsirkin             return -1;
868322fd48aSMichael S. Tsirkin     }
8697c23b892Sbalrog     do {
870b19487e2SMichael S. Tsirkin         desc_size = total_size - desc_offset;
871b19487e2SMichael S. Tsirkin         if (desc_size > s->rxbuf_size) {
872b19487e2SMichael S. Tsirkin             desc_size = s->rxbuf_size;
873b19487e2SMichael S. Tsirkin         }
874d17161f6SKevin Wolf         base = rx_desc_base(s) + sizeof(desc) * s->mac_reg[RDH];
87500c3a05bSDavid Gibson         pci_dma_read(&s->dev, base, &desc, sizeof(desc));
8768f2e8d1fSaliguori         desc.special = vlan_special;
8778f2e8d1fSaliguori         desc.status |= (vlan_status | E1000_RXD_STAT_DD);
8787c23b892Sbalrog         if (desc.buffer_addr) {
879b19487e2SMichael S. Tsirkin             if (desc_offset < size) {
880b19487e2SMichael S. Tsirkin                 size_t copy_size = size - desc_offset;
881b19487e2SMichael S. Tsirkin                 if (copy_size > s->rxbuf_size) {
882b19487e2SMichael S. Tsirkin                     copy_size = s->rxbuf_size;
883b19487e2SMichael S. Tsirkin                 }
88462ecbd35SEduard - Gabriel Munteanu                 pci_dma_write(&s->dev, le64_to_cpu(desc.buffer_addr),
88500c3a05bSDavid Gibson                               buf + desc_offset + vlan_offset, copy_size);
886b19487e2SMichael S. Tsirkin             }
887b19487e2SMichael S. Tsirkin             desc_offset += desc_size;
888b19487e2SMichael S. Tsirkin             desc.length = cpu_to_le16(desc_size);
889ee912ccfSMichael S. Tsirkin             if (desc_offset >= total_size) {
8907c23b892Sbalrog                 desc.status |= E1000_RXD_STAT_EOP | E1000_RXD_STAT_IXSM;
891b19487e2SMichael S. Tsirkin             } else {
892ee912ccfSMichael S. Tsirkin                 /* Guest zeroing out status is not a hardware requirement.
893ee912ccfSMichael S. Tsirkin                    Clear EOP in case guest didn't do it. */
894ee912ccfSMichael S. Tsirkin                 desc.status &= ~E1000_RXD_STAT_EOP;
895b19487e2SMichael S. Tsirkin             }
89643ad7e3eSJes Sorensen         } else { // as per intel docs; skip descriptors with null buf addr
8977c23b892Sbalrog             DBGOUT(RX, "Null RX descriptor!!\n");
89843ad7e3eSJes Sorensen         }
89900c3a05bSDavid Gibson         pci_dma_write(&s->dev, base, &desc, sizeof(desc));
9007c23b892Sbalrog 
9017c23b892Sbalrog         if (++s->mac_reg[RDH] * sizeof(desc) >= s->mac_reg[RDLEN])
9027c23b892Sbalrog             s->mac_reg[RDH] = 0;
9037c23b892Sbalrog         /* see comment in start_xmit; same here */
9047c23b892Sbalrog         if (s->mac_reg[RDH] == rdh_start) {
9057c23b892Sbalrog             DBGOUT(RXERR, "RDH wraparound @%x, RDT %x, RDLEN %x\n",
9067c23b892Sbalrog                    rdh_start, s->mac_reg[RDT], s->mac_reg[RDLEN]);
9077c23b892Sbalrog             set_ics(s, 0, E1000_ICS_RXO);
9084f1c942bSMark McLoughlin             return -1;
9097c23b892Sbalrog         }
910b19487e2SMichael S. Tsirkin     } while (desc_offset < total_size);
9117c23b892Sbalrog 
9127c23b892Sbalrog     s->mac_reg[GPRC]++;
9137c23b892Sbalrog     s->mac_reg[TPR]++;
914a05e8a6eSMichael S. Tsirkin     /* TOR - Total Octets Received:
915a05e8a6eSMichael S. Tsirkin      * This register includes bytes received in a packet from the <Destination
916a05e8a6eSMichael S. Tsirkin      * Address> field through the <CRC> field, inclusively.
917a05e8a6eSMichael S. Tsirkin      */
918a05e8a6eSMichael S. Tsirkin     n = s->mac_reg[TORL] + size + /* Always include FCS length. */ 4;
919a05e8a6eSMichael S. Tsirkin     if (n < s->mac_reg[TORL])
9207c23b892Sbalrog         s->mac_reg[TORH]++;
921a05e8a6eSMichael S. Tsirkin     s->mac_reg[TORL] = n;
9227c23b892Sbalrog 
9237c23b892Sbalrog     n = E1000_ICS_RXT0;
9247c23b892Sbalrog     if ((rdt = s->mac_reg[RDT]) < s->mac_reg[RDH])
9257c23b892Sbalrog         rdt += s->mac_reg[RDLEN] / sizeof(desc);
926bf16cc8fSaliguori     if (((rdt - s->mac_reg[RDH]) * sizeof(desc)) <= s->mac_reg[RDLEN] >>
927bf16cc8fSaliguori         s->rxbuf_min_shift)
9287c23b892Sbalrog         n |= E1000_ICS_RXDMT0;
9297c23b892Sbalrog 
9307c23b892Sbalrog     set_ics(s, 0, n);
9314f1c942bSMark McLoughlin 
9324f1c942bSMark McLoughlin     return size;
9337c23b892Sbalrog }
9347c23b892Sbalrog 
9357c23b892Sbalrog static uint32_t
9367c23b892Sbalrog mac_readreg(E1000State *s, int index)
9377c23b892Sbalrog {
9387c23b892Sbalrog     return s->mac_reg[index];
9397c23b892Sbalrog }
9407c23b892Sbalrog 
9417c23b892Sbalrog static uint32_t
9427c23b892Sbalrog mac_icr_read(E1000State *s, int index)
9437c23b892Sbalrog {
9447c23b892Sbalrog     uint32_t ret = s->mac_reg[ICR];
9457c23b892Sbalrog 
9467c23b892Sbalrog     DBGOUT(INTERRUPT, "ICR read: %x\n", ret);
9477c23b892Sbalrog     set_interrupt_cause(s, 0, 0);
9487c23b892Sbalrog     return ret;
9497c23b892Sbalrog }
9507c23b892Sbalrog 
9517c23b892Sbalrog static uint32_t
9527c23b892Sbalrog mac_read_clr4(E1000State *s, int index)
9537c23b892Sbalrog {
9547c23b892Sbalrog     uint32_t ret = s->mac_reg[index];
9557c23b892Sbalrog 
9567c23b892Sbalrog     s->mac_reg[index] = 0;
9577c23b892Sbalrog     return ret;
9587c23b892Sbalrog }
9597c23b892Sbalrog 
9607c23b892Sbalrog static uint32_t
9617c23b892Sbalrog mac_read_clr8(E1000State *s, int index)
9627c23b892Sbalrog {
9637c23b892Sbalrog     uint32_t ret = s->mac_reg[index];
9647c23b892Sbalrog 
9657c23b892Sbalrog     s->mac_reg[index] = 0;
9667c23b892Sbalrog     s->mac_reg[index-1] = 0;
9677c23b892Sbalrog     return ret;
9687c23b892Sbalrog }
9697c23b892Sbalrog 
9707c23b892Sbalrog static void
9717c23b892Sbalrog mac_writereg(E1000State *s, int index, uint32_t val)
9727c23b892Sbalrog {
9737c23b892Sbalrog     s->mac_reg[index] = val;
9747c23b892Sbalrog }
9757c23b892Sbalrog 
9767c23b892Sbalrog static void
9777c23b892Sbalrog set_rdt(E1000State *s, int index, uint32_t val)
9787c23b892Sbalrog {
9797c23b892Sbalrog     s->mac_reg[index] = val & 0xffff;
980e8b4c680SPaolo Bonzini     if (e1000_has_rxbufs(s, 1)) {
981b356f76dSJason Wang         qemu_flush_queued_packets(qemu_get_queue(s->nic));
982e8b4c680SPaolo Bonzini     }
9837c23b892Sbalrog }
9847c23b892Sbalrog 
9857c23b892Sbalrog static void
9867c23b892Sbalrog set_16bit(E1000State *s, int index, uint32_t val)
9877c23b892Sbalrog {
9887c23b892Sbalrog     s->mac_reg[index] = val & 0xffff;
9897c23b892Sbalrog }
9907c23b892Sbalrog 
9917c23b892Sbalrog static void
9927c23b892Sbalrog set_dlen(E1000State *s, int index, uint32_t val)
9937c23b892Sbalrog {
9947c23b892Sbalrog     s->mac_reg[index] = val & 0xfff80;
9957c23b892Sbalrog }
9967c23b892Sbalrog 
9977c23b892Sbalrog static void
9987c23b892Sbalrog set_tctl(E1000State *s, int index, uint32_t val)
9997c23b892Sbalrog {
10007c23b892Sbalrog     s->mac_reg[index] = val;
10017c23b892Sbalrog     s->mac_reg[TDT] &= 0xffff;
10027c23b892Sbalrog     start_xmit(s);
10037c23b892Sbalrog }
10047c23b892Sbalrog 
10057c23b892Sbalrog static void
10067c23b892Sbalrog set_icr(E1000State *s, int index, uint32_t val)
10077c23b892Sbalrog {
10087c23b892Sbalrog     DBGOUT(INTERRUPT, "set_icr %x\n", val);
10097c23b892Sbalrog     set_interrupt_cause(s, 0, s->mac_reg[ICR] & ~val);
10107c23b892Sbalrog }
10117c23b892Sbalrog 
10127c23b892Sbalrog static void
10137c23b892Sbalrog set_imc(E1000State *s, int index, uint32_t val)
10147c23b892Sbalrog {
10157c23b892Sbalrog     s->mac_reg[IMS] &= ~val;
10167c23b892Sbalrog     set_ics(s, 0, 0);
10177c23b892Sbalrog }
10187c23b892Sbalrog 
10197c23b892Sbalrog static void
10207c23b892Sbalrog set_ims(E1000State *s, int index, uint32_t val)
10217c23b892Sbalrog {
10227c23b892Sbalrog     s->mac_reg[IMS] |= val;
10237c23b892Sbalrog     set_ics(s, 0, 0);
10247c23b892Sbalrog }
10257c23b892Sbalrog 
10267c23b892Sbalrog #define getreg(x)	[x] = mac_readreg
10277c23b892Sbalrog static uint32_t (*macreg_readops[])(E1000State *, int) = {
10287c23b892Sbalrog     getreg(PBA),	getreg(RCTL),	getreg(TDH),	getreg(TXDCTL),
10297c23b892Sbalrog     getreg(WUFC),	getreg(TDT),	getreg(CTRL),	getreg(LEDCTL),
10307c23b892Sbalrog     getreg(MANC),	getreg(MDIC),	getreg(SWSM),	getreg(STATUS),
10317c23b892Sbalrog     getreg(TORL),	getreg(TOTL),	getreg(IMS),	getreg(TCTL),
1032b1332393SBill Paul     getreg(RDH),	getreg(RDT),	getreg(VET),	getreg(ICS),
1033a00b2335SKay Ackermann     getreg(TDBAL),	getreg(TDBAH),	getreg(RDBAH),	getreg(RDBAL),
1034a00b2335SKay Ackermann     getreg(TDLEN),	getreg(RDLEN),
10357c23b892Sbalrog 
10367c23b892Sbalrog     [TOTH] = mac_read_clr8,	[TORH] = mac_read_clr8,	[GPRC] = mac_read_clr4,
10377c23b892Sbalrog     [GPTC] = mac_read_clr4,	[TPR] = mac_read_clr4,	[TPT] = mac_read_clr4,
10387c23b892Sbalrog     [ICR] = mac_icr_read,	[EECD] = get_eecd,	[EERD] = flash_eerd_read,
10397c23b892Sbalrog     [CRCERRS ... MPC] = &mac_readreg,
10407c23b892Sbalrog     [RA ... RA+31] = &mac_readreg,
10417c23b892Sbalrog     [MTA ... MTA+127] = &mac_readreg,
10428f2e8d1fSaliguori     [VFTA ... VFTA+127] = &mac_readreg,
10437c23b892Sbalrog };
1044b1503cdaSmalc enum { NREADOPS = ARRAY_SIZE(macreg_readops) };
10457c23b892Sbalrog 
10467c23b892Sbalrog #define putreg(x)	[x] = mac_writereg
10477c23b892Sbalrog static void (*macreg_writeops[])(E1000State *, int, uint32_t) = {
10487c23b892Sbalrog     putreg(PBA),	putreg(EERD),	putreg(SWSM),	putreg(WUFC),
10497c23b892Sbalrog     putreg(TDBAL),	putreg(TDBAH),	putreg(TXDCTL),	putreg(RDBAH),
1050cab3c825SKevin Wolf     putreg(RDBAL),	putreg(LEDCTL), putreg(VET),
10517c23b892Sbalrog     [TDLEN] = set_dlen,	[RDLEN] = set_dlen,	[TCTL] = set_tctl,
10527c23b892Sbalrog     [TDT] = set_tctl,	[MDIC] = set_mdic,	[ICS] = set_ics,
10537c23b892Sbalrog     [TDH] = set_16bit,	[RDH] = set_16bit,	[RDT] = set_rdt,
10547c23b892Sbalrog     [IMC] = set_imc,	[IMS] = set_ims,	[ICR] = set_icr,
1055cab3c825SKevin Wolf     [EECD] = set_eecd,	[RCTL] = set_rx_control, [CTRL] = set_ctrl,
10567c23b892Sbalrog     [RA ... RA+31] = &mac_writereg,
10577c23b892Sbalrog     [MTA ... MTA+127] = &mac_writereg,
10588f2e8d1fSaliguori     [VFTA ... VFTA+127] = &mac_writereg,
10597c23b892Sbalrog };
1060b9d03e35SJason Wang 
1061b1503cdaSmalc enum { NWRITEOPS = ARRAY_SIZE(macreg_writeops) };
10627c23b892Sbalrog 
10637c23b892Sbalrog static void
1064a8170e5eSAvi Kivity e1000_mmio_write(void *opaque, hwaddr addr, uint64_t val,
1065ad00a9b9SAvi Kivity                  unsigned size)
10667c23b892Sbalrog {
10677c23b892Sbalrog     E1000State *s = opaque;
10688da3ff18Spbrook     unsigned int index = (addr & 0x1ffff) >> 2;
10697c23b892Sbalrog 
107043ad7e3eSJes Sorensen     if (index < NWRITEOPS && macreg_writeops[index]) {
10716b59fc74Saurel32         macreg_writeops[index](s, index, val);
107243ad7e3eSJes Sorensen     } else if (index < NREADOPS && macreg_readops[index]) {
1073ad00a9b9SAvi Kivity         DBGOUT(MMIO, "e1000_mmio_writel RO %x: 0x%04"PRIx64"\n", index<<2, val);
107443ad7e3eSJes Sorensen     } else {
1075ad00a9b9SAvi Kivity         DBGOUT(UNKNOWN, "MMIO unknown write addr=0x%08x,val=0x%08"PRIx64"\n",
10767c23b892Sbalrog                index<<2, val);
10777c23b892Sbalrog     }
107843ad7e3eSJes Sorensen }
10797c23b892Sbalrog 
1080ad00a9b9SAvi Kivity static uint64_t
1081a8170e5eSAvi Kivity e1000_mmio_read(void *opaque, hwaddr addr, unsigned size)
10827c23b892Sbalrog {
10837c23b892Sbalrog     E1000State *s = opaque;
10848da3ff18Spbrook     unsigned int index = (addr & 0x1ffff) >> 2;
10857c23b892Sbalrog 
10867c23b892Sbalrog     if (index < NREADOPS && macreg_readops[index])
10876b59fc74Saurel32     {
108832600a30SAlexander Graf         return macreg_readops[index](s, index);
10896b59fc74Saurel32     }
10907c23b892Sbalrog     DBGOUT(UNKNOWN, "MMIO unknown read addr=0x%08x\n", index<<2);
10917c23b892Sbalrog     return 0;
10927c23b892Sbalrog }
10937c23b892Sbalrog 
1094ad00a9b9SAvi Kivity static const MemoryRegionOps e1000_mmio_ops = {
1095ad00a9b9SAvi Kivity     .read = e1000_mmio_read,
1096ad00a9b9SAvi Kivity     .write = e1000_mmio_write,
1097ad00a9b9SAvi Kivity     .endianness = DEVICE_LITTLE_ENDIAN,
1098ad00a9b9SAvi Kivity     .impl = {
1099ad00a9b9SAvi Kivity         .min_access_size = 4,
1100ad00a9b9SAvi Kivity         .max_access_size = 4,
1101ad00a9b9SAvi Kivity     },
1102ad00a9b9SAvi Kivity };
1103ad00a9b9SAvi Kivity 
1104a8170e5eSAvi Kivity static uint64_t e1000_io_read(void *opaque, hwaddr addr,
1105ad00a9b9SAvi Kivity                               unsigned size)
11067c23b892Sbalrog {
1107ad00a9b9SAvi Kivity     E1000State *s = opaque;
1108ad00a9b9SAvi Kivity 
1109ad00a9b9SAvi Kivity     (void)s;
1110ad00a9b9SAvi Kivity     return 0;
11117c23b892Sbalrog }
11127c23b892Sbalrog 
1113a8170e5eSAvi Kivity static void e1000_io_write(void *opaque, hwaddr addr,
1114ad00a9b9SAvi Kivity                            uint64_t val, unsigned size)
11157c23b892Sbalrog {
1116ad00a9b9SAvi Kivity     E1000State *s = opaque;
1117ad00a9b9SAvi Kivity 
1118ad00a9b9SAvi Kivity     (void)s;
11197c23b892Sbalrog }
11207c23b892Sbalrog 
1121ad00a9b9SAvi Kivity static const MemoryRegionOps e1000_io_ops = {
1122ad00a9b9SAvi Kivity     .read = e1000_io_read,
1123ad00a9b9SAvi Kivity     .write = e1000_io_write,
1124ad00a9b9SAvi Kivity     .endianness = DEVICE_LITTLE_ENDIAN,
1125ad00a9b9SAvi Kivity };
1126ad00a9b9SAvi Kivity 
1127e482dc3eSJuan Quintela static bool is_version_1(void *opaque, int version_id)
11287c23b892Sbalrog {
1129e482dc3eSJuan Quintela     return version_id == 1;
11307c23b892Sbalrog }
11317c23b892Sbalrog 
1132ddcb73b7SMichael S. Tsirkin static void e1000_pre_save(void *opaque)
1133ddcb73b7SMichael S. Tsirkin {
1134ddcb73b7SMichael S. Tsirkin     E1000State *s = opaque;
1135ddcb73b7SMichael S. Tsirkin     NetClientState *nc = qemu_get_queue(s->nic);
11362af234e6SMichael S. Tsirkin 
11372af234e6SMichael S. Tsirkin     if (!(s->compat_flags & E1000_FLAG_AUTONEG)) {
11382af234e6SMichael S. Tsirkin         return;
11392af234e6SMichael S. Tsirkin     }
11402af234e6SMichael S. Tsirkin 
1141ddcb73b7SMichael S. Tsirkin     /*
1142ddcb73b7SMichael S. Tsirkin      * If link is down and auto-negotiation is ongoing, complete
1143ddcb73b7SMichael S. Tsirkin      * auto-negotiation immediately.  This allows is to look at
1144ddcb73b7SMichael S. Tsirkin      * MII_SR_AUTONEG_COMPLETE to infer link status on load.
1145ddcb73b7SMichael S. Tsirkin      */
1146ddcb73b7SMichael S. Tsirkin     if (nc->link_down &&
1147ddcb73b7SMichael S. Tsirkin         s->phy_reg[PHY_CTRL] & MII_CR_AUTO_NEG_EN &&
1148ddcb73b7SMichael S. Tsirkin         s->phy_reg[PHY_CTRL] & MII_CR_RESTART_AUTO_NEG) {
1149ddcb73b7SMichael S. Tsirkin          s->phy_reg[PHY_STATUS] |= MII_SR_AUTONEG_COMPLETE;
1150ddcb73b7SMichael S. Tsirkin     }
1151ddcb73b7SMichael S. Tsirkin }
1152ddcb73b7SMichael S. Tsirkin 
1153e4b82364SAmos Kong static int e1000_post_load(void *opaque, int version_id)
1154e4b82364SAmos Kong {
1155e4b82364SAmos Kong     E1000State *s = opaque;
1156b356f76dSJason Wang     NetClientState *nc = qemu_get_queue(s->nic);
1157e4b82364SAmos Kong 
1158e4b82364SAmos Kong     /* nc.link_down can't be migrated, so infer link_down according
1159ddcb73b7SMichael S. Tsirkin      * to link status bit in mac_reg[STATUS].
1160ddcb73b7SMichael S. Tsirkin      * Alternatively, restart link negotiation if it was in progress. */
1161b356f76dSJason Wang     nc->link_down = (s->mac_reg[STATUS] & E1000_STATUS_LU) == 0;
11622af234e6SMichael S. Tsirkin 
11632af234e6SMichael S. Tsirkin     if (!(s->compat_flags & E1000_FLAG_AUTONEG)) {
11642af234e6SMichael S. Tsirkin         return 0;
11652af234e6SMichael S. Tsirkin     }
11662af234e6SMichael S. Tsirkin 
1167ddcb73b7SMichael S. Tsirkin     if (s->phy_reg[PHY_CTRL] & MII_CR_AUTO_NEG_EN &&
1168ddcb73b7SMichael S. Tsirkin         s->phy_reg[PHY_CTRL] & MII_CR_RESTART_AUTO_NEG &&
1169ddcb73b7SMichael S. Tsirkin         !(s->phy_reg[PHY_STATUS] & MII_SR_AUTONEG_COMPLETE)) {
1170ddcb73b7SMichael S. Tsirkin         nc->link_down = false;
1171ddcb73b7SMichael S. Tsirkin         qemu_mod_timer(s->autoneg_timer, qemu_get_clock_ms(vm_clock) + 500);
1172ddcb73b7SMichael S. Tsirkin     }
1173e4b82364SAmos Kong 
1174e4b82364SAmos Kong     return 0;
1175e4b82364SAmos Kong }
1176e4b82364SAmos Kong 
1177e482dc3eSJuan Quintela static const VMStateDescription vmstate_e1000 = {
1178e482dc3eSJuan Quintela     .name = "e1000",
1179e482dc3eSJuan Quintela     .version_id = 2,
1180e482dc3eSJuan Quintela     .minimum_version_id = 1,
1181e482dc3eSJuan Quintela     .minimum_version_id_old = 1,
1182ddcb73b7SMichael S. Tsirkin     .pre_save = e1000_pre_save,
1183e4b82364SAmos Kong     .post_load = e1000_post_load,
1184e482dc3eSJuan Quintela     .fields      = (VMStateField []) {
1185e482dc3eSJuan Quintela         VMSTATE_PCI_DEVICE(dev, E1000State),
1186e482dc3eSJuan Quintela         VMSTATE_UNUSED_TEST(is_version_1, 4), /* was instance id */
1187e482dc3eSJuan Quintela         VMSTATE_UNUSED(4), /* Was mmio_base.  */
1188e482dc3eSJuan Quintela         VMSTATE_UINT32(rxbuf_size, E1000State),
1189e482dc3eSJuan Quintela         VMSTATE_UINT32(rxbuf_min_shift, E1000State),
1190e482dc3eSJuan Quintela         VMSTATE_UINT32(eecd_state.val_in, E1000State),
1191e482dc3eSJuan Quintela         VMSTATE_UINT16(eecd_state.bitnum_in, E1000State),
1192e482dc3eSJuan Quintela         VMSTATE_UINT16(eecd_state.bitnum_out, E1000State),
1193e482dc3eSJuan Quintela         VMSTATE_UINT16(eecd_state.reading, E1000State),
1194e482dc3eSJuan Quintela         VMSTATE_UINT32(eecd_state.old_eecd, E1000State),
1195e482dc3eSJuan Quintela         VMSTATE_UINT8(tx.ipcss, E1000State),
1196e482dc3eSJuan Quintela         VMSTATE_UINT8(tx.ipcso, E1000State),
1197e482dc3eSJuan Quintela         VMSTATE_UINT16(tx.ipcse, E1000State),
1198e482dc3eSJuan Quintela         VMSTATE_UINT8(tx.tucss, E1000State),
1199e482dc3eSJuan Quintela         VMSTATE_UINT8(tx.tucso, E1000State),
1200e482dc3eSJuan Quintela         VMSTATE_UINT16(tx.tucse, E1000State),
1201e482dc3eSJuan Quintela         VMSTATE_UINT32(tx.paylen, E1000State),
1202e482dc3eSJuan Quintela         VMSTATE_UINT8(tx.hdr_len, E1000State),
1203e482dc3eSJuan Quintela         VMSTATE_UINT16(tx.mss, E1000State),
1204e482dc3eSJuan Quintela         VMSTATE_UINT16(tx.size, E1000State),
1205e482dc3eSJuan Quintela         VMSTATE_UINT16(tx.tso_frames, E1000State),
1206e482dc3eSJuan Quintela         VMSTATE_UINT8(tx.sum_needed, E1000State),
1207e482dc3eSJuan Quintela         VMSTATE_INT8(tx.ip, E1000State),
1208e482dc3eSJuan Quintela         VMSTATE_INT8(tx.tcp, E1000State),
1209e482dc3eSJuan Quintela         VMSTATE_BUFFER(tx.header, E1000State),
1210e482dc3eSJuan Quintela         VMSTATE_BUFFER(tx.data, E1000State),
1211e482dc3eSJuan Quintela         VMSTATE_UINT16_ARRAY(eeprom_data, E1000State, 64),
1212e482dc3eSJuan Quintela         VMSTATE_UINT16_ARRAY(phy_reg, E1000State, 0x20),
1213e482dc3eSJuan Quintela         VMSTATE_UINT32(mac_reg[CTRL], E1000State),
1214e482dc3eSJuan Quintela         VMSTATE_UINT32(mac_reg[EECD], E1000State),
1215e482dc3eSJuan Quintela         VMSTATE_UINT32(mac_reg[EERD], E1000State),
1216e482dc3eSJuan Quintela         VMSTATE_UINT32(mac_reg[GPRC], E1000State),
1217e482dc3eSJuan Quintela         VMSTATE_UINT32(mac_reg[GPTC], E1000State),
1218e482dc3eSJuan Quintela         VMSTATE_UINT32(mac_reg[ICR], E1000State),
1219e482dc3eSJuan Quintela         VMSTATE_UINT32(mac_reg[ICS], E1000State),
1220e482dc3eSJuan Quintela         VMSTATE_UINT32(mac_reg[IMC], E1000State),
1221e482dc3eSJuan Quintela         VMSTATE_UINT32(mac_reg[IMS], E1000State),
1222e482dc3eSJuan Quintela         VMSTATE_UINT32(mac_reg[LEDCTL], E1000State),
1223e482dc3eSJuan Quintela         VMSTATE_UINT32(mac_reg[MANC], E1000State),
1224e482dc3eSJuan Quintela         VMSTATE_UINT32(mac_reg[MDIC], E1000State),
1225e482dc3eSJuan Quintela         VMSTATE_UINT32(mac_reg[MPC], E1000State),
1226e482dc3eSJuan Quintela         VMSTATE_UINT32(mac_reg[PBA], E1000State),
1227e482dc3eSJuan Quintela         VMSTATE_UINT32(mac_reg[RCTL], E1000State),
1228e482dc3eSJuan Quintela         VMSTATE_UINT32(mac_reg[RDBAH], E1000State),
1229e482dc3eSJuan Quintela         VMSTATE_UINT32(mac_reg[RDBAL], E1000State),
1230e482dc3eSJuan Quintela         VMSTATE_UINT32(mac_reg[RDH], E1000State),
1231e482dc3eSJuan Quintela         VMSTATE_UINT32(mac_reg[RDLEN], E1000State),
1232e482dc3eSJuan Quintela         VMSTATE_UINT32(mac_reg[RDT], E1000State),
1233e482dc3eSJuan Quintela         VMSTATE_UINT32(mac_reg[STATUS], E1000State),
1234e482dc3eSJuan Quintela         VMSTATE_UINT32(mac_reg[SWSM], E1000State),
1235e482dc3eSJuan Quintela         VMSTATE_UINT32(mac_reg[TCTL], E1000State),
1236e482dc3eSJuan Quintela         VMSTATE_UINT32(mac_reg[TDBAH], E1000State),
1237e482dc3eSJuan Quintela         VMSTATE_UINT32(mac_reg[TDBAL], E1000State),
1238e482dc3eSJuan Quintela         VMSTATE_UINT32(mac_reg[TDH], E1000State),
1239e482dc3eSJuan Quintela         VMSTATE_UINT32(mac_reg[TDLEN], E1000State),
1240e482dc3eSJuan Quintela         VMSTATE_UINT32(mac_reg[TDT], E1000State),
1241e482dc3eSJuan Quintela         VMSTATE_UINT32(mac_reg[TORH], E1000State),
1242e482dc3eSJuan Quintela         VMSTATE_UINT32(mac_reg[TORL], E1000State),
1243e482dc3eSJuan Quintela         VMSTATE_UINT32(mac_reg[TOTH], E1000State),
1244e482dc3eSJuan Quintela         VMSTATE_UINT32(mac_reg[TOTL], E1000State),
1245e482dc3eSJuan Quintela         VMSTATE_UINT32(mac_reg[TPR], E1000State),
1246e482dc3eSJuan Quintela         VMSTATE_UINT32(mac_reg[TPT], E1000State),
1247e482dc3eSJuan Quintela         VMSTATE_UINT32(mac_reg[TXDCTL], E1000State),
1248e482dc3eSJuan Quintela         VMSTATE_UINT32(mac_reg[WUFC], E1000State),
1249e482dc3eSJuan Quintela         VMSTATE_UINT32(mac_reg[VET], E1000State),
1250e482dc3eSJuan Quintela         VMSTATE_UINT32_SUB_ARRAY(mac_reg, E1000State, RA, 32),
1251e482dc3eSJuan Quintela         VMSTATE_UINT32_SUB_ARRAY(mac_reg, E1000State, MTA, 128),
1252e482dc3eSJuan Quintela         VMSTATE_UINT32_SUB_ARRAY(mac_reg, E1000State, VFTA, 128),
1253e482dc3eSJuan Quintela         VMSTATE_END_OF_LIST()
12547c23b892Sbalrog     }
1255e482dc3eSJuan Quintela };
12567c23b892Sbalrog 
125788b4e9dbSblueswir1 static const uint16_t e1000_eeprom_template[64] = {
12587c23b892Sbalrog     0x0000, 0x0000, 0x0000, 0x0000,      0xffff, 0x0000,      0x0000, 0x0000,
12597c23b892Sbalrog     0x3000, 0x1000, 0x6403, E1000_DEVID, 0x8086, E1000_DEVID, 0x8086, 0x3040,
12607c23b892Sbalrog     0x0008, 0x2000, 0x7e14, 0x0048,      0x1000, 0x00d8,      0x0000, 0x2700,
12617c23b892Sbalrog     0x6cc9, 0x3150, 0x0722, 0x040b,      0x0984, 0x0000,      0xc000, 0x0706,
12627c23b892Sbalrog     0x1008, 0x0000, 0x0f04, 0x7fff,      0x4d01, 0xffff,      0xffff, 0xffff,
12637c23b892Sbalrog     0xffff, 0xffff, 0xffff, 0xffff,      0xffff, 0xffff,      0xffff, 0xffff,
12647c23b892Sbalrog     0x0100, 0x4000, 0x121c, 0xffff,      0xffff, 0xffff,      0xffff, 0xffff,
12657c23b892Sbalrog     0xffff, 0xffff, 0xffff, 0xffff,      0xffff, 0xffff,      0xffff, 0x0000,
12667c23b892Sbalrog };
12677c23b892Sbalrog 
12687c23b892Sbalrog /* PCI interface */
12697c23b892Sbalrog 
12707c23b892Sbalrog static void
1271ad00a9b9SAvi Kivity e1000_mmio_setup(E1000State *d)
12727c23b892Sbalrog {
1273f65ed4c1Saliguori     int i;
1274f65ed4c1Saliguori     const uint32_t excluded_regs[] = {
1275f65ed4c1Saliguori         E1000_MDIC, E1000_ICR, E1000_ICS, E1000_IMS,
1276f65ed4c1Saliguori         E1000_IMC, E1000_TCTL, E1000_TDT, PNPMMIO_SIZE
1277f65ed4c1Saliguori     };
1278f65ed4c1Saliguori 
1279*eedfac6fSPaolo Bonzini     memory_region_init_io(&d->mmio, OBJECT(d), &e1000_mmio_ops, d,
1280*eedfac6fSPaolo Bonzini                           "e1000-mmio", PNPMMIO_SIZE);
1281ad00a9b9SAvi Kivity     memory_region_add_coalescing(&d->mmio, 0, excluded_regs[0]);
1282f65ed4c1Saliguori     for (i = 0; excluded_regs[i] != PNPMMIO_SIZE; i++)
1283ad00a9b9SAvi Kivity         memory_region_add_coalescing(&d->mmio, excluded_regs[i] + 4,
1284ad00a9b9SAvi Kivity                                      excluded_regs[i+1] - excluded_regs[i] - 4);
1285*eedfac6fSPaolo Bonzini     memory_region_init_io(&d->io, OBJECT(d), &e1000_io_ops, d, "e1000-io", IOPORT_SIZE);
12867c23b892Sbalrog }
12877c23b892Sbalrog 
1288b946a153Saliguori static void
12894e68f7a0SStefan Hajnoczi e1000_cleanup(NetClientState *nc)
1290b946a153Saliguori {
1291cc1f0f45SJason Wang     E1000State *s = qemu_get_nic_opaque(nc);
1292b946a153Saliguori 
1293a03e2aecSMark McLoughlin     s->nic = NULL;
1294b946a153Saliguori }
1295b946a153Saliguori 
1296f90c2bcdSAlex Williamson static void
12974b09be85Saliguori pci_e1000_uninit(PCIDevice *dev)
12984b09be85Saliguori {
12997d9e52bdSJuan Quintela     E1000State *d = DO_UPCAST(E1000State, dev, dev);
13004b09be85Saliguori 
1301b9d03e35SJason Wang     qemu_del_timer(d->autoneg_timer);
1302b9d03e35SJason Wang     qemu_free_timer(d->autoneg_timer);
1303ad00a9b9SAvi Kivity     memory_region_destroy(&d->mmio);
1304ad00a9b9SAvi Kivity     memory_region_destroy(&d->io);
1305948ecf21SJason Wang     qemu_del_nic(d->nic);
13064b09be85Saliguori }
13074b09be85Saliguori 
1308a03e2aecSMark McLoughlin static NetClientInfo net_e1000_info = {
13092be64a68SLaszlo Ersek     .type = NET_CLIENT_OPTIONS_KIND_NIC,
1310a03e2aecSMark McLoughlin     .size = sizeof(NICState),
1311a03e2aecSMark McLoughlin     .can_receive = e1000_can_receive,
1312a03e2aecSMark McLoughlin     .receive = e1000_receive,
1313a03e2aecSMark McLoughlin     .cleanup = e1000_cleanup,
1314a03e2aecSMark McLoughlin     .link_status_changed = e1000_set_link_status,
1315a03e2aecSMark McLoughlin };
1316a03e2aecSMark McLoughlin 
131781a322d4SGerd Hoffmann static int pci_e1000_init(PCIDevice *pci_dev)
13187c23b892Sbalrog {
13197d9e52bdSJuan Quintela     E1000State *d = DO_UPCAST(E1000State, dev, pci_dev);
13207c23b892Sbalrog     uint8_t *pci_conf;
13217c23b892Sbalrog     uint16_t checksum = 0;
13227c23b892Sbalrog     int i;
1323fbdaa002SGerd Hoffmann     uint8_t *macaddr;
1324aff427a1SChris Wright 
13257c23b892Sbalrog     pci_conf = d->dev.config;
13267c23b892Sbalrog 
1327a9cbacb0SMichael S. Tsirkin     /* TODO: RST# value should be 0, PCI spec 6.2.4 */
1328a9cbacb0SMichael S. Tsirkin     pci_conf[PCI_CACHE_LINE_SIZE] = 0x10;
13297c23b892Sbalrog 
1330817e0b6fSMichael S. Tsirkin     pci_conf[PCI_INTERRUPT_PIN] = 1; /* interrupt pin A */
13317c23b892Sbalrog 
1332ad00a9b9SAvi Kivity     e1000_mmio_setup(d);
13337c23b892Sbalrog 
1334e824b2ccSAvi Kivity     pci_register_bar(&d->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &d->mmio);
13357c23b892Sbalrog 
1336e824b2ccSAvi Kivity     pci_register_bar(&d->dev, 1, PCI_BASE_ADDRESS_SPACE_IO, &d->io);
13377c23b892Sbalrog 
13387c23b892Sbalrog     memmove(d->eeprom_data, e1000_eeprom_template,
13397c23b892Sbalrog         sizeof e1000_eeprom_template);
1340fbdaa002SGerd Hoffmann     qemu_macaddr_default_if_unset(&d->conf.macaddr);
1341fbdaa002SGerd Hoffmann     macaddr = d->conf.macaddr.a;
13427c23b892Sbalrog     for (i = 0; i < 3; i++)
13439d07d757SPaul Brook         d->eeprom_data[i] = (macaddr[2*i+1]<<8) | macaddr[2*i];
13447c23b892Sbalrog     for (i = 0; i < EEPROM_CHECKSUM_REG; i++)
13457c23b892Sbalrog         checksum += d->eeprom_data[i];
13467c23b892Sbalrog     checksum = (uint16_t) EEPROM_SUM - checksum;
13477c23b892Sbalrog     d->eeprom_data[EEPROM_CHECKSUM_REG] = checksum;
13487c23b892Sbalrog 
1349a03e2aecSMark McLoughlin     d->nic = qemu_new_nic(&net_e1000_info, &d->conf,
1350f79f2bfcSAnthony Liguori                           object_get_typename(OBJECT(d)), d->dev.qdev.id, d);
13517c23b892Sbalrog 
1352b356f76dSJason Wang     qemu_format_nic_info_str(qemu_get_queue(d->nic), macaddr);
13531ca4d09aSGleb Natapov 
13541ca4d09aSGleb Natapov     add_boot_device_path(d->conf.bootindex, &pci_dev->qdev, "/ethernet-phy@0");
13551ca4d09aSGleb Natapov 
1356b9d03e35SJason Wang     d->autoneg_timer = qemu_new_timer_ms(vm_clock, e1000_autoneg_timer, d);
1357b9d03e35SJason Wang 
135881a322d4SGerd Hoffmann     return 0;
13597c23b892Sbalrog }
13609d07d757SPaul Brook 
1361fbdaa002SGerd Hoffmann static void qdev_e1000_reset(DeviceState *dev)
1362fbdaa002SGerd Hoffmann {
1363fbdaa002SGerd Hoffmann     E1000State *d = DO_UPCAST(E1000State, dev.qdev, dev);
1364fbdaa002SGerd Hoffmann     e1000_reset(d);
1365fbdaa002SGerd Hoffmann }
1366fbdaa002SGerd Hoffmann 
136740021f08SAnthony Liguori static Property e1000_properties[] = {
1368fbdaa002SGerd Hoffmann     DEFINE_NIC_PROPERTIES(E1000State, conf),
13692af234e6SMichael S. Tsirkin     DEFINE_PROP_BIT("autonegotiation", E1000State,
13702af234e6SMichael S. Tsirkin                     compat_flags, E1000_FLAG_AUTONEG_BIT, true),
1371fbdaa002SGerd Hoffmann     DEFINE_PROP_END_OF_LIST(),
137240021f08SAnthony Liguori };
137340021f08SAnthony Liguori 
137440021f08SAnthony Liguori static void e1000_class_init(ObjectClass *klass, void *data)
137540021f08SAnthony Liguori {
137639bffca2SAnthony Liguori     DeviceClass *dc = DEVICE_CLASS(klass);
137740021f08SAnthony Liguori     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
137840021f08SAnthony Liguori 
137940021f08SAnthony Liguori     k->init = pci_e1000_init;
138040021f08SAnthony Liguori     k->exit = pci_e1000_uninit;
1381c45e5b5bSGerd Hoffmann     k->romfile = "efi-e1000.rom";
138240021f08SAnthony Liguori     k->vendor_id = PCI_VENDOR_ID_INTEL;
138340021f08SAnthony Liguori     k->device_id = E1000_DEVID;
138440021f08SAnthony Liguori     k->revision = 0x03;
138540021f08SAnthony Liguori     k->class_id = PCI_CLASS_NETWORK_ETHERNET;
138639bffca2SAnthony Liguori     dc->desc = "Intel Gigabit Ethernet";
138739bffca2SAnthony Liguori     dc->reset = qdev_e1000_reset;
138839bffca2SAnthony Liguori     dc->vmsd = &vmstate_e1000;
138939bffca2SAnthony Liguori     dc->props = e1000_properties;
1390fbdaa002SGerd Hoffmann }
139140021f08SAnthony Liguori 
13928c43a6f0SAndreas Färber static const TypeInfo e1000_info = {
139340021f08SAnthony Liguori     .name          = "e1000",
139439bffca2SAnthony Liguori     .parent        = TYPE_PCI_DEVICE,
139539bffca2SAnthony Liguori     .instance_size = sizeof(E1000State),
139640021f08SAnthony Liguori     .class_init    = e1000_class_init,
13970aab0d3aSGerd Hoffmann };
13980aab0d3aSGerd Hoffmann 
139983f7d43aSAndreas Färber static void e1000_register_types(void)
14009d07d757SPaul Brook {
140139bffca2SAnthony Liguori     type_register_static(&e1000_info);
14029d07d757SPaul Brook }
14039d07d757SPaul Brook 
140483f7d43aSAndreas Färber type_init(e1000_register_types)
1405