aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hw/i386/pc_piix.c16
-rw-r--r--hw/i386/pc_q35.c15
-rw-r--r--hw/net/e1000.c131
-rw-r--r--hw/net/ne2000.c2
-rw-r--r--hw/net/vmxnet3.h2
-rw-r--r--include/hw/i386/pc.h8
-rw-r--r--include/net/net.h2
-rw-r--r--net/hub.c2
-rw-r--r--net/net.c14
-rw-r--r--net/tap-bsd.c11
10 files changed, 174 insertions, 29 deletions
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index 275e39595d..147d08cf23 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -339,14 +339,25 @@ static void pc_xen_hvm_init(QEMUMachineInitArgs *args)
.desc = "Standard PC (i440FX + PIIX, 1996)", \
.hot_add_cpu = pc_hot_add_cpu
+#define PC_I440FX_1_7_MACHINE_OPTIONS PC_I440FX_MACHINE_OPTIONS
+static QEMUMachine pc_i440fx_machine_v1_7 = {
+ PC_I440FX_1_7_MACHINE_OPTIONS,
+ .name = "pc-i440fx-1.7",
+ .alias = "pc",
+ .init = pc_init_pci,
+ .is_default = 1,
+};
+
#define PC_I440FX_1_6_MACHINE_OPTIONS PC_I440FX_MACHINE_OPTIONS
static QEMUMachine pc_i440fx_machine_v1_6 = {
PC_I440FX_1_6_MACHINE_OPTIONS,
.name = "pc-i440fx-1.6",
- .alias = "pc",
.init = pc_init_pci_1_6,
- .is_default = 1,
+ .compat_props = (GlobalProperty[]) {
+ PC_COMPAT_1_6,
+ { /* end of list */ }
+ },
};
static QEMUMachine pc_i440fx_machine_v1_5 = {
@@ -735,6 +746,7 @@ static QEMUMachine xenfv_machine = {
static void pc_machine_init(void)
{
+ qemu_register_machine(&pc_i440fx_machine_v1_7);
qemu_register_machine(&pc_i440fx_machine_v1_6);
qemu_register_machine(&pc_i440fx_machine_v1_5);
qemu_register_machine(&pc_i440fx_machine_v1_4);
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index d7b7c3bf9a..b4b5155d89 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -258,13 +258,25 @@ static void pc_q35_init_1_4(QEMUMachineInitArgs *args)
.desc = "Standard PC (Q35 + ICH9, 2009)", \
.hot_add_cpu = pc_hot_add_cpu
+#define PC_Q35_1_7_MACHINE_OPTIONS PC_Q35_MACHINE_OPTIONS
+
+static QEMUMachine pc_q35_machine_v1_7 = {
+ PC_Q35_1_7_MACHINE_OPTIONS,
+ .name = "pc-q35-1.7",
+ .alias = "q35",
+ .init = pc_q35_init,
+};
+
#define PC_Q35_1_6_MACHINE_OPTIONS PC_Q35_MACHINE_OPTIONS
static QEMUMachine pc_q35_machine_v1_6 = {
PC_Q35_1_6_MACHINE_OPTIONS,
.name = "pc-q35-1.6",
- .alias = "q35",
.init = pc_q35_init_1_6,
+ .compat_props = (GlobalProperty[]) {
+ PC_COMPAT_1_6,
+ { /* end of list */ }
+ },
};
static QEMUMachine pc_q35_machine_v1_5 = {
@@ -293,6 +305,7 @@ static QEMUMachine pc_q35_machine_v1_4 = {
static void pc_q35_machine_init(void)
{
+ qemu_register_machine(&pc_q35_machine_v1_7);
qemu_register_machine(&pc_q35_machine_v1_6);
qemu_register_machine(&pc_q35_machine_v1_5);
qemu_register_machine(&pc_q35_machine_v1_4);
diff --git a/hw/net/e1000.c b/hw/net/e1000.c
index f5ebed46ab..d3f274cc28 100644
--- a/hw/net/e1000.c
+++ b/hw/net/e1000.c
@@ -135,9 +135,16 @@ typedef struct E1000State_st {
QEMUTimer *autoneg_timer;
+ QEMUTimer *mit_timer; /* Mitigation timer. */
+ bool mit_timer_on; /* Mitigation timer is running. */
+ bool mit_irq_level; /* Tracks interrupt pin level. */
+ uint32_t mit_ide; /* Tracks E1000_TXD_CMD_IDE bit. */
+
/* Compatibility flags for migration to/from qemu 1.3.0 and older */
#define E1000_FLAG_AUTONEG_BIT 0
+#define E1000_FLAG_MIT_BIT 1
#define E1000_FLAG_AUTONEG (1 << E1000_FLAG_AUTONEG_BIT)
+#define E1000_FLAG_MIT (1 << E1000_FLAG_MIT_BIT)
uint32_t compat_flags;
} E1000State;
@@ -158,7 +165,8 @@ enum {
defreg(TORH), defreg(TORL), defreg(TOTH), defreg(TOTL),
defreg(TPR), defreg(TPT), defreg(TXDCTL), defreg(WUFC),
defreg(RA), defreg(MTA), defreg(CRCERRS),defreg(VFTA),
- defreg(VET),
+ defreg(VET), defreg(RDTR), defreg(RADV), defreg(TADV),
+ defreg(ITR),
};
static void
@@ -245,10 +253,21 @@ static const uint32_t mac_reg_init[] = {
E1000_MANC_RMCP_EN,
};
+/* Helper function, *curr == 0 means the value is not set */
+static inline void
+mit_update_delay(uint32_t *curr, uint32_t value)
+{
+ if (value && (*curr == 0 || value < *curr)) {
+ *curr = value;
+ }
+}
+
static void
set_interrupt_cause(E1000State *s, int index, uint32_t val)
{
PCIDevice *d = PCI_DEVICE(s);
+ uint32_t pending_ints;
+ uint32_t mit_delay;
if (val && (E1000_DEVID >= E1000_DEV_ID_82547EI_MOBILE)) {
/* Only for 8257x */
@@ -266,7 +285,57 @@ set_interrupt_cause(E1000State *s, int index, uint32_t val)
*/
s->mac_reg[ICS] = val;
- qemu_set_irq(d->irq[0], (s->mac_reg[IMS] & s->mac_reg[ICR]) != 0);
+ pending_ints = (s->mac_reg[IMS] & s->mac_reg[ICR]);
+ if (!s->mit_irq_level && pending_ints) {
+ /*
+ * Here we detect a potential raising edge. We postpone raising the
+ * interrupt line if we are inside the mitigation delay window
+ * (s->mit_timer_on == 1).
+ * We provide a partial implementation of interrupt mitigation,
+ * emulating only RADV, TADV and ITR (lower 16 bits, 1024ns units for
+ * RADV and TADV, 256ns units for ITR). RDTR is only used to enable
+ * RADV; relative timers based on TIDV and RDTR are not implemented.
+ */
+ if (s->mit_timer_on) {
+ return;
+ }
+ if (s->compat_flags & E1000_FLAG_MIT) {
+ /* Compute the next mitigation delay according to pending
+ * interrupts and the current values of RADV (provided
+ * RDTR!=0), TADV and ITR.
+ * Then rearm the timer.
+ */
+ mit_delay = 0;
+ if (s->mit_ide &&
+ (pending_ints & (E1000_ICR_TXQE | E1000_ICR_TXDW))) {
+ mit_update_delay(&mit_delay, s->mac_reg[TADV] * 4);
+ }
+ if (s->mac_reg[RDTR] && (pending_ints & E1000_ICS_RXT0)) {
+ mit_update_delay(&mit_delay, s->mac_reg[RADV] * 4);
+ }
+ mit_update_delay(&mit_delay, s->mac_reg[ITR]);
+
+ if (mit_delay) {
+ s->mit_timer_on = 1;
+ timer_mod(s->mit_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
+ mit_delay * 256);
+ }
+ s->mit_ide = 0;
+ }
+ }
+
+ s->mit_irq_level = (pending_ints != 0);
+ qemu_set_irq(d->irq[0], s->mit_irq_level);
+}
+
+static void
+e1000_mit_timer(void *opaque)
+{
+ E1000State *s = opaque;
+
+ s->mit_timer_on = 0;
+ /* Call set_interrupt_cause to update the irq level (if necessary). */
+ set_interrupt_cause(s, 0, s->mac_reg[ICR]);
}
static void
@@ -307,6 +376,10 @@ static void e1000_reset(void *opaque)
int i;
timer_del(d->autoneg_timer);
+ timer_del(d->mit_timer);
+ d->mit_timer_on = 0;
+ d->mit_irq_level = 0;
+ d->mit_ide = 0;
memset(d->phy_reg, 0, sizeof d->phy_reg);
memmove(d->phy_reg, phy_reg_init, sizeof phy_reg_init);
memset(d->mac_reg, 0, sizeof d->mac_reg);
@@ -572,6 +645,7 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp)
struct e1000_context_desc *xp = (struct e1000_context_desc *)dp;
struct e1000_tx *tp = &s->tx;
+ s->mit_ide |= (txd_lower & E1000_TXD_CMD_IDE);
if (dtype == E1000_TXD_CMD_DEXT) { // context descriptor
op = le32_to_cpu(xp->cmd_and_length);
tp->ipcss = xp->lower_setup.ip_fields.ipcss;
@@ -1047,7 +1121,8 @@ static uint32_t (*macreg_readops[])(E1000State *, int) = {
getreg(TORL), getreg(TOTL), getreg(IMS), getreg(TCTL),
getreg(RDH), getreg(RDT), getreg(VET), getreg(ICS),
getreg(TDBAL), getreg(TDBAH), getreg(RDBAH), getreg(RDBAL),
- getreg(TDLEN), getreg(RDLEN),
+ getreg(TDLEN), getreg(RDLEN), getreg(RDTR), getreg(RADV),
+ getreg(TADV), getreg(ITR),
[TOTH] = mac_read_clr8, [TORH] = mac_read_clr8, [GPRC] = mac_read_clr4,
[GPTC] = mac_read_clr4, [TPR] = mac_read_clr4, [TPT] = mac_read_clr4,
@@ -1069,6 +1144,8 @@ static void (*macreg_writeops[])(E1000State *, int, uint32_t) = {
[TDH] = set_16bit, [RDH] = set_16bit, [RDT] = set_rdt,
[IMC] = set_imc, [IMS] = set_ims, [ICR] = set_icr,
[EECD] = set_eecd, [RCTL] = set_rx_control, [CTRL] = set_ctrl,
+ [RDTR] = set_16bit, [RADV] = set_16bit, [TADV] = set_16bit,
+ [ITR] = set_16bit,
[RA ... RA+31] = &mac_writereg,
[MTA ... MTA+127] = &mac_writereg,
[VFTA ... VFTA+127] = &mac_writereg,
@@ -1150,6 +1227,11 @@ static void e1000_pre_save(void *opaque)
E1000State *s = opaque;
NetClientState *nc = qemu_get_queue(s->nic);
+ /* If the mitigation timer is active, emulate a timeout now. */
+ if (s->mit_timer_on) {
+ e1000_mit_timer(s);
+ }
+
if (!(s->compat_flags & E1000_FLAG_AUTONEG)) {
return;
}
@@ -1171,6 +1253,14 @@ static int e1000_post_load(void *opaque, int version_id)
E1000State *s = opaque;
NetClientState *nc = qemu_get_queue(s->nic);
+ if (!(s->compat_flags & E1000_FLAG_MIT)) {
+ s->mac_reg[ITR] = s->mac_reg[RDTR] = s->mac_reg[RADV] =
+ s->mac_reg[TADV] = 0;
+ s->mit_irq_level = false;
+ }
+ s->mit_ide = 0;
+ s->mit_timer_on = false;
+
/* nc.link_down can't be migrated, so infer link_down according
* to link status bit in mac_reg[STATUS].
* Alternatively, restart link negotiation if it was in progress. */
@@ -1190,6 +1280,28 @@ static int e1000_post_load(void *opaque, int version_id)
return 0;
}
+static bool e1000_mit_state_needed(void *opaque)
+{
+ E1000State *s = opaque;
+
+ return s->compat_flags & E1000_FLAG_MIT;
+}
+
+static const VMStateDescription vmstate_e1000_mit_state = {
+ .name = "e1000/mit_state",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(mac_reg[RDTR], E1000State),
+ VMSTATE_UINT32(mac_reg[RADV], E1000State),
+ VMSTATE_UINT32(mac_reg[TADV], E1000State),
+ VMSTATE_UINT32(mac_reg[ITR], E1000State),
+ VMSTATE_BOOL(mit_irq_level, E1000State),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static const VMStateDescription vmstate_e1000 = {
.name = "e1000",
.version_id = 2,
@@ -1267,6 +1379,14 @@ static const VMStateDescription vmstate_e1000 = {
VMSTATE_UINT32_SUB_ARRAY(mac_reg, E1000State, MTA, 128),
VMSTATE_UINT32_SUB_ARRAY(mac_reg, E1000State, VFTA, 128),
VMSTATE_END_OF_LIST()
+ },
+ .subsections = (VMStateSubsection[]) {
+ {
+ .vmsd = &vmstate_e1000_mit_state,
+ .needed = e1000_mit_state_needed,
+ }, {
+ /* empty */
+ }
}
};
@@ -1316,6 +1436,8 @@ pci_e1000_uninit(PCIDevice *dev)
timer_del(d->autoneg_timer);
timer_free(d->autoneg_timer);
+ timer_del(d->mit_timer);
+ timer_free(d->mit_timer);
memory_region_destroy(&d->mmio);
memory_region_destroy(&d->io);
qemu_del_nic(d->nic);
@@ -1371,6 +1493,7 @@ static int pci_e1000_init(PCIDevice *pci_dev)
add_boot_device_path(d->conf.bootindex, dev, "/ethernet-phy@0");
d->autoneg_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, e1000_autoneg_timer, d);
+ d->mit_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, e1000_mit_timer, d);
return 0;
}
@@ -1385,6 +1508,8 @@ static Property e1000_properties[] = {
DEFINE_NIC_PROPERTIES(E1000State, conf),
DEFINE_PROP_BIT("autonegotiation", E1000State,
compat_flags, E1000_FLAG_AUTONEG_BIT, true),
+ DEFINE_PROP_BIT("mitigation", E1000State,
+ compat_flags, E1000_FLAG_MIT_BIT, true),
DEFINE_PROP_END_OF_LIST(),
};
diff --git a/hw/net/ne2000.c b/hw/net/ne2000.c
index 31afd28c7c..c96125895e 100644
--- a/hw/net/ne2000.c
+++ b/hw/net/ne2000.c
@@ -693,7 +693,7 @@ static void ne2000_write(void *opaque, hwaddr addr,
static const MemoryRegionOps ne2000_ops = {
.read = ne2000_read,
.write = ne2000_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
+ .endianness = DEVICE_LITTLE_ENDIAN,
};
/***********************************************************/
diff --git a/hw/net/vmxnet3.h b/hw/net/vmxnet3.h
index 4eae7c76be..f987d71269 100644
--- a/hw/net/vmxnet3.h
+++ b/hw/net/vmxnet3.h
@@ -34,7 +34,6 @@
#define __le16 uint16_t
#define __le32 uint32_t
#define __le64 uint64_t
-#define __packed QEMU_PACKED
#if defined(HOST_WORDS_BIGENDIAN)
#define __BIG_ENDIAN_BITFIELD
@@ -749,7 +748,6 @@ struct Vmxnet3_DriverShared {
#undef __le16
#undef __le32
#undef __le64
-#undef __packed
#if defined(HOST_WORDS_BIGENDIAN)
#undef __BIG_ENDIAN_BITFIELD
#endif
diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
index 7fb04d8cd8..9b2ddc4acc 100644
--- a/include/hw/i386/pc.h
+++ b/include/hw/i386/pc.h
@@ -225,7 +225,15 @@ void pvpanic_init(ISABus *bus);
int e820_add_entry(uint64_t, uint64_t, uint32_t);
+#define PC_COMPAT_1_6 \
+ {\
+ .driver = "e1000",\
+ .property = "mitigation",\
+ .value = "off",\
+ }
+
#define PC_COMPAT_1_5 \
+ PC_COMPAT_1_6, \
{\
.driver = "Conroe-" TYPE_X86_CPU,\
.property = "model",\
diff --git a/include/net/net.h b/include/net/net.h
index 30e4b04066..11e146888b 100644
--- a/include/net/net.h
+++ b/include/net/net.h
@@ -69,7 +69,7 @@ struct NetClientState {
int link_down;
QTAILQ_ENTRY(NetClientState) next;
NetClientState *peer;
- NetQueue *send_queue;
+ NetQueue *incoming_queue;
char *model;
char *name;
char info_str[256];
diff --git a/net/hub.c b/net/hub.c
index df32074de0..33a99c99ef 100644
--- a/net/hub.c
+++ b/net/hub.c
@@ -347,7 +347,7 @@ bool net_hub_flush(NetClientState *nc)
QLIST_FOREACH(port, &source_port->hub->ports, next) {
if (port != source_port) {
- ret += qemu_net_queue_flush(port->nc.send_queue);
+ ret += qemu_net_queue_flush(port->nc.incoming_queue);
}
}
return ret ? true : false;
diff --git a/net/net.c b/net/net.c
index 114859267e..c330c9a3a8 100644
--- a/net/net.c
+++ b/net/net.c
@@ -207,7 +207,7 @@ static void qemu_net_client_setup(NetClientState *nc,
}
QTAILQ_INSERT_TAIL(&net_clients, nc, next);
- nc->send_queue = qemu_new_net_queue(nc);
+ nc->incoming_queue = qemu_new_net_queue(nc);
nc->destructor = destructor;
}
@@ -289,8 +289,8 @@ static void qemu_cleanup_net_client(NetClientState *nc)
static void qemu_free_net_client(NetClientState *nc)
{
- if (nc->send_queue) {
- qemu_del_net_queue(nc->send_queue);
+ if (nc->incoming_queue) {
+ qemu_del_net_queue(nc->incoming_queue);
}
if (nc->peer) {
nc->peer->peer = NULL;
@@ -431,7 +431,7 @@ void qemu_purge_queued_packets(NetClientState *nc)
return;
}
- qemu_net_queue_purge(nc->peer->send_queue, nc);
+ qemu_net_queue_purge(nc->peer->incoming_queue, nc);
}
void qemu_flush_queued_packets(NetClientState *nc)
@@ -444,7 +444,7 @@ void qemu_flush_queued_packets(NetClientState *nc)
}
return;
}
- if (qemu_net_queue_flush(nc->send_queue)) {
+ if (qemu_net_queue_flush(nc->incoming_queue)) {
/* We emptied the queue successfully, signal to the IO thread to repoll
* the file descriptor (for tap, for example).
*/
@@ -468,7 +468,7 @@ static ssize_t qemu_send_packet_async_with_flags(NetClientState *sender,
return size;
}
- queue = sender->peer->send_queue;
+ queue = sender->peer->incoming_queue;
return qemu_net_queue_send(queue, sender, flags, buf, size, sent_cb);
}
@@ -543,7 +543,7 @@ ssize_t qemu_sendv_packet_async(NetClientState *sender,
return iov_size(iov, iovcnt);
}
- queue = sender->peer->send_queue;
+ queue = sender->peer->incoming_queue;
return qemu_net_queue_send_iov(queue, sender,
QEMU_NET_PACKET_FLAG_NONE,
diff --git a/net/tap-bsd.c b/net/tap-bsd.c
index f61d580963..90f8a02276 100644
--- a/net/tap-bsd.c
+++ b/net/tap-bsd.c
@@ -44,8 +44,6 @@ int tap_open(char *ifname, int ifname_size, int *vnet_hdr,
struct stat s;
#endif
-#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \
- defined(__OpenBSD__) || defined(__APPLE__)
/* if no ifname is given, always start the search from tap0/tun0. */
int i;
char dname[100];
@@ -76,15 +74,6 @@ int tap_open(char *ifname, int ifname_size, int *vnet_hdr,
dname, strerror(errno));
return -1;
}
-#else
- TFR(fd = open("/dev/tap", O_RDWR));
- if (fd < 0) {
- fprintf(stderr,
- "warning: could not open /dev/tap: no virtual network emulation: %s\n",
- strerror(errno));
- return -1;
- }
-#endif
#ifdef TAPGIFNAME
if (ioctl(fd, TAPGIFNAME, (void *)&ifr) < 0) {