aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hmp-commands.hx2
-rw-r--r--hw/e1000.c25
-rw-r--r--hw/ich9.h11
-rw-r--r--hw/lpc_ich9.c57
-rw-r--r--hw/pc.h5
-rw-r--r--hw/pc_piix.c4
-rw-r--r--hw/sysbus.c27
-rw-r--r--hw/sysbus.h2
-rw-r--r--hw/vhost.c49
-rw-r--r--hw/virtio-net.c6
-rw-r--r--hw/virtio-pci.c5
-rw-r--r--include/net/net.h2
-rw-r--r--net/hub.c14
-rw-r--r--net/hub.h1
-rw-r--r--net/net.c25
-rw-r--r--net/queue.c15
-rw-r--r--net/tap-linux.c10
-rw-r--r--net/tap-linux.h9
-rw-r--r--net/tap.c7
-rw-r--r--pc-bios/bios.binbin131072 -> 131072 bytes
-rw-r--r--qemu-options.hx11
-rw-r--r--qmp-commands.hx2
m---------roms/seabios0
-rw-r--r--target-i386/cpu.c3
24 files changed, 245 insertions, 47 deletions
diff --git a/hmp-commands.hx b/hmp-commands.hx
index cef7708e3a..69c707d332 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -1169,7 +1169,7 @@ ETEXI
{
.name = "netdev_add",
.args_type = "netdev:O",
- .params = "[user|tap|socket],id=str[,prop=value][,...]",
+ .params = "[user|tap|socket|hubport],id=str[,prop=value][,...]",
.help = "add host network device",
.mhandler.cmd = hmp_netdev_add,
},
diff --git a/hw/e1000.c b/hw/e1000.c
index d6fe815eda..45cc3300cf 100644
--- a/hw/e1000.c
+++ b/hw/e1000.c
@@ -131,6 +131,11 @@ typedef struct E1000State_st {
} eecd_state;
QEMUTimer *autoneg_timer;
+
+/* Compatibility flags for migration to/from qemu 1.3.0 and older */
+#define E1000_FLAG_AUTONEG_BIT 0
+#define E1000_FLAG_AUTONEG (1 << E1000_FLAG_AUTONEG_BIT)
+ uint32_t compat_flags;
} E1000State;
#define defreg(x) x = (E1000_##x>>2)
@@ -165,6 +170,14 @@ e1000_link_up(E1000State *s)
static void
set_phy_ctrl(E1000State *s, int index, uint16_t val)
{
+ /*
+ * QEMU 1.3 does not support link auto-negotiation emulation, so if we
+ * migrate during auto negotiation, after migration the link will be
+ * down.
+ */
+ if (!(s->compat_flags & E1000_FLAG_AUTONEG)) {
+ return;
+ }
if ((val & MII_CR_AUTO_NEG_EN) && (val & MII_CR_RESTART_AUTO_NEG)) {
e1000_link_down(s);
s->phy_reg[PHY_STATUS] &= ~MII_SR_AUTONEG_COMPLETE;
@@ -1120,6 +1133,11 @@ static void e1000_pre_save(void *opaque)
{
E1000State *s = opaque;
NetClientState *nc = qemu_get_queue(s->nic);
+
+ if (!(s->compat_flags & E1000_FLAG_AUTONEG)) {
+ return;
+ }
+
/*
* If link is down and auto-negotiation is ongoing, complete
* auto-negotiation immediately. This allows is to look at
@@ -1141,6 +1159,11 @@ static int e1000_post_load(void *opaque, int version_id)
* to link status bit in mac_reg[STATUS].
* Alternatively, restart link negotiation if it was in progress. */
nc->link_down = (s->mac_reg[STATUS] & E1000_STATUS_LU) == 0;
+
+ if (!(s->compat_flags & E1000_FLAG_AUTONEG)) {
+ return 0;
+ }
+
if (s->phy_reg[PHY_CTRL] & MII_CR_AUTO_NEG_EN &&
s->phy_reg[PHY_CTRL] & MII_CR_RESTART_AUTO_NEG &&
!(s->phy_reg[PHY_STATUS] & MII_SR_AUTONEG_COMPLETE)) {
@@ -1343,6 +1366,8 @@ static void qdev_e1000_reset(DeviceState *dev)
static Property e1000_properties[] = {
DEFINE_NIC_PROPERTIES(E1000State, conf),
+ DEFINE_PROP_BIT("autonegotiation", E1000State,
+ compat_flags, E1000_FLAG_AUTONEG_BIT, true),
DEFINE_PROP_END_OF_LIST(),
};
diff --git a/hw/ich9.h b/hw/ich9.h
index d4509bb606..dbc44957b4 100644
--- a/hw/ich9.h
+++ b/hw/ich9.h
@@ -49,6 +49,15 @@ typedef struct ICH9LPCState {
/* 10.1 Chipset Configuration registers(Memory Space)
which is pointed by RCBA */
uint8_t chip_config[ICH9_CC_SIZE];
+
+ /*
+ * 13.7.5 RST_CNT---Reset Control Register (LPC I/F---D31:F0)
+ *
+ * register contents and IO memory region
+ */
+ uint8_t rst_cnt;
+ MemoryRegion rst_cnt_mem;
+
/* isa bus */
ISABus *isa_bus;
MemoryRegion rbca_mem;
@@ -103,6 +112,8 @@ typedef struct ICH9LPCState {
#define ICH9_D2P_A2_REVISION 0x92
+/* D31:F0 LPC Processor Interface */
+#define ICH9_RST_CNT_IOPORT 0xCF9
/* D31:F1 LPC controller */
#define ICH9_A2_LPC "ICH9 A2 LPC"
diff --git a/hw/lpc_ich9.c b/hw/lpc_ich9.c
index e25689bf87..eceb052420 100644
--- a/hw/lpc_ich9.c
+++ b/hw/lpc_ich9.c
@@ -466,6 +466,7 @@ static void ich9_lpc_reset(DeviceState *qdev)
ich9_lpc_rcba_update(lpc, rbca_old);
lpc->sci_level = 0;
+ lpc->rst_cnt = 0;
}
static const MemoryRegionOps rbca_mmio_ops = {
@@ -498,6 +499,32 @@ static void ich9_lpc_machine_ready(Notifier *n, void *opaque)
}
}
+/* reset control */
+static void ich9_rst_cnt_write(void *opaque, hwaddr addr, uint64_t val,
+ unsigned len)
+{
+ ICH9LPCState *lpc = opaque;
+
+ if (val & 4) {
+ qemu_system_reset_request();
+ return;
+ }
+ lpc->rst_cnt = val & 0xA; /* keep FULL_RST (bit 3) and SYS_RST (bit 1) */
+}
+
+static uint64_t ich9_rst_cnt_read(void *opaque, hwaddr addr, unsigned len)
+{
+ ICH9LPCState *lpc = opaque;
+
+ return lpc->rst_cnt;
+}
+
+static const MemoryRegionOps ich9_rst_cnt_ops = {
+ .read = ich9_rst_cnt_read,
+ .write = ich9_rst_cnt_write,
+ .endianness = DEVICE_LITTLE_ENDIAN
+};
+
static int ich9_lpc_initfn(PCIDevice *d)
{
ICH9LPCState *lpc = ICH9_LPC_DEVICE(d);
@@ -519,9 +546,32 @@ static int ich9_lpc_initfn(PCIDevice *d)
lpc->machine_ready.notify = ich9_lpc_machine_ready;
qemu_add_machine_init_done_notifier(&lpc->machine_ready);
+ memory_region_init_io(&lpc->rst_cnt_mem, &ich9_rst_cnt_ops, lpc,
+ "lpc-reset-control", 1);
+ memory_region_add_subregion_overlap(pci_address_space_io(d),
+ ICH9_RST_CNT_IOPORT, &lpc->rst_cnt_mem,
+ 1);
+
return 0;
}
+static bool ich9_rst_cnt_needed(void *opaque)
+{
+ ICH9LPCState *lpc = opaque;
+
+ return (lpc->rst_cnt != 0);
+}
+
+static const VMStateDescription vmstate_ich9_rst_cnt = {
+ .name = "ICH9LPC/rst_cnt",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT8(rst_cnt, ICH9LPCState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static const VMStateDescription vmstate_ich9_lpc = {
.name = "ICH9LPC",
.version_id = 1,
@@ -535,6 +585,13 @@ static const VMStateDescription vmstate_ich9_lpc = {
VMSTATE_UINT8_ARRAY(chip_config, ICH9LPCState, ICH9_CC_SIZE),
VMSTATE_UINT32(sci_level, ICH9LPCState),
VMSTATE_END_OF_LIST()
+ },
+ .subsections = (VMStateSubsection[]) {
+ {
+ .vmsd = &vmstate_ich9_rst_cnt,
+ .needed = ich9_rst_cnt_needed
+ },
+ { 0 }
}
};
diff --git a/hw/pc.h b/hw/pc.h
index da1b102ef1..f2c1b1c2a4 100644
--- a/hw/pc.h
+++ b/hw/pc.h
@@ -216,6 +216,11 @@ int e820_add_entry(uint64_t, uint64_t, uint32_t);
.driver = "virtio-blk-pci",\
.property = "discard_granularity",\
.value = stringify(0),\
+ },{\
+ .driver = "virtio-serial-pci",\
+ .property = "vectors",\
+ /* DEV_NVECTORS_UNSPECIFIED as a uint32_t string */\
+ .value = stringify(0xFFFFFFFF),\
}
#endif
diff --git a/hw/pc_piix.c b/hw/pc_piix.c
index aa9cc81a2d..a305e1fb77 100644
--- a/hw/pc_piix.c
+++ b/hw/pc_piix.c
@@ -330,6 +330,10 @@ static QEMUMachine pc_i440fx_machine_v1_4 = {
.driver = "virtio-net-pci", \
.property = "mq", \
.value = "off", \
+ }, {\
+ .driver = "e1000",\
+ .property = "autonegotiation",\
+ .value = "off",\
}
static QEMUMachine pc_machine_v1_3 = {
diff --git a/hw/sysbus.c b/hw/sysbus.c
index 6d9d1df419..50c7232799 100644
--- a/hw/sysbus.c
+++ b/hw/sysbus.c
@@ -48,7 +48,8 @@ void sysbus_connect_irq(SysBusDevice *dev, int n, qemu_irq irq)
}
}
-void sysbus_mmio_map(SysBusDevice *dev, int n, hwaddr addr)
+static void sysbus_mmio_map_common(SysBusDevice *dev, int n, hwaddr addr,
+ bool may_overlap, unsigned priority)
{
assert(n >= 0 && n < dev->num_mmio);
@@ -61,11 +62,29 @@ void sysbus_mmio_map(SysBusDevice *dev, int n, hwaddr addr)
memory_region_del_subregion(get_system_memory(), dev->mmio[n].memory);
}
dev->mmio[n].addr = addr;
- memory_region_add_subregion(get_system_memory(),
- addr,
- dev->mmio[n].memory);
+ if (may_overlap) {
+ memory_region_add_subregion_overlap(get_system_memory(),
+ addr,
+ dev->mmio[n].memory,
+ priority);
+ }
+ else {
+ memory_region_add_subregion(get_system_memory(),
+ addr,
+ dev->mmio[n].memory);
+ }
}
+void sysbus_mmio_map(SysBusDevice *dev, int n, hwaddr addr)
+{
+ sysbus_mmio_map_common(dev, n, addr, false, 0);
+}
+
+void sysbus_mmio_map_overlap(SysBusDevice *dev, int n, hwaddr addr,
+ unsigned priority)
+{
+ sysbus_mmio_map_common(dev, n, addr, true, priority);
+}
/* Request an IRQ source. The actual IRQ object may be populated later. */
void sysbus_init_irq(SysBusDevice *dev, qemu_irq *p)
diff --git a/hw/sysbus.h b/hw/sysbus.h
index a7fcded6e7..2100bd7d07 100644
--- a/hw/sysbus.h
+++ b/hw/sysbus.h
@@ -56,6 +56,8 @@ void sysbus_init_ioports(SysBusDevice *dev, pio_addr_t ioport, pio_addr_t size);
void sysbus_connect_irq(SysBusDevice *dev, int n, qemu_irq irq);
void sysbus_mmio_map(SysBusDevice *dev, int n, hwaddr addr);
+void sysbus_mmio_map_overlap(SysBusDevice *dev, int n, hwaddr addr,
+ unsigned priority);
void sysbus_add_memory(SysBusDevice *dev, hwaddr addr,
MemoryRegion *mem);
void sysbus_add_memory_overlap(SysBusDevice *dev, hwaddr addr,
diff --git a/hw/vhost.c b/hw/vhost.c
index 8d41fdb53f..37777c267e 100644
--- a/hw/vhost.c
+++ b/hw/vhost.c
@@ -53,10 +53,14 @@ static void vhost_dev_sync_region(struct vhost_dev *dev,
log = __sync_fetch_and_and(from, 0);
while ((bit = sizeof(log) > sizeof(int) ?
ffsll(log) : ffs(log))) {
- ram_addr_t ram_addr;
+ hwaddr page_addr;
+ hwaddr section_offset;
+ hwaddr mr_offset;
bit -= 1;
- ram_addr = section->offset_within_region + bit * VHOST_LOG_PAGE;
- memory_region_set_dirty(section->mr, ram_addr, VHOST_LOG_PAGE);
+ page_addr = addr + bit * VHOST_LOG_PAGE;
+ section_offset = page_addr - section->offset_within_address_space;
+ mr_offset = section_offset + section->offset_within_region;
+ memory_region_set_dirty(section->mr, mr_offset, VHOST_LOG_PAGE);
log &= ~(0x1ull << bit);
}
addr += VHOST_LOG_CHUNK;
@@ -65,14 +69,21 @@ static void vhost_dev_sync_region(struct vhost_dev *dev,
static int vhost_sync_dirty_bitmap(struct vhost_dev *dev,
MemoryRegionSection *section,
- hwaddr start_addr,
- hwaddr end_addr)
+ hwaddr first,
+ hwaddr last)
{
int i;
+ hwaddr start_addr;
+ hwaddr end_addr;
if (!dev->log_enabled || !dev->started) {
return 0;
}
+ start_addr = section->offset_within_address_space;
+ end_addr = range_get_last(start_addr, section->size);
+ start_addr = MAX(first, start_addr);
+ end_addr = MIN(last, end_addr);
+
for (i = 0; i < dev->mem->nregions; ++i) {
struct vhost_memory_region *reg = dev->mem->regions + i;
vhost_dev_sync_region(dev, section, start_addr, end_addr,
@@ -93,10 +104,18 @@ static void vhost_log_sync(MemoryListener *listener,
{
struct vhost_dev *dev = container_of(listener, struct vhost_dev,
memory_listener);
- hwaddr start_addr = section->offset_within_address_space;
- hwaddr end_addr = start_addr + section->size;
+ vhost_sync_dirty_bitmap(dev, section, 0x0, ~0x0ULL);
+}
- vhost_sync_dirty_bitmap(dev, section, start_addr, end_addr);
+static void vhost_log_sync_range(struct vhost_dev *dev,
+ hwaddr first, hwaddr last)
+{
+ int i;
+ /* FIXME: this is N^2 in number of sections */
+ for (i = 0; i < dev->n_mem_sections; ++i) {
+ MemoryRegionSection *section = &dev->mem_sections[i];
+ vhost_sync_dirty_bitmap(dev, section, first, last);
+ }
}
/* Assign/unassign. Keep an unsorted array of non-overlapping
@@ -268,16 +287,15 @@ static inline void vhost_dev_log_resize(struct vhost_dev* dev, uint64_t size)
{
vhost_log_chunk_t *log;
uint64_t log_base;
- int r, i;
+ int r;
log = g_malloc0(size * sizeof *log);
log_base = (uint64_t)(unsigned long)log;
r = ioctl(dev->control, VHOST_SET_LOG_BASE, &log_base);
assert(r >= 0);
- for (i = 0; i < dev->n_mem_sections; ++i) {
- /* Sync only the range covered by the old log */
- vhost_sync_dirty_bitmap(dev, &dev->mem_sections[i], 0,
- dev->log_size * VHOST_LOG_CHUNK - 1);
+ /* Sync only the range covered by the old log */
+ if (dev->log_size) {
+ vhost_log_sync_range(dev, 0, dev->log_size * VHOST_LOG_CHUNK - 1);
}
if (dev->log) {
g_free(dev->log);
@@ -1014,10 +1032,7 @@ void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev)
hdev->vqs + i,
hdev->vq_index + i);
}
- for (i = 0; i < hdev->n_mem_sections; ++i) {
- vhost_sync_dirty_bitmap(hdev, &hdev->mem_sections[i],
- 0, (hwaddr)~0x0ull);
- }
+ vhost_log_sync_range(hdev, 0, ~0x0ull);
hdev->started = false;
g_free(hdev->log);
diff --git a/hw/virtio-net.c b/hw/virtio-net.c
index 573c669d15..bb2c26c483 100644
--- a/hw/virtio-net.c
+++ b/hw/virtio-net.c
@@ -44,7 +44,7 @@ typedef struct VirtIONet
VirtIODevice vdev;
uint8_t mac[ETH_ALEN];
uint16_t status;
- VirtIONetQueue vqs[MAX_QUEUE_NUM];
+ VirtIONetQueue *vqs;
VirtQueue *ctrl_vq;
NICState *nic;
uint32_t tx_timeout;
@@ -1326,8 +1326,9 @@ VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf,
n->vdev.set_status = virtio_net_set_status;
n->vdev.guest_notifier_mask = virtio_net_guest_notifier_mask;
n->vdev.guest_notifier_pending = virtio_net_guest_notifier_pending;
+ n->max_queues = MAX(conf->queues, 1);
+ n->vqs = g_malloc0(sizeof(VirtIONetQueue) * n->max_queues);
n->vqs[0].rx_vq = virtio_add_queue(&n->vdev, 256, virtio_net_handle_rx);
- n->max_queues = conf->queues;
n->curr_queues = 1;
n->vqs[0].n = n;
n->tx_timeout = net->txtimer;
@@ -1412,6 +1413,7 @@ void virtio_net_exit(VirtIODevice *vdev)
}
}
+ g_free(n->vqs);
qemu_del_nic(n->nic);
virtio_cleanup(&n->vdev);
}
diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c
index a869f535de..ba56ab2d77 100644
--- a/hw/virtio-pci.c
+++ b/hw/virtio-pci.c
@@ -975,6 +975,9 @@ static int virtio_serial_init_pci(PCIDevice *pci_dev)
if (!vdev) {
return -1;
}
+
+ /* backwards-compatibility with machines that were created with
+ DEV_NVECTORS_UNSPECIFIED */
vdev->nvectors = proxy->nvectors == DEV_NVECTORS_UNSPECIFIED
? proxy->serial.max_virtserial_ports + 1
: proxy->nvectors;
@@ -1155,7 +1158,7 @@ static const TypeInfo virtio_net_info = {
static Property virtio_serial_properties[] = {
DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
- DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, DEV_NVECTORS_UNSPECIFIED),
+ DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
DEFINE_PROP_HEX32("class", VirtIOPCIProxy, class_code, 0),
DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
DEFINE_PROP_UINT32("max_ports", VirtIOPCIProxy, serial.max_virtserial_ports, 31),
diff --git a/include/net/net.h b/include/net/net.h
index 43a045e052..cb049a16a3 100644
--- a/include/net/net.h
+++ b/include/net/net.h
@@ -72,7 +72,7 @@ struct NetClientState {
};
typedef struct NICState {
- NetClientState ncs[MAX_QUEUE_NUM];
+ NetClientState *ncs;
NICConf *conf;
void *opaque;
bool peer_deleted;
diff --git a/net/hub.c b/net/hub.c
index a24c9d17f7..df32074de0 100644
--- a/net/hub.c
+++ b/net/hub.c
@@ -338,3 +338,17 @@ void net_hub_check_clients(void)
}
}
}
+
+bool net_hub_flush(NetClientState *nc)
+{
+ NetHubPort *port;
+ NetHubPort *source_port = DO_UPCAST(NetHubPort, nc, nc);
+ int ret = 0;
+
+ QLIST_FOREACH(port, &source_port->hub->ports, next) {
+ if (port != source_port) {
+ ret += qemu_net_queue_flush(port->nc.send_queue);
+ }
+ }
+ return ret ? true : false;
+}
diff --git a/net/hub.h b/net/hub.h
index 583ada89d8..a625effe00 100644
--- a/net/hub.h
+++ b/net/hub.h
@@ -21,5 +21,6 @@ NetClientState *net_hub_add_port(int hub_id, const char *name);
NetClientState *net_hub_find_client_by_name(int hub_id, const char *name);
void net_hub_info(Monitor *mon);
void net_hub_check_clients(void);
+bool net_hub_flush(NetClientState *nc);
#endif /* NET_HUB_H */
diff --git a/net/net.c b/net/net.c
index be03a8dd14..f3d67f8322 100644
--- a/net/net.c
+++ b/net/net.c
@@ -235,23 +235,20 @@ NICState *qemu_new_nic(NetClientInfo *info,
const char *name,
void *opaque)
{
- NetClientState *nc;
NetClientState **peers = conf->peers.ncs;
NICState *nic;
- int i;
+ int i, queues = MAX(1, conf->queues);
assert(info->type == NET_CLIENT_OPTIONS_KIND_NIC);
assert(info->size >= sizeof(NICState));
- nc = qemu_new_net_client(info, peers[0], model, name);
- nc->queue_index = 0;
-
- nic = qemu_get_nic(nc);
+ nic = g_malloc0(info->size + sizeof(NetClientState) * queues);
+ nic->ncs = (void *)nic + info->size;
nic->conf = conf;
nic->opaque = opaque;
- for (i = 1; i < conf->queues; i++) {
- qemu_net_client_setup(&nic->ncs[i], info, peers[i], model, nc->name,
+ for (i = 0; i < queues; i++) {
+ qemu_net_client_setup(&nic->ncs[i], info, peers[i], model, name,
NULL);
nic->ncs[i].queue_index = i;
}
@@ -261,7 +258,7 @@ NICState *qemu_new_nic(NetClientInfo *info,
NetClientState *qemu_get_subqueue(NICState *nic, int queue_index)
{
- return &nic->ncs[queue_index];
+ return nic->ncs + queue_index;
}
NetClientState *qemu_get_queue(NICState *nic)
@@ -273,7 +270,7 @@ NICState *qemu_get_nic(NetClientState *nc)
{
NetClientState *nc0 = nc - nc->queue_index;
- return DO_UPCAST(NICState, ncs[0], nc0);
+ return (NICState *)((void *)nc0 - nc->info->size);
}
void *qemu_get_nic_opaque(NetClientState *nc)
@@ -368,6 +365,8 @@ void qemu_del_nic(NICState *nic)
qemu_cleanup_net_client(nc);
qemu_free_net_client(nc);
}
+
+ g_free(nic);
}
void qemu_foreach_nic(qemu_nic_foreach func, void *opaque)
@@ -441,6 +440,12 @@ void qemu_flush_queued_packets(NetClientState *nc)
{
nc->receive_disabled = 0;
+ if (nc->peer && nc->peer->info->type == NET_CLIENT_OPTIONS_KIND_HUBPORT) {
+ if (net_hub_flush(nc->peer)) {
+ qemu_notify_event();
+ }
+ return;
+ }
if (qemu_net_queue_flush(nc->send_queue)) {
/* We emptied the queue successfully, signal to the IO thread to repoll
* the file descriptor (for tap, for example).
diff --git a/net/queue.c b/net/queue.c
index 6eaf5b63c0..859d02a136 100644
--- a/net/queue.c
+++ b/net/queue.c
@@ -50,6 +50,8 @@ struct NetPacket {
struct NetQueue {
void *opaque;
+ uint32_t nq_maxlen;
+ uint32_t nq_count;
QTAILQ_HEAD(packets, NetPacket) packets;
@@ -63,6 +65,8 @@ NetQueue *qemu_new_net_queue(void *opaque)
queue = g_malloc0(sizeof(NetQueue));
queue->opaque = opaque;
+ queue->nq_maxlen = 10000;
+ queue->nq_count = 0;
QTAILQ_INIT(&queue->packets);
@@ -92,6 +96,9 @@ static void qemu_net_queue_append(NetQueue *queue,
{
NetPacket *packet;
+ if (queue->nq_count >= queue->nq_maxlen && !sent_cb) {
+ return; /* drop if queue full and no callback */
+ }
packet = g_malloc(sizeof(NetPacket) + size);
packet->sender = sender;
packet->flags = flags;
@@ -99,6 +106,7 @@ static void qemu_net_queue_append(NetQueue *queue,
packet->sent_cb = sent_cb;
memcpy(packet->data, buf, size);
+ queue->nq_count++;
QTAILQ_INSERT_TAIL(&queue->packets, packet, entry);
}
@@ -113,6 +121,9 @@ static void qemu_net_queue_append_iov(NetQueue *queue,
size_t max_len = 0;
int i;
+ if (queue->nq_count >= queue->nq_maxlen && !sent_cb) {
+ return; /* drop if queue full and no callback */
+ }
for (i = 0; i < iovcnt; i++) {
max_len += iov[i].iov_len;
}
@@ -130,6 +141,7 @@ static void qemu_net_queue_append_iov(NetQueue *queue,
packet->size += len;
}
+ queue->nq_count++;
QTAILQ_INSERT_TAIL(&queue->packets, packet, entry);
}
@@ -220,6 +232,7 @@ void qemu_net_queue_purge(NetQueue *queue, NetClientState *from)
QTAILQ_FOREACH_SAFE(packet, &queue->packets, entry, next) {
if (packet->sender == from) {
QTAILQ_REMOVE(&queue->packets, packet, entry);
+ queue->nq_count--;
g_free(packet);
}
}
@@ -233,6 +246,7 @@ bool qemu_net_queue_flush(NetQueue *queue)
packet = QTAILQ_FIRST(&queue->packets);
QTAILQ_REMOVE(&queue->packets, packet, entry);
+ queue->nq_count--;
ret = qemu_net_queue_deliver(queue,
packet->sender,
@@ -240,6 +254,7 @@ bool qemu_net_queue_flush(NetQueue *queue)
packet->data,
packet->size);
if (ret == 0) {
+ queue->nq_count++;
QTAILQ_INSERT_HEAD(&queue->packets, packet, entry);
return false;
}
diff --git a/net/tap-linux.c b/net/tap-linux.c
index a9531892a6..36c09e24d8 100644
--- a/net/tap-linux.c
+++ b/net/tap-linux.c
@@ -42,6 +42,7 @@ int tap_open(char *ifname, int ifname_size, int *vnet_hdr,
struct ifreq ifr;
int fd, ret;
int len = sizeof(struct virtio_net_hdr);
+ unsigned int features;
TFR(fd = open(PATH_NET_TUN, O_RDWR));
if (fd < 0) {
@@ -51,9 +52,12 @@ int tap_open(char *ifname, int ifname_size, int *vnet_hdr,
memset(&ifr, 0, sizeof(ifr));
ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
- if (*vnet_hdr) {
- unsigned int features;
+ if (ioctl(fd, TUNGETFEATURES, &features) == 0 &&
+ features & IFF_ONE_QUEUE) {
+ ifr.ifr_flags |= IFF_ONE_QUEUE;
+ }
+ if (*vnet_hdr) {
if (ioctl(fd, TUNGETFEATURES, &features) == 0 &&
features & IFF_VNET_HDR) {
*vnet_hdr = 1;
@@ -78,8 +82,6 @@ int tap_open(char *ifname, int ifname_size, int *vnet_hdr,
}
if (mq_required) {
- unsigned int features;
-
if ((ioctl(fd, TUNGETFEATURES, &features) != 0) ||
!(features & IFF_MULTI_QUEUE)) {
error_report("multiqueue required, but no kernel "
diff --git a/net/tap-linux.h b/net/tap-linux.h
index 65087e1419..1cf35d41bd 100644
--- a/net/tap-linux.h
+++ b/net/tap-linux.h
@@ -34,10 +34,11 @@
#endif
/* TUNSETIFF ifr flags */
-#define IFF_TAP 0x0002
-#define IFF_NO_PI 0x1000
-#define IFF_VNET_HDR 0x4000
-#define IFF_MULTI_QUEUE 0x0100
+#define IFF_TAP 0x0002
+#define IFF_NO_PI 0x1000
+#define IFF_ONE_QUEUE 0x2000
+#define IFF_VNET_HDR 0x4000
+#define IFF_MULTI_QUEUE 0x0100
#define IFF_ATTACH_QUEUE 0x0200
#define IFF_DETACH_QUEUE 0x0400
diff --git a/net/tap.c b/net/tap.c
index 48c254ed85..daab350efc 100644
--- a/net/tap.c
+++ b/net/tap.c
@@ -693,6 +693,13 @@ int net_init_tap(const NetClientOptions *opts, const char *name,
queues = tap->has_queues ? tap->queues : 1;
vhostfdname = tap->has_vhostfd ? tap->vhostfd : NULL;
+ /* QEMU vlans does not support multiqueue tap, in this case peer is set.
+ * For -netdev, peer is always NULL. */
+ if (peer && (tap->has_queues || tap->has_fds || tap->has_vhostfds)) {
+ error_report("Multiqueue tap cannnot be used with QEMU vlans");
+ return -1;
+ }
+
if (tap->has_fd) {
if (tap->has_ifname || tap->has_script || tap->has_downscript ||
tap->has_vnet_hdr || tap->has_helper || tap->has_queues ||
diff --git a/pc-bios/bios.bin b/pc-bios/bios.bin
index ab5dd9db6a..ec9eeb12c6 100644
--- a/pc-bios/bios.bin
+++ b/pc-bios/bios.bin
Binary files differ
diff --git a/qemu-options.hx b/qemu-options.hx
index f598d7a395..6f9334a97f 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -1408,7 +1408,8 @@ DEF("netdev", HAS_ARG, QEMU_OPTION_netdev,
#ifdef CONFIG_VDE
"vde|"
#endif
- "socket],id=str[,option][,option][,...]\n", QEMU_ARCH_ALL)
+ "socket|"
+ "hubport],id=str[,option][,option][,...]\n", QEMU_ARCH_ALL)
STEXI
@item -net nic[,vlan=@var{n}][,macaddr=@var{mac}][,model=@var{type}] [,name=@var{name}][,addr=@var{addr}][,vectors=@var{v}]
@findex -net
@@ -1730,6 +1731,14 @@ vde_switch -F -sock /tmp/myswitch
qemu-system-i386 linux.img -net nic -net vde,sock=/tmp/myswitch
@end example
+@item -netdev hubport,id=@var{id},hubid=@var{hubid}
+
+Create a hub port on QEMU "vlan" @var{hubid}.
+
+The hubport netdev lets you connect a NIC to a QEMU "vlan" instead of a single
+netdev. @code{-net} and @code{-device} with parameter @option{vlan} create the
+required hub automatically.
+
@item -net dump[,vlan=@var{n}][,file=@var{file}][,len=@var{len}]
Dump network traffic on VLAN @var{n} to file @var{file} (@file{qemu-vlan0.pcap} by default).
At most @var{len} bytes (64k by default) per packet are stored. The file format is
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 799adea1b7..95022e259f 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -822,7 +822,7 @@ Example:
-> { "execute": "netdev_add", "arguments": { "type": "user", "id": "netdev1" } }
<- { "return": {} }
-Note: The supported device options are the same ones supported by the '-net'
+Note: The supported device options are the same ones supported by the '-netdev'
command-line argument, which are listed in the '-help' output or QEMU's
manual
diff --git a/roms/seabios b/roms/seabios
-Subproject 4bd8aebf3534e10d9aa21e820903f2cf9120708
+Subproject 88cb66ea542906ffff8a80ef397b9e3adbb3311
diff --git a/target-i386/cpu.c b/target-i386/cpu.c
index 5582e5f4e6..8fb736a5b4 100644
--- a/target-i386/cpu.c
+++ b/target-i386/cpu.c
@@ -2088,7 +2088,8 @@ static void x86_cpu_apic_init(X86CPU *cpu, Error **errp)
/* NOTE: the APIC is directly connected to the CPU - it is not
on the global memory bus. */
/* XXX: what if the base changes? */
- sysbus_mmio_map(SYS_BUS_DEVICE(env->apic_state), 0, MSI_ADDR_BASE);
+ sysbus_mmio_map_overlap(SYS_BUS_DEVICE(env->apic_state), 0,
+ MSI_ADDR_BASE, 0x1000);
apic_mapped = 1;
}
}