diff options
Diffstat (limited to 'hw/net')
| -rw-r--r-- | hw/net/cadence_gem.c | 2 | ||||
| -rw-r--r-- | hw/net/dp8393x.c | 95 | ||||
| -rw-r--r-- | hw/net/e1000e.c | 5 | ||||
| -rw-r--r-- | hw/net/fsl_etsec/rings.c | 19 | ||||
| -rw-r--r-- | hw/net/mcf_fec.c | 71 | ||||
| -rw-r--r-- | hw/net/rtl8139.c | 34 | ||||
| -rw-r--r-- | hw/net/spapr_llan.c | 4 | ||||
| -rw-r--r-- | hw/net/vhost_net.c | 19 | ||||
| -rw-r--r-- | hw/net/virtio-net.c | 45 | ||||
| -rw-r--r-- | hw/net/vmxnet3.c | 26 |
10 files changed, 240 insertions, 80 deletions
diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c index 7915732f74..e99d4544a2 100644 --- a/hw/net/cadence_gem.c +++ b/hw/net/cadence_gem.c @@ -896,7 +896,7 @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size) DB_PRINT("config bufsize: %d packet size: %ld\n", rxbufsize, size); - /* Find which queue we are targetting */ + /* Find which queue we are targeting */ q = get_queue_from_screen(s, rxbuf_ptr, rxbufsize); while (bytes_to_copy) { diff --git a/hw/net/dp8393x.c b/hw/net/dp8393x.c index 17f0338d1c..efa33ad40a 100644 --- a/hw/net/dp8393x.c +++ b/hw/net/dp8393x.c @@ -174,6 +174,52 @@ typedef struct dp8393xState { AddressSpace as; } dp8393xState; +/* Accessor functions for values which are formed by + * concatenating two 16 bit device registers. By putting these + * in their own functions with a uint32_t return type we avoid the + * pitfall of implicit sign extension where ((x << 16) | y) is a + * signed 32 bit integer that might get sign-extended to a 64 bit integer. + */ +static uint32_t dp8393x_cdp(dp8393xState *s) +{ + return (s->regs[SONIC_URRA] << 16) | s->regs[SONIC_CDP]; +} + +static uint32_t dp8393x_crba(dp8393xState *s) +{ + return (s->regs[SONIC_CRBA1] << 16) | s->regs[SONIC_CRBA0]; +} + +static uint32_t dp8393x_crda(dp8393xState *s) +{ + return (s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA]; +} + +static uint32_t dp8393x_rbwc(dp8393xState *s) +{ + return (s->regs[SONIC_RBWC1] << 16) | s->regs[SONIC_RBWC0]; +} + +static uint32_t dp8393x_rrp(dp8393xState *s) +{ + return (s->regs[SONIC_URRA] << 16) | s->regs[SONIC_RRP]; +} + +static uint32_t dp8393x_tsa(dp8393xState *s) +{ + return (s->regs[SONIC_TSA1] << 16) | s->regs[SONIC_TSA0]; +} + +static uint32_t dp8393x_ttda(dp8393xState *s) +{ + return (s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_TTDA]; +} + +static uint32_t dp8393x_wt(dp8393xState *s) +{ + return s->regs[SONIC_WT1] << 16 | s->regs[SONIC_WT0]; +} + static void dp8393x_update_irq(dp8393xState *s) { int level = (s->regs[SONIC_IMR] & s->regs[SONIC_ISR]) ? 1 : 0; @@ -203,8 +249,7 @@ static void dp8393x_do_load_cam(dp8393xState *s) while (s->regs[SONIC_CDC] & 0x1f) { /* Fill current entry */ - address_space_rw(&s->as, - (s->regs[SONIC_URRA] << 16) | s->regs[SONIC_CDP], + address_space_rw(&s->as, dp8393x_cdp(s), MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0); s->cam[index][0] = data[1 * width] & 0xff; s->cam[index][1] = data[1 * width] >> 8; @@ -222,8 +267,7 @@ static void dp8393x_do_load_cam(dp8393xState *s) } /* Read CAM enable */ - address_space_rw(&s->as, - (s->regs[SONIC_URRA] << 16) | s->regs[SONIC_CDP], + address_space_rw(&s->as, dp8393x_cdp(s), MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0); s->regs[SONIC_CE] = data[0 * width]; DPRINTF("load cam done. cam enable mask 0x%04x\n", s->regs[SONIC_CE]); @@ -242,8 +286,7 @@ static void dp8393x_do_read_rra(dp8393xState *s) /* Read memory */ width = (s->regs[SONIC_DCR] & SONIC_DCR_DW) ? 2 : 1; size = sizeof(uint16_t) * 4 * width; - address_space_rw(&s->as, - (s->regs[SONIC_URRA] << 16) | s->regs[SONIC_RRP], + address_space_rw(&s->as, dp8393x_rrp(s), MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0); /* Update SONIC registers */ @@ -292,7 +335,7 @@ static void dp8393x_set_next_tick(dp8393xState *s) return; } - ticks = s->regs[SONIC_WT1] << 16 | s->regs[SONIC_WT0]; + ticks = dp8393x_wt(s); s->wt_last_update = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); delay = NANOSECONDS_PER_SECOND * ticks / 5000000; timer_mod(s->watchdog, s->wt_last_update + delay); @@ -309,7 +352,7 @@ static void dp8393x_update_wt_regs(dp8393xState *s) } elapsed = s->wt_last_update - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - val = s->regs[SONIC_WT1] << 16 | s->regs[SONIC_WT0]; + val = dp8393x_wt(s); val -= elapsed / 5000000; s->regs[SONIC_WT1] = (val >> 16) & 0xffff; s->regs[SONIC_WT0] = (val >> 0) & 0xffff; @@ -356,12 +399,11 @@ static void dp8393x_do_transmit_packets(dp8393xState *s) while (1) { /* Read memory */ - DPRINTF("Transmit packet at %08x\n", - (s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_CTDA]); size = sizeof(uint16_t) * 6 * width; s->regs[SONIC_TTDA] = s->regs[SONIC_CTDA]; + DPRINTF("Transmit packet at %08x\n", dp8393x_ttda(s)); address_space_rw(&s->as, - ((s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_TTDA]) + sizeof(uint16_t) * width, + dp8393x_ttda(s) + sizeof(uint16_t) * width, MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0); tx_len = 0; @@ -386,8 +428,7 @@ static void dp8393x_do_transmit_packets(dp8393xState *s) if (tx_len + len > sizeof(s->tx_buffer)) { len = sizeof(s->tx_buffer) - tx_len; } - address_space_rw(&s->as, - (s->regs[SONIC_TSA1] << 16) | s->regs[SONIC_TSA0], + address_space_rw(&s->as, dp8393x_tsa(s), MEMTXATTRS_UNSPECIFIED, &s->tx_buffer[tx_len], len, 0); tx_len += len; @@ -396,7 +437,7 @@ static void dp8393x_do_transmit_packets(dp8393xState *s) /* Read next fragment details */ size = sizeof(uint16_t) * 3 * width; address_space_rw(&s->as, - ((s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_TTDA]) + sizeof(uint16_t) * (4 + 3 * i) * width, + dp8393x_ttda(s) + sizeof(uint16_t) * (4 + 3 * i) * width, MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0); s->regs[SONIC_TSA0] = data[0 * width]; s->regs[SONIC_TSA1] = data[1 * width]; @@ -430,14 +471,16 @@ static void dp8393x_do_transmit_packets(dp8393xState *s) data[0 * width] = s->regs[SONIC_TCR] & 0x0fff; /* status */ size = sizeof(uint16_t) * width; address_space_rw(&s->as, - (s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_TTDA], + dp8393x_ttda(s), MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 1); if (!(s->regs[SONIC_CR] & SONIC_CR_HTX)) { /* Read footer of packet */ size = sizeof(uint16_t) * width; address_space_rw(&s->as, - ((s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_TTDA]) + sizeof(uint16_t) * (4 + 3 * s->regs[SONIC_TFC]) * width, + dp8393x_ttda(s) + + sizeof(uint16_t) * + (4 + 3 * s->regs[SONIC_TFC]) * width, MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0); s->regs[SONIC_CTDA] = data[0 * width] & ~0x1; if (data[0 * width] & 0x1) { @@ -700,7 +743,7 @@ static ssize_t dp8393x_receive(NetClientState *nc, const uint8_t * buf, if (s->regs[SONIC_LLFA] & 0x1) { /* Are we still in resource exhaustion? */ size = sizeof(uint16_t) * 1 * width; - address = ((s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA]) + sizeof(uint16_t) * 5 * width; + address = dp8393x_crda(s) + sizeof(uint16_t) * 5 * width; address_space_rw(&s->as, address, MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0); if (data[0 * width] & 0x1) { @@ -719,8 +762,8 @@ static ssize_t dp8393x_receive(NetClientState *nc, const uint8_t * buf, checksum = cpu_to_le32(crc32(0, buf, rx_len)); /* Put packet into RBA */ - DPRINTF("Receive packet at %08x\n", (s->regs[SONIC_CRBA1] << 16) | s->regs[SONIC_CRBA0]); - address = (s->regs[SONIC_CRBA1] << 16) | s->regs[SONIC_CRBA0]; + DPRINTF("Receive packet at %08x\n", dp8393x_crba(s)); + address = dp8393x_crba(s); address_space_rw(&s->as, address, MEMTXATTRS_UNSPECIFIED, (uint8_t *)buf, rx_len, 1); address += rx_len; @@ -729,13 +772,13 @@ static ssize_t dp8393x_receive(NetClientState *nc, const uint8_t * buf, rx_len += 4; s->regs[SONIC_CRBA1] = address >> 16; s->regs[SONIC_CRBA0] = address & 0xffff; - available = (s->regs[SONIC_RBWC1] << 16) | s->regs[SONIC_RBWC0]; + available = dp8393x_rbwc(s); available -= rx_len / 2; s->regs[SONIC_RBWC1] = available >> 16; s->regs[SONIC_RBWC0] = available & 0xffff; /* Update status */ - if (((s->regs[SONIC_RBWC1] << 16) | s->regs[SONIC_RBWC0]) < s->regs[SONIC_EOBC]) { + if (dp8393x_rbwc(s) < s->regs[SONIC_EOBC]) { s->regs[SONIC_RCR] |= SONIC_RCR_LPKT; } s->regs[SONIC_RCR] |= packet_type; @@ -746,20 +789,19 @@ static ssize_t dp8393x_receive(NetClientState *nc, const uint8_t * buf, } /* Write status to memory */ - DPRINTF("Write status at %08x\n", (s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA]); + DPRINTF("Write status at %08x\n", dp8393x_crda(s)); data[0 * width] = s->regs[SONIC_RCR]; /* status */ data[1 * width] = rx_len; /* byte count */ data[2 * width] = s->regs[SONIC_TRBA0]; /* pkt_ptr0 */ data[3 * width] = s->regs[SONIC_TRBA1]; /* pkt_ptr1 */ data[4 * width] = s->regs[SONIC_RSC]; /* seq_no */ size = sizeof(uint16_t) * 5 * width; - address_space_rw(&s->as, (s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA], + address_space_rw(&s->as, dp8393x_crda(s), MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 1); /* Move to next descriptor */ size = sizeof(uint16_t) * width; - address_space_rw(&s->as, - ((s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA]) + sizeof(uint16_t) * 5 * width, + address_space_rw(&s->as, dp8393x_crda(s) + sizeof(uint16_t) * 5 * width, MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0); s->regs[SONIC_LLFA] = data[0 * width]; if (s->regs[SONIC_LLFA] & 0x1) { @@ -767,8 +809,7 @@ static ssize_t dp8393x_receive(NetClientState *nc, const uint8_t * buf, s->regs[SONIC_ISR] |= SONIC_ISR_RDE; } else { data[0 * width] = 0; /* in_use */ - address_space_rw(&s->as, - ((s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA]) + sizeof(uint16_t) * 6 * width, + address_space_rw(&s->as, dp8393x_crda(s) + sizeof(uint16_t) * 6 * width, MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, sizeof(uint16_t), 1); s->regs[SONIC_CRDA] = s->regs[SONIC_LLFA]; s->regs[SONIC_ISR] |= SONIC_ISR_PKTRX; diff --git a/hw/net/e1000e.c b/hw/net/e1000e.c index 4994e1ca00..0e9a25b7ab 100644 --- a/hw/net/e1000e.c +++ b/hw/net/e1000e.c @@ -472,7 +472,8 @@ static void e1000e_pci_realize(PCIDevice *pci_dev, Error **errp) hw_error("Failed to initialize PM capability"); } - if (pcie_aer_init(pci_dev, e1000e_aer_offset, PCI_ERR_SIZEOF) < 0) { + if (pcie_aer_init(pci_dev, PCI_ERR_VER, e1000e_aer_offset, + PCI_ERR_SIZEOF, NULL) < 0) { hw_error("Failed to initialize AER capability"); } @@ -592,7 +593,7 @@ static const VMStateDescription e1000e_vmstate = { .pre_save = e1000e_pre_save, .post_load = e1000e_post_load, .fields = (VMStateField[]) { - VMSTATE_PCIE_DEVICE(parent_obj, E1000EState), + VMSTATE_PCI_DEVICE(parent_obj, E1000EState), VMSTATE_MSIX(parent_obj, E1000EState), VMSTATE_UINT32(ioaddr, E1000EState), diff --git a/hw/net/fsl_etsec/rings.c b/hw/net/fsl_etsec/rings.c index 54c01275d4..d0f93eebfc 100644 --- a/hw/net/fsl_etsec/rings.c +++ b/hw/net/fsl_etsec/rings.c @@ -358,25 +358,24 @@ void etsec_walk_tx_ring(eTSEC *etsec, int ring_nbr) /* Save flags before BD update */ bd_flags = bd.flags; - if (bd_flags & BD_TX_READY) { - process_tx_bd(etsec, &bd); - - /* Write back BD after update */ - write_buffer_descriptor(etsec, bd_addr, &bd); + if (!(bd_flags & BD_TX_READY)) { + break; } + process_tx_bd(etsec, &bd); + /* Write back BD after update */ + write_buffer_descriptor(etsec, bd_addr, &bd); + /* Wrap or next BD */ if (bd_flags & BD_WRAP) { bd_addr = ring_base; } else { bd_addr += sizeof(eTSEC_rxtx_bd); } + } while (TRUE); - } while (bd_addr != ring_base); - - bd_addr = ring_base; - - /* Save the Buffer Descriptor Pointers to current bd */ + /* Save the Buffer Descriptor Pointers to last bd that was not + * succesfully closed */ etsec->regs[TBPTR0 + ring_nbr].value = bd_addr; /* Set transmit halt THLTx */ diff --git a/hw/net/mcf_fec.c b/hw/net/mcf_fec.c index 4025eb3b33..a3eca7e0f5 100644 --- a/hw/net/mcf_fec.c +++ b/hw/net/mcf_fec.c @@ -9,7 +9,9 @@ #include "hw/hw.h" #include "net/net.h" #include "hw/m68k/mcf.h" +#include "hw/m68k/mcf_fec.h" #include "hw/net/mii.h" +#include "hw/sysbus.h" /* For crc32 */ #include <zlib.h> #include "exec/address-spaces.h" @@ -27,9 +29,10 @@ do { printf("mcf_fec: " fmt , ## __VA_ARGS__); } while (0) #define FEC_MAX_FRAME_SIZE 2032 typedef struct { - MemoryRegion *sysmem; + SysBusDevice parent_obj; + MemoryRegion iomem; - qemu_irq *irq; + qemu_irq irq[FEC_NUM_IRQ]; NICState *nic; NICConf conf; uint32_t irq_state; @@ -68,7 +71,6 @@ typedef struct { #define FEC_RESET 1 /* Map interrupt flags onto IRQ lines. */ -#define FEC_NUM_IRQ 13 static const uint32_t mcf_fec_irq_map[FEC_NUM_IRQ] = { FEC_INT_TXF, FEC_INT_TXB, @@ -208,8 +210,10 @@ static void mcf_fec_enable_rx(mcf_fec_state *s) } } -static void mcf_fec_reset(mcf_fec_state *s) +static void mcf_fec_reset(DeviceState *dev) { + mcf_fec_state *s = MCF_FEC_NET(dev); + s->eir = 0; s->eimr = 0; s->rx_enabled = 0; @@ -330,7 +334,7 @@ static void mcf_fec_write(void *opaque, hwaddr addr, s->ecr = value; if (value & FEC_RESET) { DPRINTF("Reset\n"); - mcf_fec_reset(s); + mcf_fec_reset(opaque); } if ((s->ecr & FEC_EN) == 0) { s->rx_enabled = 0; @@ -513,24 +517,55 @@ static NetClientInfo net_mcf_fec_info = { .receive = mcf_fec_receive, }; -void mcf_fec_init(MemoryRegion *sysmem, NICInfo *nd, - hwaddr base, qemu_irq *irq) +static void mcf_fec_realize(DeviceState *dev, Error **errp) { - mcf_fec_state *s; + mcf_fec_state *s = MCF_FEC_NET(dev); + + s->nic = qemu_new_nic(&net_mcf_fec_info, &s->conf, + object_get_typename(OBJECT(dev)), dev->id, s); + qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); +} - qemu_check_nic_model(nd, "mcf_fec"); +static void mcf_fec_instance_init(Object *obj) +{ + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + mcf_fec_state *s = MCF_FEC_NET(obj); + int i; + + memory_region_init_io(&s->iomem, obj, &mcf_fec_ops, s, "fec", 0x400); + sysbus_init_mmio(sbd, &s->iomem); + for (i = 0; i < FEC_NUM_IRQ; i++) { + sysbus_init_irq(sbd, &s->irq[i]); + } +} - s = (mcf_fec_state *)g_malloc0(sizeof(mcf_fec_state)); - s->sysmem = sysmem; - s->irq = irq; +static Property mcf_fec_properties[] = { + DEFINE_NIC_PROPERTIES(mcf_fec_state, conf), + DEFINE_PROP_END_OF_LIST(), +}; - memory_region_init_io(&s->iomem, NULL, &mcf_fec_ops, s, "fec", 0x400); - memory_region_add_subregion(sysmem, base, &s->iomem); +static void mcf_fec_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); - s->conf.macaddr = nd->macaddr; - s->conf.peers.ncs[0] = nd->netdev; + set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); + dc->realize = mcf_fec_realize; + dc->desc = "MCF Fast Ethernet Controller network device"; + dc->reset = mcf_fec_reset; + dc->props = mcf_fec_properties; +} - s->nic = qemu_new_nic(&net_mcf_fec_info, &s->conf, nd->model, nd->name, s); +static const TypeInfo mcf_fec_info = { + .name = TYPE_MCF_FEC_NET, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(mcf_fec_state), + .instance_init = mcf_fec_instance_init, + .class_init = mcf_fec_class_init, +}; - qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); +static void mcf_fec_register_types(void) +{ + type_register_static(&mcf_fec_info); } + +type_init(mcf_fec_register_types) diff --git a/hw/net/rtl8139.c b/hw/net/rtl8139.c index f05e59c85f..671c7e48c6 100644 --- a/hw/net/rtl8139.c +++ b/hw/net/rtl8139.c @@ -1205,6 +1205,20 @@ static void rtl8139_reset_rxring(RTL8139State *s, uint32_t bufferSize) s->RxBufAddr = 0; } +static void rtl8139_reset_phy(RTL8139State *s) +{ + s->BasicModeStatus = 0x7809; + s->BasicModeStatus |= 0x0020; /* autonegotiation completed */ + /* preserve link state */ + s->BasicModeStatus |= qemu_get_queue(s->nic)->link_down ? 0 : 0x04; + + s->NWayAdvert = 0x05e1; /* all modes, full duplex */ + s->NWayLPAR = 0x05e1; /* all modes, full duplex */ + s->NWayExpansion = 0x0001; /* autonegotiation supported */ + + s->CSCR = CSCR_F_LINK_100 | CSCR_HEART_BIT | CSCR_LD; +} + static void rtl8139_reset(DeviceState *d) { RTL8139State *s = RTL8139(d); @@ -1256,25 +1270,14 @@ static void rtl8139_reset(DeviceState *d) s->Config3 = 0x1; /* fast back-to-back compatible */ s->Config5 = 0x0; - s->CSCR = CSCR_F_LINK_100 | CSCR_HEART_BIT | CSCR_LD; - s->CpCmd = 0x0; /* reset C+ mode */ s->cplus_enabled = 0; - // s->BasicModeCtrl = 0x3100; // 100Mbps, full duplex, autonegotiation // s->BasicModeCtrl = 0x2100; // 100Mbps, full duplex s->BasicModeCtrl = 0x1000; // autonegotiation - s->BasicModeStatus = 0x7809; - //s->BasicModeStatus |= 0x0040; /* UTP medium */ - s->BasicModeStatus |= 0x0020; /* autonegotiation completed */ - /* preserve link state */ - s->BasicModeStatus |= qemu_get_queue(s->nic)->link_down ? 0 : 0x04; - - s->NWayAdvert = 0x05e1; /* all modes, full duplex */ - s->NWayLPAR = 0x05e1; /* all modes, full duplex */ - s->NWayExpansion = 0x0001; /* autonegotiation supported */ + rtl8139_reset_phy(s); /* also reset timer and disable timer interrupt */ s->TCTR = 0; @@ -1469,7 +1472,7 @@ static void rtl8139_BasicModeCtrl_write(RTL8139State *s, uint32_t val) DPRINTF("BasicModeCtrl register write(w) val=0x%04x\n", val); /* mask unwritable bits */ - uint32_t mask = 0x4cff; + uint32_t mask = 0xccff; if (1 || !rtl8139_config_writable(s)) { @@ -1479,6 +1482,11 @@ static void rtl8139_BasicModeCtrl_write(RTL8139State *s, uint32_t val) mask |= 0x0100; } + if (val & 0x8000) { + /* Reset PHY */ + rtl8139_reset_phy(s); + } + val = SET_MASKED(val, mask, s->BasicModeCtrl); s->BasicModeCtrl = val; diff --git a/hw/net/spapr_llan.c b/hw/net/spapr_llan.c index 01ecb02773..058908d8d7 100644 --- a/hw/net/spapr_llan.c +++ b/hw/net/spapr_llan.c @@ -105,7 +105,7 @@ typedef struct VIOsPAPRVLANDevice { uint32_t add_buf_ptr, use_buf_ptr, rx_bufs; hwaddr rxq_ptr; QEMUTimer *rxp_timer; - uint32_t compat_flags; /* Compatability flags for migration */ + uint32_t compat_flags; /* Compatibility flags for migration */ RxBufPool *rx_pool[RX_MAX_POOLS]; /* Receive buffer descriptor pools */ } VIOsPAPRVLANDevice; @@ -559,7 +559,7 @@ static target_long spapr_vlan_add_rxbuf_to_pool(VIOsPAPRVLANDevice *dev, if (pool < 0) { /* * No matching pool found? Try to use a new one. If the guest used all - * pools before, but changed the size of one pool inbetween, we might + * pools before, but changed the size of one pool in the meantime, we might * need to recycle that pool here (if it's empty already). Thus scan * all buffer pools now, starting with the last (likely empty) one. */ diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c index f2d49ad7e7..22874a9777 100644 --- a/hw/net/vhost_net.c +++ b/hw/net/vhost_net.c @@ -51,6 +51,8 @@ static const int kernel_feature_bits[] = { VIRTIO_RING_F_EVENT_IDX, VIRTIO_NET_F_MRG_RXBUF, VIRTIO_F_VERSION_1, + VIRTIO_NET_F_MTU, + VIRTIO_F_IOMMU_PLATFORM, VHOST_INVALID_FEATURE_BIT }; @@ -74,6 +76,7 @@ static const int user_feature_bits[] = { VIRTIO_NET_F_HOST_ECN, VIRTIO_NET_F_HOST_UFO, VIRTIO_NET_F_MRG_RXBUF, + VIRTIO_NET_F_MTU, /* This bit implies RARP isn't sent by QEMU out of band */ VIRTIO_NET_F_GUEST_ANNOUNCE, @@ -435,6 +438,17 @@ int vhost_set_vring_enable(NetClientState *nc, int enable) return 0; } +int vhost_net_set_mtu(struct vhost_net *net, uint16_t mtu) +{ + const VhostOps *vhost_ops = net->dev.vhost_ops; + + if (!vhost_ops->vhost_net_set_mtu) { + return 0; + } + + return vhost_ops->vhost_net_set_mtu(&net->dev, mtu); +} + #else uint64_t vhost_net_get_max_queues(VHostNetState *net) { @@ -501,4 +515,9 @@ int vhost_set_vring_enable(NetClientState *nc, int enable) { return 0; } + +int vhost_net_set_mtu(struct vhost_net *net, uint16_t mtu) +{ + return 0; +} #endif diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 5009533cfa..7b3ad4a9f0 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -55,6 +55,8 @@ static VirtIOFeature feature_sizes[] = { .end = endof(struct virtio_net_config, status)}, {.flags = 1 << VIRTIO_NET_F_MQ, .end = endof(struct virtio_net_config, max_virtqueue_pairs)}, + {.flags = 1 << VIRTIO_NET_F_MTU, + .end = endof(struct virtio_net_config, mtu)}, {} }; @@ -81,6 +83,7 @@ static void virtio_net_get_config(VirtIODevice *vdev, uint8_t *config) virtio_stw_p(vdev, &netcfg.status, n->status); virtio_stw_p(vdev, &netcfg.max_virtqueue_pairs, n->max_queues); + virtio_stw_p(vdev, &netcfg.mtu, n->net_conf.mtu); memcpy(netcfg.mac, n->mac, ETH_ALEN); memcpy(config, &netcfg, n->config_size); } @@ -152,6 +155,16 @@ static void virtio_net_vhost_status(VirtIONet *n, uint8_t status) qemu_net_queue_purge(qnc->incoming_queue, qnc->peer); } + if (virtio_has_feature(vdev->guest_features, VIRTIO_NET_F_MTU)) { + r = vhost_net_set_mtu(get_vhost_net(nc->peer), n->net_conf.mtu); + if (r < 0) { + error_report("%uBytes MTU not supported by the backend", + n->net_conf.mtu); + + return; + } + } + n->vhost_started = 1; r = vhost_net_start(vdev, n->nic->ncs, queues); if (r < 0) { @@ -218,6 +231,14 @@ static void virtio_net_vnet_endian_status(VirtIONet *n, uint8_t status) } } +static void virtio_net_drop_tx_queue_data(VirtIODevice *vdev, VirtQueue *vq) +{ + unsigned int dropped = virtqueue_drop_all(vq); + if (dropped) { + virtio_notify(vdev, vq); + } +} + static void virtio_net_set_status(struct VirtIODevice *vdev, uint8_t status) { VirtIONet *n = VIRTIO_NET(vdev); @@ -262,6 +283,14 @@ static void virtio_net_set_status(struct VirtIODevice *vdev, uint8_t status) } else { qemu_bh_cancel(q->tx_bh); } + if ((n->status & VIRTIO_NET_S_LINK_UP) == 0 && + (queue_status & VIRTIO_CONFIG_S_DRIVER_OK)) { + /* if tx is waiting we are likely have some packets in tx queue + * and disabled notification */ + q->tx_waiting = 0; + virtio_queue_set_notification(q->tx_vq, 1); + virtio_net_drop_tx_queue_data(vdev, q->tx_vq); + } } } } @@ -1323,6 +1352,11 @@ static void virtio_net_handle_tx_timer(VirtIODevice *vdev, VirtQueue *vq) VirtIONet *n = VIRTIO_NET(vdev); VirtIONetQueue *q = &n->vqs[vq2q(virtio_get_queue_index(vq))]; + if (unlikely((n->status & VIRTIO_NET_S_LINK_UP) == 0)) { + virtio_net_drop_tx_queue_data(vdev, vq); + return; + } + /* This happens when device was stopped but VCPU wasn't. */ if (!vdev->vm_running) { q->tx_waiting = 1; @@ -1349,6 +1383,11 @@ static void virtio_net_handle_tx_bh(VirtIODevice *vdev, VirtQueue *vq) VirtIONet *n = VIRTIO_NET(vdev); VirtIONetQueue *q = &n->vqs[vq2q(virtio_get_queue_index(vq))]; + if (unlikely((n->status & VIRTIO_NET_S_LINK_UP) == 0)) { + virtio_net_drop_tx_queue_data(vdev, vq); + return; + } + if (unlikely(q->tx_waiting)) { return; } @@ -1695,6 +1734,7 @@ static void virtio_net_set_config_size(VirtIONet *n, uint64_t host_features) { int i, config_size = 0; virtio_add_feature(&host_features, VIRTIO_NET_F_MAC); + for (i = 0; feature_sizes[i].flags != 0; i++) { if (host_features & feature_sizes[i].flags) { config_size = MAX(feature_sizes[i].end, config_size); @@ -1724,6 +1764,10 @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp) NetClientState *nc; int i; + if (n->net_conf.mtu) { + n->host_features |= (0x1 << VIRTIO_NET_F_MTU); + } + virtio_net_set_config_size(n, n->host_features); virtio_init(vdev, "virtio-net", VIRTIO_ID_NET, n->config_size); @@ -1922,6 +1966,7 @@ static Property virtio_net_properties[] = { DEFINE_PROP_STRING("tx", VirtIONet, net_conf.tx), DEFINE_PROP_UINT16("rx_queue_size", VirtIONet, net_conf.rx_queue_size, VIRTIO_NET_RX_QUEUE_DEFAULT_SIZE), + DEFINE_PROP_UINT16("host_mtu", VirtIONet, net_conf.mtu, 0), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/net/vmxnet3.c b/hw/net/vmxnet3.c index 92f6af9620..2cb2731e29 100644 --- a/hw/net/vmxnet3.c +++ b/hw/net/vmxnet3.c @@ -2451,7 +2451,8 @@ static void vmxnet3_put_tx_stats_to_file(QEMUFile *f, qemu_put_be64(f, tx_stat->pktsTxDiscard); } -static int vmxnet3_get_txq_descr(QEMUFile *f, void *pv, size_t size) +static int vmxnet3_get_txq_descr(QEMUFile *f, void *pv, size_t size, + VMStateField *field) { Vmxnet3TxqDescr *r = pv; @@ -2465,7 +2466,8 @@ static int vmxnet3_get_txq_descr(QEMUFile *f, void *pv, size_t size) return 0; } -static void vmxnet3_put_txq_descr(QEMUFile *f, void *pv, size_t size) +static int vmxnet3_put_txq_descr(QEMUFile *f, void *pv, size_t size, + VMStateField *field, QJSON *vmdesc) { Vmxnet3TxqDescr *r = pv; @@ -2474,6 +2476,8 @@ static void vmxnet3_put_txq_descr(QEMUFile *f, void *pv, size_t size) qemu_put_byte(f, r->intr_idx); qemu_put_be64(f, r->tx_stats_pa); vmxnet3_put_tx_stats_to_file(f, &r->txq_stats); + + return 0; } static const VMStateInfo txq_descr_info = { @@ -2512,7 +2516,8 @@ static void vmxnet3_put_rx_stats_to_file(QEMUFile *f, qemu_put_be64(f, rx_stat->pktsRxError); } -static int vmxnet3_get_rxq_descr(QEMUFile *f, void *pv, size_t size) +static int vmxnet3_get_rxq_descr(QEMUFile *f, void *pv, size_t size, + VMStateField *field) { Vmxnet3RxqDescr *r = pv; int i; @@ -2530,7 +2535,8 @@ static int vmxnet3_get_rxq_descr(QEMUFile *f, void *pv, size_t size) return 0; } -static void vmxnet3_put_rxq_descr(QEMUFile *f, void *pv, size_t size) +static int vmxnet3_put_rxq_descr(QEMUFile *f, void *pv, size_t size, + VMStateField *field, QJSON *vmdesc) { Vmxnet3RxqDescr *r = pv; int i; @@ -2543,6 +2549,8 @@ static void vmxnet3_put_rxq_descr(QEMUFile *f, void *pv, size_t size) qemu_put_byte(f, r->intr_idx); qemu_put_be64(f, r->rx_stats_pa); vmxnet3_put_rx_stats_to_file(f, &r->rxq_stats); + + return 0; } static int vmxnet3_post_load(void *opaque, int version_id) @@ -2575,7 +2583,8 @@ static const VMStateInfo rxq_descr_info = { .put = vmxnet3_put_rxq_descr }; -static int vmxnet3_get_int_state(QEMUFile *f, void *pv, size_t size) +static int vmxnet3_get_int_state(QEMUFile *f, void *pv, size_t size, + VMStateField *field) { Vmxnet3IntState *r = pv; @@ -2586,13 +2595,16 @@ static int vmxnet3_get_int_state(QEMUFile *f, void *pv, size_t size) return 0; } -static void vmxnet3_put_int_state(QEMUFile *f, void *pv, size_t size) +static int vmxnet3_put_int_state(QEMUFile *f, void *pv, size_t size, + VMStateField *field, QJSON *vmdesc) { Vmxnet3IntState *r = pv; qemu_put_byte(f, r->is_masked); qemu_put_byte(f, r->is_pending); qemu_put_byte(f, r->is_asserted); + + return 0; } static const VMStateInfo int_state_info = { @@ -2619,7 +2631,7 @@ static const VMStateDescription vmstate_vmxnet3_pcie_device = { .minimum_version_id = 1, .needed = vmxnet3_vmstate_need_pcie_device, .fields = (VMStateField[]) { - VMSTATE_PCIE_DEVICE(parent_obj, VMXNET3State), + VMSTATE_PCI_DEVICE(parent_obj, VMXNET3State), VMSTATE_END_OF_LIST() } }; |