aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
Diffstat (limited to 'hw')
-rw-r--r--hw/core/qdev-properties-system.c54
-rw-r--r--hw/net/virtio-net.c118
-rw-r--r--hw/pci-host/mv64361.c1
-rw-r--r--hw/ppc/pegasos2.c30
-rw-r--r--hw/ppc/pnv_core.c11
-rw-r--r--hw/ppc/pnv_nest_pervasive.c2
-rw-r--r--hw/ppc/spapr.c2
-rw-r--r--hw/ppc/spapr_cpu_core.c1
-rw-r--r--hw/virtio/virtio.c7
9 files changed, 155 insertions, 71 deletions
diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c
index a61c5ee..22ea1ed 100644
--- a/hw/core/qdev-properties-system.c
+++ b/hw/core/qdev-properties-system.c
@@ -816,39 +816,57 @@ static void set_pci_devfn(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
Property *prop = opaque;
+ g_autofree GenericAlternate *alt;
int32_t value, *ptr = object_field_prop_ptr(obj, prop);
unsigned int slot, fn, n;
- char *str;
+ g_autofree char *str = NULL;
+
+ if (!visit_start_alternate(v, name, &alt, sizeof(*alt), errp)) {
+ return;
+ }
+
+ switch (alt->type) {
+ case QTYPE_QSTRING:
+ if (!visit_type_str(v, name, &str, errp)) {
+ goto out;
+ }
- if (!visit_type_str(v, name, &str, NULL)) {
+ if (sscanf(str, "%x.%x%n", &slot, &fn, &n) != 2) {
+ fn = 0;
+ if (sscanf(str, "%x%n", &slot, &n) != 1) {
+ goto invalid;
+ }
+ }
+ if (str[n] != '\0' || fn > 7 || slot > 31) {
+ goto invalid;
+ }
+ *ptr = slot << 3 | fn;
+ break;
+
+ case QTYPE_QNUM:
if (!visit_type_int32(v, name, &value, errp)) {
- return;
+ goto out;
}
if (value < -1 || value > 255) {
error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
name ? name : "null", "a value between -1 and 255");
- return;
+ goto out;
}
*ptr = value;
- return;
- }
+ break;
- if (sscanf(str, "%x.%x%n", &slot, &fn, &n) != 2) {
- fn = 0;
- if (sscanf(str, "%x%n", &slot, &n) != 1) {
- goto invalid;
- }
- }
- if (str[n] != '\0' || fn > 7 || slot > 31) {
- goto invalid;
+ default:
+ error_setg(errp, "Invalid parameter type for '%s', expected int or str",
+ name ? name : "null");
+ goto out;
}
- *ptr = slot << 3 | fn;
- g_free(str);
- return;
+
+ goto out;
invalid:
error_set_from_qdev_prop_error(errp, EINVAL, obj, name, str);
- g_free(str);
+out:
+ visit_end_alternate(v, (void **) &alt);
}
static int print_pci_devfn(Object *obj, Property *prop, char *dest,
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index 75b4a28..6e8c51a 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -1695,38 +1695,44 @@ static void virtio_net_hdr_swap(VirtIODevice *vdev, struct virtio_net_hdr *hdr)
* cache.
*/
static void work_around_broken_dhclient(struct virtio_net_hdr *hdr,
- uint8_t *buf, size_t size)
+ size_t *hdr_len, const uint8_t *buf,
+ size_t buf_size, size_t *buf_offset)
{
+ size_t csum_size = ETH_HLEN + sizeof(struct ip_header) +
+ sizeof(struct udp_header);
+
+ buf += *buf_offset;
+ buf_size -= *buf_offset;
+
if ((hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) && /* missing csum */
- (size > 27 && size < 1500) && /* normal sized MTU */
+ (buf_size >= csum_size && buf_size < 1500) && /* normal sized MTU */
(buf[12] == 0x08 && buf[13] == 0x00) && /* ethertype == IPv4 */
(buf[23] == 17) && /* ip.protocol == UDP */
(buf[34] == 0 && buf[35] == 67)) { /* udp.srcport == bootps */
- net_checksum_calculate(buf, size, CSUM_UDP);
+ memcpy((uint8_t *)hdr + *hdr_len, buf, csum_size);
+ net_checksum_calculate((uint8_t *)hdr + *hdr_len, csum_size, CSUM_UDP);
hdr->flags &= ~VIRTIO_NET_HDR_F_NEEDS_CSUM;
+ *hdr_len += csum_size;
+ *buf_offset += csum_size;
}
}
-static void receive_header(VirtIONet *n, const struct iovec *iov, int iov_cnt,
- const void *buf, size_t size)
+static size_t receive_header(VirtIONet *n, struct virtio_net_hdr *hdr,
+ const void *buf, size_t buf_size,
+ size_t *buf_offset)
{
- if (n->has_vnet_hdr) {
- /* FIXME this cast is evil */
- void *wbuf = (void *)buf;
- work_around_broken_dhclient(wbuf, wbuf + n->host_hdr_len,
- size - n->host_hdr_len);
+ size_t hdr_len = n->guest_hdr_len;
- if (n->needs_vnet_hdr_swap) {
- virtio_net_hdr_swap(VIRTIO_DEVICE(n), wbuf);
- }
- iov_from_buf(iov, iov_cnt, 0, buf, sizeof(struct virtio_net_hdr));
- } else {
- struct virtio_net_hdr hdr = {
- .flags = 0,
- .gso_type = VIRTIO_NET_HDR_GSO_NONE
- };
- iov_from_buf(iov, iov_cnt, 0, &hdr, sizeof hdr);
+ memcpy(hdr, buf, sizeof(struct virtio_net_hdr));
+
+ *buf_offset = n->host_hdr_len;
+ work_around_broken_dhclient(hdr, &hdr_len, buf, buf_size, buf_offset);
+
+ if (n->needs_vnet_hdr_swap) {
+ virtio_net_hdr_swap(VIRTIO_DEVICE(n), hdr);
}
+
+ return hdr_len;
}
static int receive_filter(VirtIONet *n, const uint8_t *buf, int size)
@@ -1894,33 +1900,42 @@ static int virtio_net_process_rss(NetClientState *nc, const uint8_t *buf,
return (index == new_index) ? -1 : new_index;
}
+typedef struct Header {
+ struct virtio_net_hdr_v1_hash virtio_net;
+ struct eth_header eth;
+ struct ip_header ip;
+ struct udp_header udp;
+} Header;
+
static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf,
- size_t size, bool no_rss)
+ size_t size)
{
VirtIONet *n = qemu_get_nic_opaque(nc);
- VirtIONetQueue *q = virtio_net_get_subqueue(nc);
+ VirtIONetQueue *q;
VirtIODevice *vdev = VIRTIO_DEVICE(n);
VirtQueueElement *elems[VIRTQUEUE_MAX_SIZE];
size_t lens[VIRTQUEUE_MAX_SIZE];
struct iovec mhdr_sg[VIRTQUEUE_MAX_SIZE];
- struct virtio_net_hdr_v1_hash extra_hdr;
+ Header hdr;
unsigned mhdr_cnt = 0;
size_t offset, i, guest_offset, j;
ssize_t err;
- if (!virtio_net_can_receive(nc)) {
- return -1;
- }
+ memset(&hdr.virtio_net, 0, sizeof(hdr.virtio_net));
- if (!no_rss && n->rss_data.enabled && n->rss_data.enabled_software_rss) {
- int index = virtio_net_process_rss(nc, buf, size, &extra_hdr);
+ if (n->rss_data.enabled && n->rss_data.enabled_software_rss) {
+ int index = virtio_net_process_rss(nc, buf, size, &hdr.virtio_net);
if (index >= 0) {
- NetClientState *nc2 =
- qemu_get_subqueue(n->nic, index % n->curr_queue_pairs);
- return virtio_net_receive_rcu(nc2, buf, size, true);
+ nc = qemu_get_subqueue(n->nic, index % n->curr_queue_pairs);
}
}
+ if (!virtio_net_can_receive(nc)) {
+ return -1;
+ }
+
+ q = virtio_net_get_subqueue(nc);
+
/* hdr_len refers to the header we supply to the guest */
if (!virtio_net_has_buffers(q, size + n->guest_hdr_len - n->host_hdr_len)) {
return 0;
@@ -1974,21 +1989,18 @@ static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf,
if (n->mergeable_rx_bufs) {
mhdr_cnt = iov_copy(mhdr_sg, ARRAY_SIZE(mhdr_sg),
sg, elem->in_num,
- offsetof(typeof(extra_hdr), hdr.num_buffers),
- sizeof(extra_hdr.hdr.num_buffers));
+ offsetof(typeof(hdr),
+ virtio_net.hdr.num_buffers),
+ sizeof(hdr.virtio_net.hdr.num_buffers));
}
- receive_header(n, sg, elem->in_num, buf, size);
- if (n->rss_data.populate_hash) {
- offset = offsetof(typeof(extra_hdr), hash_value);
- iov_from_buf(sg, elem->in_num, offset,
- (char *)&extra_hdr + offset,
- sizeof(extra_hdr.hash_value) +
- sizeof(extra_hdr.hash_report));
- }
- offset = n->host_hdr_len;
- total += n->guest_hdr_len;
- guest_offset = n->guest_hdr_len;
+ guest_offset = n->has_vnet_hdr ?
+ receive_header(n, (struct virtio_net_hdr *)&hdr,
+ buf, size, &offset) :
+ n->guest_hdr_len;
+
+ iov_from_buf(sg, elem->in_num, 0, &hdr, guest_offset);
+ total += guest_offset;
} else {
guest_offset = 0;
}
@@ -2014,11 +2026,11 @@ static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf,
}
if (mhdr_cnt) {
- virtio_stw_p(vdev, &extra_hdr.hdr.num_buffers, i);
+ virtio_stw_p(vdev, &hdr.virtio_net.hdr.num_buffers, i);
iov_from_buf(mhdr_sg, mhdr_cnt,
0,
- &extra_hdr.hdr.num_buffers,
- sizeof extra_hdr.hdr.num_buffers);
+ &hdr.virtio_net.hdr.num_buffers,
+ sizeof hdr.virtio_net.hdr.num_buffers);
}
for (j = 0; j < i; j++) {
@@ -2046,7 +2058,7 @@ static ssize_t virtio_net_do_receive(NetClientState *nc, const uint8_t *buf,
{
RCU_READ_LOCK_GUARD();
- return virtio_net_receive_rcu(nc, buf, size, false);
+ return virtio_net_receive_rcu(nc, buf, size);
}
/*
@@ -3052,6 +3064,15 @@ static void virtio_net_set_multiqueue(VirtIONet *n, int multiqueue)
virtio_net_set_queue_pairs(n);
}
+static int virtio_net_pre_load_queues(VirtIODevice *vdev)
+{
+ virtio_net_set_multiqueue(VIRTIO_NET(vdev),
+ virtio_has_feature(vdev->guest_features, VIRTIO_NET_F_RSS) ||
+ virtio_has_feature(vdev->guest_features, VIRTIO_NET_F_MQ));
+
+ return 0;
+}
+
static int virtio_net_post_load_device(void *opaque, int version_id)
{
VirtIONet *n = opaque;
@@ -4061,6 +4082,7 @@ static void virtio_net_class_init(ObjectClass *klass, void *data)
vdc->guest_notifier_mask = virtio_net_guest_notifier_mask;
vdc->guest_notifier_pending = virtio_net_guest_notifier_pending;
vdc->legacy_features |= (0x1 << VIRTIO_NET_F_GSO);
+ vdc->pre_load_queues = virtio_net_pre_load_queues;
vdc->post_load = virtio_net_post_load_virtio;
vdc->vmsd = &vmstate_virtio_net_device;
vdc->primary_unplug_pending = primary_unplug_pending;
diff --git a/hw/pci-host/mv64361.c b/hw/pci-host/mv64361.c
index 1036d86..421c287 100644
--- a/hw/pci-host/mv64361.c
+++ b/hw/pci-host/mv64361.c
@@ -95,6 +95,7 @@ static void mv64361_pcihost_realize(DeviceState *dev, Error **errp)
&s->mem, &s->io, 0, 4, TYPE_PCI_BUS);
g_free(name);
pci_create_simple(h->bus, 0, TYPE_MV64361_PCI_BRIDGE);
+ qdev_init_gpio_out(dev, s->irq, ARRAY_SIZE(s->irq));
}
static Property mv64361_pcihost_props[] = {
diff --git a/hw/ppc/pegasos2.c b/hw/ppc/pegasos2.c
index 8ff4a00..16abeaa 100644
--- a/hw/ppc/pegasos2.c
+++ b/hw/ppc/pegasos2.c
@@ -14,6 +14,7 @@
#include "hw/sysbus.h"
#include "hw/pci/pci_host.h"
#include "hw/irq.h"
+#include "hw/or-irq.h"
#include "hw/pci-host/mv64361.h"
#include "hw/isa/vt82c686.h"
#include "hw/ide/pci.h"
@@ -73,8 +74,11 @@ OBJECT_DECLARE_TYPE(Pegasos2MachineState, MachineClass, PEGASOS2_MACHINE)
struct Pegasos2MachineState {
MachineState parent_obj;
+
PowerPCCPU *cpu;
DeviceState *mv;
+ IRQState pci_irqs[PCI_NUM_PINS];
+ OrIRQState orirq[PCI_NUM_PINS];
qemu_irq mv_pirq[PCI_NUM_PINS];
qemu_irq via_pirq[PCI_NUM_PINS];
Vof *vof;
@@ -177,7 +181,6 @@ static void pegasos2_init(MachineState *machine)
pm->mv_pirq[i] = qdev_get_gpio_in_named(pm->mv, "gpp", 12 + i);
}
pci_bus = mv64361_get_pci_bus(pm->mv, 1);
- pci_bus_irqs(pci_bus, pegasos2_pci_irq, pm, PCI_NUM_PINS);
/* VIA VT8231 South Bridge (multifunction PCI device) */
via = OBJECT(pci_new_multifunction(PCI_DEVFN(12, 0), TYPE_VT8231_ISA));
@@ -209,6 +212,31 @@ static void pegasos2_init(MachineState *machine)
/* other PC hardware */
pci_vga_init(pci_bus);
+ /* PCI interrupt routing: lines from pci.0 and pci.1 are ORed */
+ for (int h = 0; h < 2; h++) {
+ DeviceState *pd;
+ g_autofree const char *pn = g_strdup_printf("pcihost%d", h);
+
+ pd = DEVICE(object_resolve_path_component(OBJECT(pm->mv), pn));
+ assert(pd);
+ for (i = 0; i < PCI_NUM_PINS; i++) {
+ OrIRQState *ori = &pm->orirq[i];
+
+ if (h == 0) {
+ g_autofree const char *n = g_strdup_printf("pci-orirq[%d]", i);
+
+ object_initialize_child_with_props(OBJECT(pm), n,
+ ori, sizeof(*ori),
+ TYPE_OR_IRQ, &error_fatal,
+ "num-lines", "2", NULL);
+ qdev_realize(DEVICE(ori), NULL, &error_fatal);
+ qemu_init_irq(&pm->pci_irqs[i], pegasos2_pci_irq, pm, i);
+ qdev_connect_gpio_out(DEVICE(ori), 0, &pm->pci_irqs[i]);
+ }
+ qdev_connect_gpio_out(pd, i, qdev_get_gpio_in(DEVICE(ori), h));
+ }
+ }
+
if (machine->kernel_filename) {
sz = load_elf(machine->kernel_filename, NULL, NULL, NULL,
&pm->kernel_entry, &pm->kernel_addr, NULL, NULL, 1,
diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c
index a306939..e6b0229 100644
--- a/hw/ppc/pnv_core.c
+++ b/hw/ppc/pnv_core.c
@@ -217,8 +217,8 @@ static uint64_t pnv_core_power10_xscom_read(void *opaque, hwaddr addr,
case PNV10_XSCOM_EC_CORE_RAS_STATUS:
for (i = 0; i < nr_threads; i++) {
PowerPCCPU *cpu = pc->threads[i];
- CPUState *cs = CPU(cpu);
- if (cs->stopped) {
+ CPUPPCState *env = &cpu->env;
+ if (env->quiesced) {
val |= PPC_BIT(0 + 8 * i) | PPC_BIT(1 + 8 * i);
}
}
@@ -244,20 +244,25 @@ static void pnv_core_power10_xscom_write(void *opaque, hwaddr addr,
for (i = 0; i < nr_threads; i++) {
PowerPCCPU *cpu = pc->threads[i];
CPUState *cs = CPU(cpu);
+ CPUPPCState *env = &cpu->env;
if (val & PPC_BIT(7 + 8 * i)) { /* stop */
val &= ~PPC_BIT(7 + 8 * i);
cpu_pause(cs);
+ env->quiesced = true;
}
if (val & PPC_BIT(6 + 8 * i)) { /* start */
val &= ~PPC_BIT(6 + 8 * i);
+ env->quiesced = false;
cpu_resume(cs);
}
if (val & PPC_BIT(4 + 8 * i)) { /* sreset */
val &= ~PPC_BIT(4 + 8 * i);
+ env->quiesced = false;
pnv_cpu_do_nmi_resume(cs);
}
if (val & PPC_BIT(3 + 8 * i)) { /* clear maint */
+ env->quiesced = false;
/*
* Hardware has very particular cases for where clear maint
* must be used and where start must be used to resume a
@@ -317,6 +322,8 @@ static void pnv_core_cpu_realize(PnvCore *pc, PowerPCCPU *cpu, Error **errp,
pir_spr->default_value = pir;
tir_spr->default_value = tir;
+ env->chip_index = pc->chip->chip_id;
+
if (pc->big_core) {
/* 2 "small cores" get the same core index for SMT operations */
env->core_index = core_hwid >> 1;
diff --git a/hw/ppc/pnv_nest_pervasive.c b/hw/ppc/pnv_nest_pervasive.c
index 7747675..780fa69 100644
--- a/hw/ppc/pnv_nest_pervasive.c
+++ b/hw/ppc/pnv_nest_pervasive.c
@@ -177,7 +177,7 @@ static void pnv_nest_pervasive_realize(DeviceState *dev, Error **errp)
pnv_xscom_region_init(&nest_pervasive->xscom_ctrl_regs_mr,
OBJECT(nest_pervasive),
&pnv_nest_pervasive_control_xscom_ops,
- nest_pervasive, "pervasive-control",
+ nest_pervasive, "xscom-pervasive-control",
PNV10_XSCOM_CHIPLET_CTRL_REGS_SIZE);
}
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index 5c02037..0d4efaa 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -701,7 +701,7 @@ static void spapr_dt_cpu(CPUState *cs, void *fdt, int offset,
uint32_t radix_AP_encodings[PPC_PAGE_SIZES_MAX_SZ];
int i;
- drc = spapr_drc_by_id(TYPE_SPAPR_DRC_CPU, index);
+ drc = spapr_drc_by_id(TYPE_SPAPR_DRC_CPU, env->core_index);
if (drc) {
drc_index = spapr_drc_index(drc);
_FDT((fdt_setprop_cell(fdt, offset, "ibm,my-drc-index", drc_index)));
diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c
index ada439e..135f86a 100644
--- a/hw/ppc/spapr_cpu_core.c
+++ b/hw/ppc/spapr_cpu_core.c
@@ -313,6 +313,7 @@ static PowerPCCPU *spapr_create_vcpu(SpaprCpuCore *sc, int i, Error **errp)
return NULL;
}
+ env->chip_index = sc->node_id;
env->core_index = cc->core_id;
cpu->node_id = sc->node_id;
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index a26f189..f12c4aa 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -3255,6 +3255,13 @@ virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id)
config_len--;
}
+ if (vdc->pre_load_queues) {
+ ret = vdc->pre_load_queues(vdev);
+ if (ret) {
+ return ret;
+ }
+ }
+
num = qemu_get_be32(f);
if (num > VIRTIO_QUEUE_MAX) {