summaryrefslogtreecommitdiffstats
path: root/hw
diff options
context:
space:
mode:
Diffstat (limited to 'hw')
-rw-r--r--hw/acpi/pcihp.c11
-rw-r--r--hw/acpi/piix4.c2
-rw-r--r--hw/block/block.c24
-rw-r--r--hw/block/fdc.c28
-rw-r--r--hw/block/m25p80.c8
-rw-r--r--hw/block/nand.c7
-rw-r--r--hw/block/nvme.c8
-rw-r--r--hw/block/onenand.c7
-rw-r--r--hw/block/pflash_cfi01.c18
-rw-r--r--hw/block/pflash_cfi02.c19
-rw-r--r--hw/block/virtio-blk.c8
-rw-r--r--hw/core/bus.c2
-rw-r--r--hw/core/ptimer.c8
-rw-r--r--hw/core/qdev-properties-system.c9
-rw-r--r--hw/core/qdev.c7
-rw-r--r--hw/i386/acpi-build.c4
-rw-r--r--hw/ide/core.c2
-rw-r--r--hw/ide/qdev.c9
-rw-r--r--hw/intc/xics.c461
-rw-r--r--hw/intc/xics_kvm.c184
-rw-r--r--hw/intc/xics_spapr.c128
-rw-r--r--hw/nvram/spapr_nvram.c8
-rw-r--r--hw/pci/pci.c28
-rw-r--r--hw/ppc/spapr.c196
-rw-r--r--hw/ppc/spapr_cpu_core.c24
-rw-r--r--hw/ppc/spapr_events.c10
-rw-r--r--hw/ppc/spapr_hcall.c89
-rw-r--r--hw/ppc/spapr_pci.c312
-rw-r--r--hw/ppc/spapr_vio.c2
-rw-r--r--hw/scsi/scsi-disk.c12
-rw-r--r--hw/sd/sd.c8
-rw-r--r--hw/usb/bus.c19
-rw-r--r--hw/usb/dev-storage.c22
-rw-r--r--hw/usb/dev-uas.c2
34 files changed, 998 insertions, 688 deletions
diff --git a/hw/acpi/pcihp.c b/hw/acpi/pcihp.c
index d957d1e30d..2b0f3e1bfb 100644
--- a/hw/acpi/pcihp.c
+++ b/hw/acpi/pcihp.c
@@ -49,7 +49,6 @@
#define ACPI_PCIHP_ADDR 0xae00
#define ACPI_PCIHP_SIZE 0x0014
-#define ACPI_PCIHP_LEGACY_SIZE 0x000f
#define PCI_UP_BASE 0x0000
#define PCI_DOWN_BASE 0x0004
#define PCI_EJ_BASE 0x0008
@@ -302,16 +301,6 @@ void acpi_pcihp_init(Object *owner, AcpiPciHpState *s, PCIBus *root_bus,
s->root= root_bus;
s->legacy_piix = !bridges_enabled;
- if (s->legacy_piix) {
- unsigned *bus_bsel = g_malloc(sizeof *bus_bsel);
-
- s->io_len = ACPI_PCIHP_LEGACY_SIZE;
-
- *bus_bsel = ACPI_PCIHP_BSEL_DEFAULT;
- object_property_add_uint32_ptr(OBJECT(root_bus), ACPI_PCIHP_PROP_BSEL,
- bus_bsel, NULL);
- }
-
memory_region_init_io(&s->io, owner, &acpi_pcihp_io_ops, s,
"acpi-pci-hotplug", s->io_len);
memory_region_add_subregion(address_space_io, s->io_base, &s->io);
diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c
index 6d99fe407c..a553a7e110 100644
--- a/hw/acpi/piix4.c
+++ b/hw/acpi/piix4.c
@@ -440,6 +440,8 @@ static void piix4_update_bus_hotplug(PCIBus *pci_bus, void *opaque)
{
PIIX4PMState *s = opaque;
+ /* pci_bus cannot outlive PIIX4PMState, because /machine keeps it alive
+ * and it's not hot-unpluggable */
qbus_set_hotplug_handler(BUS(pci_bus), DEVICE(s), &error_abort);
}
diff --git a/hw/block/block.c b/hw/block/block.c
index 8dc9d84a39..27878d0087 100644
--- a/hw/block/block.c
+++ b/hw/block/block.c
@@ -51,11 +51,33 @@ void blkconf_blocksizes(BlockConf *conf)
}
}
-void blkconf_apply_backend_options(BlockConf *conf)
+void blkconf_apply_backend_options(BlockConf *conf, bool readonly,
+ bool resizable, Error **errp)
{
BlockBackend *blk = conf->blk;
BlockdevOnError rerror, werror;
+ uint64_t perm, shared_perm;
bool wce;
+ int ret;
+
+ perm = BLK_PERM_CONSISTENT_READ;
+ if (!readonly) {
+ perm |= BLK_PERM_WRITE;
+ }
+
+ shared_perm = BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE_UNCHANGED |
+ BLK_PERM_GRAPH_MOD;
+ if (resizable) {
+ shared_perm |= BLK_PERM_RESIZE;
+ }
+ if (conf->share_rw) {
+ shared_perm |= BLK_PERM_WRITE;
+ }
+
+ ret = blk_set_perm(blk, perm, shared_perm, errp);
+ if (ret < 0) {
+ return;
+ }
switch (conf->wce) {
case ON_OFF_AUTO_ON: wce = true; break;
diff --git a/hw/block/fdc.c b/hw/block/fdc.c
index 17d29e7bc5..a328693d15 100644
--- a/hw/block/fdc.c
+++ b/hw/block/fdc.c
@@ -186,6 +186,7 @@ typedef enum FDiskFlags {
struct FDrive {
FDCtrl *fdctrl;
BlockBackend *blk;
+ BlockConf *conf;
/* Drive status */
FloppyDriveType drive; /* CMOS drive type */
uint8_t perpendicular; /* 2.88 MB access mode */
@@ -469,9 +470,22 @@ static void fd_revalidate(FDrive *drv)
}
}
-static void fd_change_cb(void *opaque, bool load)
+static void fd_change_cb(void *opaque, bool load, Error **errp)
{
FDrive *drive = opaque;
+ Error *local_err = NULL;
+
+ if (!load) {
+ blk_set_perm(drive->blk, 0, BLK_PERM_ALL, &error_abort);
+ } else {
+ blkconf_apply_backend_options(drive->conf,
+ blk_is_read_only(drive->blk), false,
+ &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+ }
drive->media_changed = 1;
drive->media_validated = false;
@@ -508,6 +522,7 @@ static int floppy_drive_init(DeviceState *qdev)
FloppyDrive *dev = FLOPPY_DRIVE(qdev);
FloppyBus *bus = FLOPPY_BUS(qdev->parent_bus);
FDrive *drive;
+ Error *local_err = NULL;
int ret;
if (dev->unit == -1) {
@@ -533,7 +548,7 @@ static int floppy_drive_init(DeviceState *qdev)
if (!dev->conf.blk) {
/* Anonymous BlockBackend for an empty drive */
- dev->conf.blk = blk_new();
+ dev->conf.blk = blk_new(0, BLK_PERM_ALL);
ret = blk_attach_dev(dev->conf.blk, qdev);
assert(ret == 0);
}
@@ -551,7 +566,13 @@ static int floppy_drive_init(DeviceState *qdev)
* blkconf_apply_backend_options(). */
dev->conf.rerror = BLOCKDEV_ON_ERROR_AUTO;
dev->conf.werror = BLOCKDEV_ON_ERROR_AUTO;
- blkconf_apply_backend_options(&dev->conf);
+
+ blkconf_apply_backend_options(&dev->conf, blk_is_read_only(dev->conf.blk),
+ false, &local_err);
+ if (local_err) {
+ error_report_err(local_err);
+ return -1;
+ }
/* 'enospc' is the default for -drive, 'report' is what blk_new() gives us
* for empty drives. */
@@ -565,6 +586,7 @@ static int floppy_drive_init(DeviceState *qdev)
return -1;
}
+ drive->conf = &dev->conf;
drive->blk = dev->conf.blk;
drive->fdctrl = bus->fdc;
diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c
index 2d6eb46a04..190573cefa 100644
--- a/hw/block/m25p80.c
+++ b/hw/block/m25p80.c
@@ -1215,6 +1215,7 @@ static void m25p80_realize(SSISlave *ss, Error **errp)
{
Flash *s = M25P80(ss);
M25P80Class *mc = M25P80_GET_CLASS(s);
+ int ret;
s->pi = mc->pi;
@@ -1222,6 +1223,13 @@ static void m25p80_realize(SSISlave *ss, Error **errp)
s->dirty_page = -1;
if (s->blk) {
+ uint64_t perm = BLK_PERM_CONSISTENT_READ |
+ (blk_is_read_only(s->blk) ? 0 : BLK_PERM_WRITE);
+ ret = blk_set_perm(s->blk, perm, BLK_PERM_ALL, errp);
+ if (ret < 0) {
+ return;
+ }
+
DB_PRINT_L(0, "Binding to IF_MTD drive\n");
s->storage = blk_blockalign(s->blk, s->size);
diff --git a/hw/block/nand.c b/hw/block/nand.c
index c69e6755d9..0d33ac281f 100644
--- a/hw/block/nand.c
+++ b/hw/block/nand.c
@@ -373,6 +373,8 @@ static void nand_realize(DeviceState *dev, Error **errp)
{
int pagesize;
NANDFlashState *s = NAND(dev);
+ int ret;
+
s->buswidth = nand_flash_ids[s->chip_id].width >> 3;
s->size = nand_flash_ids[s->chip_id].size << 20;
@@ -407,6 +409,11 @@ static void nand_realize(DeviceState *dev, Error **errp)
error_setg(errp, "Can't use a read-only drive");
return;
}
+ ret = blk_set_perm(s->blk, BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE,
+ BLK_PERM_ALL, errp);
+ if (ret < 0) {
+ return;
+ }
if (blk_getlength(s->blk) >=
(s->pages << s->page_shift) + (s->pages << s->oob_shift)) {
pagesize = 0;
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
index ae91a18f17..ae303d44e5 100644
--- a/hw/block/nvme.c
+++ b/hw/block/nvme.c
@@ -835,6 +835,7 @@ static int nvme_init(PCIDevice *pci_dev)
int i;
int64_t bs_size;
uint8_t *pci_conf;
+ Error *local_err = NULL;
if (!n->conf.blk) {
return -1;
@@ -850,7 +851,12 @@ static int nvme_init(PCIDevice *pci_dev)
return -1;
}
blkconf_blocksizes(&n->conf);
- blkconf_apply_backend_options(&n->conf);
+ blkconf_apply_backend_options(&n->conf, blk_is_read_only(n->conf.blk),
+ false, &local_err);
+ if (local_err) {
+ error_report_err(local_err);
+ return -1;
+ }
pci_conf = pci_dev->config;
pci_conf[PCI_INTERRUPT_PIN] = 1;
diff --git a/hw/block/onenand.c b/hw/block/onenand.c
index 8d8422739e..ddf5492426 100644
--- a/hw/block/onenand.c
+++ b/hw/block/onenand.c
@@ -778,6 +778,7 @@ static int onenand_initfn(SysBusDevice *sbd)
OneNANDState *s = ONE_NAND(dev);
uint32_t size = 1 << (24 + ((s->id.dev >> 4) & 7));
void *ram;
+ Error *local_err = NULL;
s->base = (hwaddr)-1;
s->rdy = NULL;
@@ -796,6 +797,12 @@ static int onenand_initfn(SysBusDevice *sbd)
error_report("Can't use a read-only drive");
return -1;
}
+ blk_set_perm(s->blk, BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE,
+ BLK_PERM_ALL, &local_err);
+ if (local_err) {
+ error_report_err(local_err);
+ return -1;
+ }
s->blk_cur = s->blk;
}
s->otp = memset(g_malloc((64 + 2) << PAGE_SHIFT),
diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c
index 71b98a3eef..594d4cf6fe 100644
--- a/hw/block/pflash_cfi01.c
+++ b/hw/block/pflash_cfi01.c
@@ -758,6 +758,18 @@ static void pflash_cfi01_realize(DeviceState *dev, Error **errp)
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &pfl->mem);
if (pfl->blk) {
+ uint64_t perm;
+ pfl->ro = blk_is_read_only(pfl->blk);
+ perm = BLK_PERM_CONSISTENT_READ | (pfl->ro ? 0 : BLK_PERM_WRITE);
+ ret = blk_set_perm(pfl->blk, perm, BLK_PERM_ALL, errp);
+ if (ret < 0) {
+ return;
+ }
+ } else {
+ pfl->ro = 0;
+ }
+
+ if (pfl->blk) {
/* read the initial flash content */
ret = blk_pread(pfl->blk, 0, pfl->storage, total_len);
@@ -768,12 +780,6 @@ static void pflash_cfi01_realize(DeviceState *dev, Error **errp)
}
}
- if (pfl->blk) {
- pfl->ro = blk_is_read_only(pfl->blk);
- } else {
- pfl->ro = 0;
- }
-
/* Default to devices being used at their maximum device width. This was
* assumed before the device_width support was added.
*/
diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c
index ef71322759..e6c5c6c25d 100644
--- a/hw/block/pflash_cfi02.c
+++ b/hw/block/pflash_cfi02.c
@@ -632,6 +632,19 @@ static void pflash_cfi02_realize(DeviceState *dev, Error **errp)
vmstate_register_ram(&pfl->orig_mem, DEVICE(pfl));
pfl->storage = memory_region_get_ram_ptr(&pfl->orig_mem);
pfl->chip_len = chip_len;
+
+ if (pfl->blk) {
+ uint64_t perm;
+ pfl->ro = blk_is_read_only(pfl->blk);
+ perm = BLK_PERM_CONSISTENT_READ | (pfl->ro ? 0 : BLK_PERM_WRITE);
+ ret = blk_set_perm(pfl->blk, perm, BLK_PERM_ALL, errp);
+ if (ret < 0) {
+ return;
+ }
+ } else {
+ pfl->ro = 0;
+ }
+
if (pfl->blk) {
/* read the initial flash content */
ret = blk_pread(pfl->blk, 0, pfl->storage, chip_len);
@@ -646,12 +659,6 @@ static void pflash_cfi02_realize(DeviceState *dev, Error **errp)
pfl->rom_mode = 1;
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &pfl->mem);
- if (pfl->blk) {
- pfl->ro = blk_is_read_only(pfl->blk);
- } else {
- pfl->ro = 0;
- }
-
pfl->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, pflash_timer, pfl);
pfl->wcycle = 0;
pfl->cmd = 0;
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
index 843bd2fa73..98c16a7a9a 100644
--- a/hw/block/virtio-blk.c
+++ b/hw/block/virtio-blk.c
@@ -928,7 +928,13 @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp)
}
blkconf_serial(&conf->conf, &conf->serial);
- blkconf_apply_backend_options(&conf->conf);
+ blkconf_apply_backend_options(&conf->conf,
+ blk_is_read_only(conf->conf.blk), true,
+ &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
s->original_wce = blk_enable_write_cache(conf->conf.blk);
blkconf_geometry(&conf->conf, NULL, 65535, 255, 255, &err);
if (err) {
diff --git a/hw/core/bus.c b/hw/core/bus.c
index cf383fc1af..4651f24486 100644
--- a/hw/core/bus.c
+++ b/hw/core/bus.c
@@ -197,7 +197,7 @@ static void qbus_initfn(Object *obj)
TYPE_HOTPLUG_HANDLER,
(Object **)&bus->hotplug_handler,
object_property_allow_set_link,
- OBJ_PROP_LINK_UNREF_ON_RELEASE,
+ 0,
NULL);
object_property_add_bool(obj, "realized",
bus_get_realized, bus_set_realized, NULL);
diff --git a/hw/core/ptimer.c b/hw/core/ptimer.c
index 3af82afe78..59ccb00550 100644
--- a/hw/core/ptimer.c
+++ b/hw/core/ptimer.c
@@ -12,6 +12,7 @@
#include "qemu/host-utils.h"
#include "sysemu/replay.h"
#include "sysemu/qtest.h"
+#include "block/aio.h"
#define DELTA_ADJUST 1
#define DELTA_NO_ADJUST -1
@@ -353,3 +354,10 @@ ptimer_state *ptimer_init(QEMUBH *bh, uint8_t policy_mask)
s->policy_mask = policy_mask;
return s;
}
+
+void ptimer_free(ptimer_state *s)
+{
+ qemu_bh_delete(s->bh);
+ timer_free(s->timer);
+ g_free(s);
+}
diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c
index 94f4d8bde4..c34be1c1ba 100644
--- a/hw/core/qdev-properties-system.c
+++ b/hw/core/qdev-properties-system.c
@@ -73,14 +73,19 @@ static void parse_drive(DeviceState *dev, const char *str, void **ptr,
{
BlockBackend *blk;
bool blk_created = false;
+ int ret;
blk = blk_by_name(str);
if (!blk) {
BlockDriverState *bs = bdrv_lookup_bs(NULL, str, NULL);
if (bs) {
- blk = blk_new();
- blk_insert_bs(blk, bs);
+ blk = blk_new(0, BLK_PERM_ALL);
blk_created = true;
+
+ ret = blk_insert_bs(blk, bs, errp);
+ if (ret < 0) {
+ goto fail;
+ }
}
}
if (!blk) {
diff --git a/hw/core/qdev.c b/hw/core/qdev.c
index 923e626333..1e7fb33246 100644
--- a/hw/core/qdev.c
+++ b/hw/core/qdev.c
@@ -37,6 +37,7 @@
#include "hw/boards.h"
#include "hw/sysbus.h"
#include "qapi-event.h"
+#include "migration/migration.h"
int qdev_hotplug = 0;
static bool qdev_hot_added = false;
@@ -903,6 +904,7 @@ static void device_set_realized(Object *obj, bool value, Error **errp)
Error *local_err = NULL;
bool unattached_parent = false;
static int unattached_count;
+ int ret;
if (dev->hotplugged && !dc->hotpluggable) {
error_setg(errp, QERR_DEVICE_NO_HOTPLUG, object_get_typename(obj));
@@ -910,6 +912,11 @@ static void device_set_realized(Object *obj, bool value, Error **errp)
}
if (value && !dev->realized) {
+ ret = check_migratable(obj, &local_err);
+ if (ret < 0) {
+ goto fail;
+ }
+
if (!obj->parent) {
gchar *name = g_strdup_printf("device[%d]", unattached_count++);
diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index 1c928abb28..f44767b9be 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -462,7 +462,7 @@ static void *acpi_set_bsel(PCIBus *bus, void *opaque)
*bus_bsel = (*bsel_alloc)++;
object_property_add_uint32_ptr(OBJECT(bus), ACPI_PCIHP_PROP_BSEL,
- bus_bsel, NULL);
+ bus_bsel, &error_abort);
}
return bsel_alloc;
@@ -471,7 +471,7 @@ static void *acpi_set_bsel(PCIBus *bus, void *opaque)
static void acpi_set_pci_info(void)
{
PCIBus *bus = find_i440fx(); /* TODO: Q35 support */
- unsigned bsel_alloc = 0;
+ unsigned bsel_alloc = ACPI_PCIHP_BSEL_DEFAULT;
if (bus) {
/* Scan all PCI buses. Set property to enable acpi based hotplug. */
diff --git a/hw/ide/core.c b/hw/ide/core.c
index cfa5de6ebf..db509b3e15 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -1120,7 +1120,7 @@ static void ide_cfata_metadata_write(IDEState *s)
}
/* called when the inserted state of the media has changed */
-static void ide_cd_change_cb(void *opaque, bool load)
+static void ide_cd_change_cb(void *opaque, bool load, Error **errp)
{
IDEState *s = opaque;
uint64_t nb_sectors;
diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c
index dbaa75cf59..4383cd111d 100644
--- a/hw/ide/qdev.c
+++ b/hw/ide/qdev.c
@@ -170,7 +170,7 @@ static int ide_dev_initfn(IDEDevice *dev, IDEDriveKind kind)
return -1;
} else {
/* Anonymous BlockBackend for an empty drive */
- dev->conf.blk = blk_new();
+ dev->conf.blk = blk_new(0, BLK_PERM_ALL);
}
}
@@ -196,7 +196,12 @@ static int ide_dev_initfn(IDEDevice *dev, IDEDriveKind kind)
return -1;
}
}
- blkconf_apply_backend_options(&dev->conf);
+ blkconf_apply_backend_options(&dev->conf, kind == IDE_CD, kind != IDE_CD,
+ &err);
+ if (err) {
+ error_report_err(err);
+ return -1;
+ }
if (ide_init_drive(s, dev->conf.blk, kind,
dev->version, dev->serial, dev->model, dev->wwn,
diff --git a/hw/intc/xics.c b/hw/intc/xics.c
index 095c16a300..ffc0747c7f 100644
--- a/hw/intc/xics.c
+++ b/hw/intc/xics.c
@@ -49,40 +49,41 @@ int xics_get_cpu_index_by_dt_id(int cpu_dt_id)
return -1;
}
-void xics_cpu_destroy(XICSState *xics, PowerPCCPU *cpu)
+void xics_cpu_destroy(XICSFabric *xi, PowerPCCPU *cpu)
{
CPUState *cs = CPU(cpu);
- ICPState *ss = &xics->ss[cs->cpu_index];
+ ICPState *icp = xics_icp_get(xi, cs->cpu_index);
- assert(cs->cpu_index < xics->nr_servers);
- assert(cs == ss->cs);
+ assert(icp);
+ assert(cs == icp->cs);
- ss->output = NULL;
- ss->cs = NULL;
+ icp->output = NULL;
+ icp->cs = NULL;
}
-void xics_cpu_setup(XICSState *xics, PowerPCCPU *cpu)
+void xics_cpu_setup(XICSFabric *xi, PowerPCCPU *cpu)
{
CPUState *cs = CPU(cpu);
CPUPPCState *env = &cpu->env;
- ICPState *ss = &xics->ss[cs->cpu_index];
- XICSStateClass *info = XICS_COMMON_GET_CLASS(xics);
+ ICPState *icp = xics_icp_get(xi, cs->cpu_index);
+ ICPStateClass *icpc;
- assert(cs->cpu_index < xics->nr_servers);
+ assert(icp);
- ss->cs = cs;
+ icp->cs = cs;
- if (info->cpu_setup) {
- info->cpu_setup(xics, cpu);
+ icpc = ICP_GET_CLASS(icp);
+ if (icpc->cpu_setup) {
+ icpc->cpu_setup(icp, cpu);
}
switch (PPC_INPUT(env)) {
case PPC_FLAGS_INPUT_POWER7:
- ss->output = env->irq_inputs[POWER7_INPUT_INT];
+ icp->output = env->irq_inputs[POWER7_INPUT_INT];
break;
case PPC_FLAGS_INPUT_970:
- ss->output = env->irq_inputs[PPC970_INPUT_INT];
+ icp->output = env->irq_inputs[PPC970_INPUT_INT];
break;
default:
@@ -92,185 +93,43 @@ void xics_cpu_setup(XICSState *xics, PowerPCCPU *cpu)
}
}
-static void xics_common_pic_print_info(InterruptStatsProvider *obj,
- Monitor *mon)
+void icp_pic_print_info(ICPState *icp, Monitor *mon)
{
- XICSState *xics = XICS_COMMON(obj);
- ICSState *ics;
- uint32_t i;
-
- for (i = 0; i < xics->nr_servers; i++) {
- ICPState *icp = &xics->ss[i];
-
- if (!icp->output) {
- continue;
- }
- monitor_printf(mon, "CPU %d XIRR=%08x (%p) PP=%02x MFRR=%02x\n",
- i, icp->xirr, icp->xirr_owner,
- icp->pending_priority, icp->mfrr);
- }
-
- QLIST_FOREACH(ics, &xics->ics, list) {
- monitor_printf(mon, "ICS %4x..%4x %p\n",
- ics->offset, ics->offset + ics->nr_irqs - 1, ics);
-
- if (!ics->irqs) {
- continue;
- }
-
- for (i = 0; i < ics->nr_irqs; i++) {
- ICSIRQState *irq = ics->irqs + i;
-
- if (!(irq->flags & XICS_FLAGS_IRQ_MASK)) {
- continue;
- }
- monitor_printf(mon, " %4x %s %02x %02x\n",
- ics->offset + i,
- (irq->flags & XICS_FLAGS_IRQ_LSI) ?
- "LSI" : "MSI",
- irq->priority, irq->status);
- }
- }
-}
-
-/*
- * XICS Common class - parent for emulated XICS and KVM-XICS
- */
-static void xics_common_reset(DeviceState *d)
-{
- XICSState *xics = XICS_COMMON(d);
- ICSState *ics;
- int i;
-
- for (i = 0; i < xics->nr_servers; i++) {
- device_reset(DEVICE(&xics->ss[i]));
- }
-
- QLIST_FOREACH(ics, &xics->ics, list) {
- device_reset(DEVICE(ics));
- }
-}
-
-static void xics_prop_get_nr_irqs(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
-{
- XICSState *xics = XICS_COMMON(obj);
- int64_t value = xics->nr_irqs;
+ int cpu_index = icp->cs ? icp->cs->cpu_index : -1;
- visit_type_int(v, name, &value, errp);
-}
-
-static void xics_prop_set_nr_irqs(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
-{
- XICSState *xics = XICS_COMMON(obj);
- XICSStateClass *info = XICS_COMMON_GET_CLASS(xics);
- Error *error = NULL;
- int64_t value;
-
- visit_type_int(v, name, &value, &error);
- if (error) {
- error_propagate(errp, error);
+ if (!icp->output) {
return;
}
- if (xics->nr_irqs) {
- error_setg(errp, "Number of interrupts is already set to %u",
- xics->nr_irqs);
- return;
- }
-
- assert(info->set_nr_irqs);
- info->set_nr_irqs(xics, value, errp);
-}
-
-void xics_set_nr_servers(XICSState *xics, uint32_t nr_servers,
- const char *typename, Error **errp)
-{
- int i;
-
- xics->nr_servers = nr_servers;
-
- xics->ss = g_malloc0(xics->nr_servers * sizeof(ICPState));
- for (i = 0; i < xics->nr_servers; i++) {
- char name[32];
- ICPState *icp = &xics->ss[i];
-
- object_initialize(icp, sizeof(*icp), typename);
- snprintf(name, sizeof(name), "icp[%d]", i);
- object_property_add_child(OBJECT(xics), name, OBJECT(icp), errp);
- icp->xics = xics;
- }
+ monitor_printf(mon, "CPU %d XIRR=%08x (%p) PP=%02x MFRR=%02x\n",
+ cpu_index, icp->xirr, icp->xirr_owner,
+ icp->pending_priority, icp->mfrr);
}
-static void xics_prop_get_nr_servers(Object *obj, Visitor *v,
- const char *name, void *opaque,
- Error **errp)
+void ics_pic_print_info(ICSState *ics, Monitor *mon)
{
- XICSState *xics = XICS_COMMON(obj);
- int64_t value = xics->nr_servers;
-
- visit_type_int(v, name, &value, errp);
-}
+ uint32_t i;
-static void xics_prop_set_nr_servers(Object *obj, Visitor *v,
- const char *name, void *opaque,
- Error **errp)
-{
- XICSState *xics = XICS_COMMON(obj);
- XICSStateClass *xsc = XICS_COMMON_GET_CLASS(xics);
- Error *error = NULL;
- int64_t value;
+ monitor_printf(mon, "ICS %4x..%4x %p\n",
+ ics->offset, ics->offset + ics->nr_irqs - 1, ics);
- visit_type_int(v, name, &value, &error);
- if (error) {
- error_propagate(errp, error);
+ if (!ics->irqs) {
return;
}
- if (xics->nr_servers) {
- error_setg(errp, "Number of servers is already set to %u",
- xics->nr_servers);
- return;
- }
-
- assert(xsc->set_nr_servers);
- xsc->set_nr_servers(xics, value, errp);
-}
-
-static void xics_common_initfn(Object *obj)
-{
- XICSState *xics = XICS_COMMON(obj);
- QLIST_INIT(&xics->ics);
- object_property_add(obj, "nr_irqs", "int",
- xics_prop_get_nr_irqs, xics_prop_set_nr_irqs,
- NULL, NULL, NULL);
- object_property_add(obj, "nr_servers", "int",
- xics_prop_get_nr_servers, xics_prop_set_nr_servers,
- NULL, NULL, NULL);
-}
-
-static void xics_common_class_init(ObjectClass *oc, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(oc);
- InterruptStatsProviderClass *ic = INTERRUPT_STATS_PROVIDER_CLASS(oc);
+ for (i = 0; i < ics->nr_irqs; i++) {
+ ICSIRQState *irq = ics->irqs + i;
- dc->reset = xics_common_reset;
- ic->print_info = xics_common_pic_print_info;
+ if (!(irq->flags & XICS_FLAGS_IRQ_MASK)) {
+ continue;
+ }
+ monitor_printf(mon, " %4x %s %02x %02x\n",
+ ics->offset + i,
+ (irq->flags & XICS_FLAGS_IRQ_LSI) ?
+ "LSI" : "MSI",
+ irq->priority, irq->status);
+ }
}
-static const TypeInfo xics_common_info = {
- .name = TYPE_XICS_COMMON,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(XICSState),
- .class_size = sizeof(XICSStateClass),
- .instance_init = xics_common_initfn,
- .class_init = xics_common_class_init,
- .interfaces = (InterfaceInfo[]) {
- { TYPE_INTERRUPT_STATS_PROVIDER },
- { }
- },
-};
-
/*
* ICP: Presentation layer
*/
@@ -278,8 +137,8 @@ static const TypeInfo xics_common_info = {
#define XISR_MASK 0x00ffffff
#define CPPR_MASK 0xff000000
-#define XISR(ss) (((ss)->xirr) & XISR_MASK)
-#define CPPR(ss) (((ss)->xirr) >> 24)
+#define XISR(icp) (((icp)->xirr) & XISR_MASK)
+#define CPPR(icp) (((icp)->xirr) >> 24)
static void ics_reject(ICSState *ics, uint32_t nr)
{
@@ -290,7 +149,7 @@ static void ics_reject(ICSState *ics, uint32_t nr)
}
}
-static void ics_resend(ICSState *ics)
+void ics_resend(ICSState *ics)
{
ICSStateClass *k = ICS_BASE_GET_CLASS(ics);
@@ -308,151 +167,152 @@ static void ics_eoi(ICSState *ics, int nr)
}
}
-static void icp_check_ipi(ICPState *ss)
+static void icp_check_ipi(ICPState *icp)
{
- if (XISR(ss) && (ss->pending_priority <= ss->mfrr)) {
+ if (XISR(icp) && (icp->pending_priority <= icp->mfrr)) {
return;
}
- trace_xics_icp_check_ipi(ss->cs->cpu_index, ss->mfrr);
+ trace_xics_icp_check_ipi(icp->cs->cpu_index, icp->mfrr);
- if (XISR(ss) && ss->xirr_owner) {
- ics_reject(ss->xirr_owner, XISR(ss));
+ if (XISR(icp) && icp->xirr_owner) {
+ ics_reject(icp->xirr_owner, XISR(icp));
}
- ss->xirr = (ss->xirr & ~XISR_MASK) | XICS_IPI;
- ss->pending_priority = ss->mfrr;
- ss->xirr_owner = NULL;
- qemu_irq_raise(ss->output);
+ icp->xirr = (icp->xirr & ~XISR_MASK) | XICS_IPI;
+ icp->pending_priority = icp->mfrr;
+ icp->xirr_owner = NULL;
+ qemu_irq_raise(icp->output);
}
-static void icp_resend(ICPState *ss)
+void icp_resend(ICPState *icp)
{
- ICSState *ics;
+ XICSFabric *xi = icp->xics;
+ XICSFabricClass *xic = XICS_FABRIC_GET_CLASS(xi);
- if (ss->mfrr < CPPR(ss)) {
- icp_check_ipi(ss);
- }
- QLIST_FOREACH(ics, &ss->xics->ics, list) {
- ics_resend(ics);
+ if (icp->mfrr < CPPR(icp)) {
+ icp_check_ipi(icp);
}
+
+ xic->ics_resend(xi);
}
-void icp_set_cppr(ICPState *ss, uint8_t cppr)
+void icp_set_cppr(ICPState *icp, uint8_t cppr)
{
uint8_t old_cppr;
uint32_t old_xisr;
- old_cppr = CPPR(ss);
- ss->xirr = (ss->xirr & ~CPPR_MASK) | (cppr << 24);
+ old_cppr = CPPR(icp);
+ icp->xirr = (icp->xirr & ~CPPR_MASK) | (cppr << 24);
if (cppr < old_cppr) {
- if (XISR(ss) && (cppr <= ss->pending_priority)) {
- old_xisr = XISR(ss);
- ss->xirr &= ~XISR_MASK; /* Clear XISR */
- ss->pending_priority = 0xff;
- qemu_irq_lower(ss->output);
- if (ss->xirr_owner) {
- ics_reject(ss->xirr_owner, old_xisr);
- ss->xirr_owner = NULL;
+ if (XISR(icp) && (cppr <= icp->pending_priority)) {
+ old_xisr = XISR(icp);
+ icp->xirr &= ~XISR_MASK; /* Clear XISR */
+ icp->pending_priority = 0xff;
+ qemu_irq_lower(icp->output);
+ if (icp->xirr_owner) {
+ ics_reject(icp->xirr_owner, old_xisr);
+ icp->xirr_owner = NULL;
}
}
} else {
- if (!XISR(ss)) {
- icp_resend(ss);
+ if (!XISR(icp)) {
+ icp_resend(icp);
}
}
}
-void icp_set_mfrr(ICPState *ss, uint8_t mfrr)
+void icp_set_mfrr(ICPState *icp, uint8_t mfrr)
{
- ss->mfrr = mfrr;
- if (mfrr < CPPR(ss)) {
- icp_check_ipi(ss);
+ icp->mfrr = mfrr;
+ if (mfrr < CPPR(icp)) {
+ icp_check_ipi(icp);
}
}
-uint32_t icp_accept(ICPState *ss)
+uint32_t icp_accept(ICPState *icp)
{
- uint32_t xirr = ss->xirr;
+ uint32_t xirr = icp->xirr;
- qemu_irq_lower(ss->output);
- ss->xirr = ss->pending_priority << 24;
- ss->pending_priority = 0xff;
- ss->xirr_owner = NULL;
+ qemu_irq_lower(icp->output);
+ icp->xirr = icp->pending_priority << 24;
+ icp->pending_priority = 0xff;
+ icp->xirr_owner = NULL;
- trace_xics_icp_accept(xirr, ss->xirr);
+ trace_xics_icp_accept(xirr, icp->xirr);
return xirr;
}
-uint32_t icp_ipoll(ICPState *ss, uint32_t *mfrr)
+uint32_t icp_ipoll(ICPState *icp, uint32_t *mfrr)
{
if (mfrr) {
- *mfrr = ss->mfrr;
+ *mfrr = icp->mfrr;
}
- return ss->xirr;
+ return icp->xirr;
}
-void icp_eoi(ICPState *ss, uint32_t xirr)
+void icp_eoi(ICPState *icp, uint32_t xirr)
{
+ XICSFabric *xi = icp->xics;
+ XICSFabricClass *xic = XICS_FABRIC_GET_CLASS(xi);
ICSState *ics;
uint32_t irq;
/* Send EOI -> ICS */
- ss->xirr = (ss->xirr & ~CPPR_MASK) | (xirr & CPPR_MASK);
- trace_xics_icp_eoi(ss->cs->cpu_index, xirr, ss->xirr);
+ icp->xirr = (icp->xirr & ~CPPR_MASK) | (xirr & CPPR_MASK);
+ trace_xics_icp_eoi(icp->cs->cpu_index, xirr, icp->xirr);
irq = xirr & XISR_MASK;
- QLIST_FOREACH(ics, &ss->xics->ics, list) {
- if (ics_valid_irq(ics, irq)) {
- ics_eoi(ics, irq);
- }
+
+ ics = xic->ics_get(xi, irq);
+ if (ics) {
+ ics_eoi(ics, irq);
}
- if (!XISR(ss)) {
- icp_resend(ss);
+ if (!XISR(icp)) {
+ icp_resend(icp);
}
}
static void icp_irq(ICSState *ics, int server, int nr, uint8_t priority)
{
- XICSState *xics = ics->xics;
- ICPState *ss = xics->ss + server;
+ ICPState *icp = xics_icp_get(ics->xics, server);
trace_xics_icp_irq(server, nr, priority);
- if ((priority >= CPPR(ss))
- || (XISR(ss) && (ss->pending_priority <= priority))) {
+ if ((priority >= CPPR(icp))
+ || (XISR(icp) && (icp->pending_priority <= priority))) {
ics_reject(ics, nr);
} else {
- if (XISR(ss) && ss->xirr_owner) {
- ics_reject(ss->xirr_owner, XISR(ss));
- ss->xirr_owner = NULL;
+ if (XISR(icp) && icp->xirr_owner) {
+ ics_reject(icp->xirr_owner, XISR(icp));
+ icp->xirr_owner = NULL;
}
- ss->xirr = (ss->xirr & ~XISR_MASK) | (nr & XISR_MASK);
- ss->xirr_owner = ics;
- ss->pending_priority = priority;
- trace_xics_icp_raise(ss->xirr, ss->pending_priority);
- qemu_irq_raise(ss->output);
+ icp->xirr = (icp->xirr & ~XISR_MASK) | (nr & XISR_MASK);
+ icp->xirr_owner = ics;
+ icp->pending_priority = priority;
+ trace_xics_icp_raise(icp->xirr, icp->pending_priority);
+ qemu_irq_raise(icp->output);
}
}
static void icp_dispatch_pre_save(void *opaque)
{
- ICPState *ss = opaque;
- ICPStateClass *info = ICP_GET_CLASS(ss);
+ ICPState *icp = opaque;
+ ICPStateClass *info = ICP_GET_CLASS(icp);
if (info->pre_save) {
- info->pre_save(ss);
+ info->pre_save(icp);
}
}
static int icp_dispatch_post_load(void *opaque, int version_id)
{
- ICPState *ss = opaque;
- ICPStateClass *info = ICP_GET_CLASS(ss);
+ ICPState *icp = opaque;
+ ICPStateClass *info = ICP_GET_CLASS(icp);
if (info->post_load) {
- return info->post_load(ss, version_id);
+ return info->post_load(icp, version_id);
}
return 0;
@@ -485,12 +345,30 @@ static void icp_reset(DeviceState *dev)
qemu_set_irq(icp->output, 0);
}
+static void icp_realize(DeviceState *dev, Error **errp)
+{
+ ICPState *icp = ICP(dev);
+ Object *obj;
+ Error *err = NULL;
+
+ obj = object_property_get_link(OBJECT(dev), "xics", &err);
+ if (!obj) {
+ error_setg(errp, "%s: required link 'xics' not found: %s",
+ __func__, error_get_pretty(err));
+ return;
+ }
+
+ icp->xics = XICS_FABRIC(obj);
+}
+
+
static void icp_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->reset = icp_reset;
dc->vmsd = &vmstate_icp_server;
+ dc->realize = icp_realize;
}
static const TypeInfo icp_info = {
@@ -663,17 +541,6 @@ static void ics_simple_reset(DeviceState *dev)
}
}
-static int ics_simple_post_load(ICSState *ics, int version_id)
-{
- int i;
-
- for (i = 0; i < ics->xics->nr_servers; i++) {
- icp_resend(&ics->xics->ss[i]);
- }
-
- return 0;
-}
-
static void ics_simple_dispatch_pre_save(void *opaque)
{
ICSState *ics = opaque;
@@ -746,15 +613,20 @@ static void ics_simple_realize(DeviceState *dev, Error **errp)
ics->qirqs = qemu_allocate_irqs(ics_simple_set_irq, ics, ics->nr_irqs);
}
+static Property ics_simple_properties[] = {
+ DEFINE_PROP_UINT32("nr-irqs", ICSState, nr_irqs, 0),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
static void ics_simple_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ICSStateClass *isc = ICS_BASE_CLASS(klass);
- dc->realize = ics_simple_realize;
+ isc->realize = ics_simple_realize;
+ dc->props = ics_simple_properties;
dc->vmsd = &vmstate_ics_simple;
dc->reset = ics_simple_reset;
- isc->post_load = ics_simple_post_load;
isc->reject = ics_simple_reject;
isc->resend = ics_simple_resend;
isc->eoi = ics_simple_eoi;
@@ -769,38 +641,69 @@ static const TypeInfo ics_simple_info = {
.instance_init = ics_simple_initfn,
};
+static void ics_base_realize(DeviceState *dev, Error **errp)
+{
+ ICSStateClass *icsc = ICS_BASE_GET_CLASS(dev);
+ ICSState *ics = ICS_BASE(dev);
+ Object *obj;
+ Error *err = NULL;
+
+ obj = object_property_get_link(OBJECT(dev), "xics", &err);
+ if (!obj) {
+ error_setg(errp, "%s: required link 'xics' not found: %s",
+ __func__, error_get_pretty(err));
+ return;
+ }
+ ics->xics = XICS_FABRIC(obj);
+
+
+ if (icsc->realize) {
+ icsc->realize(dev, errp);
+ }
+}
+
+static void ics_base_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->realize = ics_base_realize;
+}
+
static const TypeInfo ics_base_info = {
.name = TYPE_ICS_BASE,
.parent = TYPE_DEVICE,
.abstract = true,
.instance_size = sizeof(ICSState),
+ .class_init = ics_base_class_init,
.class_size = sizeof(ICSStateClass),
};
+static const TypeInfo xics_fabric_info = {
+ .name = TYPE_XICS_FABRIC,
+ .parent = TYPE_INTERFACE,
+ .class_size = sizeof(XICSFabricClass),
+};
+
/*
* Exported functions
*/
-ICSState *xics_find_source(XICSState *xics, int irq)
+qemu_irq xics_get_qirq(XICSFabric *xi, int irq)
{
- ICSState *ics;
+ XICSFabricClass *xic = XICS_FABRIC_GET_CLASS(xi);
+ ICSState *ics = xic->ics_get(xi, irq);
- QLIST_FOREACH(ics, &xics->ics, list) {
- if (ics_valid_irq(ics, irq)) {
- return ics;
- }
+ if (ics) {
+ return ics->qirqs[irq - ics->offset];
}
+
return NULL;
}
-qemu_irq xics_get_qirq(XICSState *xics, int irq)
+ICPState *xics_icp_get(XICSFabric *xi, int server)
{
- ICSState *ics = xics_find_source(xics, irq);
+ XICSFabricClass *xic = XICS_FABRIC_GET_CLASS(xi);
- if (ics) {
- return ics->qirqs[irq - ics->offset];
- }
-
- return NULL;
+ return xic->icp_get(xi, server);
}
void ics_set_irq_type(ICSState *ics, int srcno, bool lsi)
@@ -813,10 +716,10 @@ void ics_set_irq_type(ICSState *ics, int srcno, bool lsi)
static void xics_register_types(void)
{
- type_register_static(&xics_common_info);
type_register_static(&ics_simple_info);
type_register_static(&ics_base_info);
type_register_static(&icp_info);
+ type_register_static(&xics_fabric_info);
}
type_init(xics_register_types)
diff --git a/hw/intc/xics_kvm.c b/hw/intc/xics_kvm.c
index 17694eaa87..0a3daca3bb 100644
--- a/hw/intc/xics_kvm.c
+++ b/hw/intc/xics_kvm.c
@@ -40,16 +40,12 @@
#include <sys/ioctl.h>
-typedef struct KVMXICSState {
- XICSState parent_obj;
-
- int kernel_xics_fd;
-} KVMXICSState;
+static int kernel_xics_fd = -1;
/*
* ICP-KVM
*/
-static void icp_get_kvm_state(ICPState *ss)
+static void icp_get_kvm_state(ICPState *icp)
{
uint64_t state;
struct kvm_one_reg reg = {
@@ -59,25 +55,25 @@ static void icp_get_kvm_state(ICPState *ss)
int ret;
/* ICP for this CPU thread is not in use, exiting */
- if (!ss->cs) {
+ if (!icp->cs) {
return;
}
- ret = kvm_vcpu_ioctl(ss->cs, KVM_GET_ONE_REG, &reg);
+ ret = kvm_vcpu_ioctl(icp->cs, KVM_GET_ONE_REG, &reg);
if (ret != 0) {
error_report("Unable to retrieve KVM interrupt controller state"
- " for CPU %ld: %s", kvm_arch_vcpu_id(ss->cs), strerror(errno));
+ " for CPU %ld: %s", kvm_arch_vcpu_id(icp->cs), strerror(errno));
exit(1);
}
- ss->xirr = state >> KVM_REG_PPC_ICP_XISR_SHIFT;
- ss->mfrr = (state >> KVM_REG_PPC_ICP_MFRR_SHIFT)
+ icp->xirr = state >> KVM_REG_PPC_ICP_XISR_SHIFT;
+ icp->mfrr = (state >> KVM_REG_PPC_ICP_MFRR_SHIFT)
& KVM_REG_PPC_ICP_MFRR_MASK;
- ss->pending_priority = (state >> KVM_REG_PPC_ICP_PPRI_SHIFT)
+ icp->pending_priority = (state >> KVM_REG_PPC_ICP_PPRI_SHIFT)
& KVM_REG_PPC_ICP_PPRI_MASK;
}
-static int icp_set_kvm_state(ICPState *ss, int version_id)
+static int icp_set_kvm_state(ICPState *icp, int version_id)
{
uint64_t state;
struct kvm_one_reg reg = {
@@ -87,18 +83,18 @@ static int icp_set_kvm_state(ICPState *ss, int version_id)
int ret;
/* ICP for this CPU thread is not in use, exiting */
- if (!ss->cs) {
+ if (!icp->cs) {
return 0;
}
- state = ((uint64_t)ss->xirr << KVM_REG_PPC_ICP_XISR_SHIFT)
- | ((uint64_t)ss->mfrr << KVM_REG_PPC_ICP_MFRR_SHIFT)
- | ((uint64_t)ss->pending_priority << KVM_REG_PPC_ICP_PPRI_SHIFT);
+ state = ((uint64_t)icp->xirr << KVM_REG_PPC_ICP_XISR_SHIFT)
+ | ((uint64_t)icp->mfrr << KVM_REG_PPC_ICP_MFRR_SHIFT)
+ | ((uint64_t)icp->pending_priority << KVM_REG_PPC_ICP_PPRI_SHIFT);
- ret = kvm_vcpu_ioctl(ss->cs, KVM_SET_ONE_REG, &reg);
+ ret = kvm_vcpu_ioctl(icp->cs, KVM_SET_ONE_REG, &reg);
if (ret != 0) {
error_report("Unable to restore KVM interrupt controller state (0x%"
- PRIx64 ") for CPU %ld: %s", state, kvm_arch_vcpu_id(ss->cs),
+ PRIx64 ") for CPU %ld: %s", state, kvm_arch_vcpu_id(icp->cs),
strerror(errno));
return ret;
}
@@ -122,6 +118,34 @@ static void icp_kvm_reset(DeviceState *dev)
icp_set_kvm_state(icp, 1);
}
+static void icp_kvm_cpu_setup(ICPState *icp, PowerPCCPU *cpu)
+{
+ CPUState *cs = CPU(cpu);
+ int ret;
+
+ if (kernel_xics_fd == -1) {
+ abort();
+ }
+
+ /*
+ * If we are reusing a parked vCPU fd corresponding to the CPU
+ * which was hot-removed earlier we don't have to renable
+ * KVM_CAP_IRQ_XICS capability again.
+ */
+ if (icp->cap_irq_xics_enabled) {
+ return;
+ }
+
+ ret = kvm_vcpu_enable_cap(cs, KVM_CAP_IRQ_XICS, 0, kernel_xics_fd,
+ kvm_arch_vcpu_id(cs));
+ if (ret < 0) {
+ error_report("Unable to connect CPU%ld to kernel XICS: %s",
+ kvm_arch_vcpu_id(cs), strerror(errno));
+ exit(1);
+ }
+ icp->cap_irq_xics_enabled = true;
+}
+
static void icp_kvm_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -130,6 +154,7 @@ static void icp_kvm_class_init(ObjectClass *klass, void *data)
dc->reset = icp_kvm_reset;
icpc->pre_save = icp_get_kvm_state;
icpc->post_load = icp_set_kvm_state;
+ icpc->cpu_setup = icp_kvm_cpu_setup;
}
static const TypeInfo icp_kvm_info = {
@@ -145,7 +170,6 @@ static const TypeInfo icp_kvm_info = {
*/
static void ics_get_kvm_state(ICSState *ics)
{
- KVMXICSState *xicskvm = XICS_SPAPR_KVM(ics->xics);
uint64_t state;
struct kvm_device_attr attr = {
.flags = 0,
@@ -160,7 +184,7 @@ static void ics_get_kvm_state(ICSState *ics)
attr.attr = i + ics->offset;
- ret = ioctl(xicskvm->kernel_xics_fd, KVM_GET_DEVICE_ATTR, &attr);
+ ret = ioctl(kernel_xics_fd, KVM_GET_DEVICE_ATTR, &attr);
if (ret != 0) {
error_report("Unable to retrieve KVM interrupt controller state"
" for IRQ %d: %s", i + ics->offset, strerror(errno));
@@ -204,7 +228,6 @@ static void ics_get_kvm_state(ICSState *ics)
static int ics_set_kvm_state(ICSState *ics, int version_id)
{
- KVMXICSState *xicskvm = XICS_SPAPR_KVM(ics->xics);
uint64_t state;
struct kvm_device_attr attr = {
.flags = 0,
@@ -238,7 +261,7 @@ static int ics_set_kvm_state(ICSState *ics, int version_id)
}
}
- ret = ioctl(xicskvm->kernel_xics_fd, KVM_SET_DEVICE_ATTR, &attr);
+ ret = ioctl(kernel_xics_fd, KVM_SET_DEVICE_ATTR, &attr);
if (ret != 0) {
error_report("Unable to restore KVM interrupt controller state"
" for IRQs %d: %s", i + ics->offset, strerror(errno));
@@ -308,7 +331,7 @@ static void ics_kvm_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
ICSStateClass *icsc = ICS_BASE_CLASS(klass);
- dc->realize = ics_kvm_realize;
+ icsc->realize = ics_kvm_realize;
dc->reset = ics_kvm_reset;
icsc->pre_save = ics_get_kvm_state;
icsc->post_load = ics_set_kvm_state;
@@ -324,57 +347,6 @@ static const TypeInfo ics_kvm_info = {
/*
* XICS-KVM
*/
-static void xics_kvm_cpu_setup(XICSState *xics, PowerPCCPU *cpu)
-{
- CPUState *cs;
- ICPState *ss;
- KVMXICSState *xicskvm = XICS_SPAPR_KVM(xics);
- int ret;
-
- cs = CPU(cpu);
- ss = &xics->ss[cs->cpu_index];
-
- assert(cs->cpu_index < xics->nr_servers);
- if (xicskvm->kernel_xics_fd == -1) {
- abort();
- }
-
- /*
- * If we are reusing a parked vCPU fd corresponding to the CPU
- * which was hot-removed earlier we don't have to renable
- * KVM_CAP_IRQ_XICS capability again.
- */
- if (ss->cap_irq_xics_enabled) {
- return;
- }
-
- ret = kvm_vcpu_enable_cap(cs, KVM_CAP_IRQ_XICS, 0, xicskvm->kernel_xics_fd,
- kvm_arch_vcpu_id(cs));
- if (ret < 0) {
- error_report("Unable to connect CPU%ld to kernel XICS: %s",
- kvm_arch_vcpu_id(cs), strerror(errno));
- exit(1);
- }
- ss->cap_irq_xics_enabled = true;
-}
-
-static void xics_kvm_set_nr_irqs(XICSState *xics, uint32_t nr_irqs,
- Error **errp)
-{
- ICSState *ics = QLIST_FIRST(&xics->ics);
-
- /* This needs to be deprecated ... */
- xics->nr_irqs = nr_irqs;
- if (ics) {
- ics->nr_irqs = nr_irqs;
- }
-}
-
-static void xics_kvm_set_nr_servers(XICSState *xics, uint32_t nr_servers,
- Error **errp)
-{
- xics_set_nr_servers(xics, nr_servers, TYPE_KVM_ICP, errp);
-}
static void rtas_dummy(PowerPCCPU *cpu, sPAPRMachineState *spapr,
uint32_t token,
@@ -385,13 +357,9 @@ static void rtas_dummy(PowerPCCPU *cpu, sPAPRMachineState *spapr,
__func__);
}
-static void xics_kvm_realize(DeviceState *dev, Error **errp)
+int xics_kvm_init(sPAPRMachineState *spapr, Error **errp)
{
- KVMXICSState *xicskvm = XICS_SPAPR_KVM(dev);
- XICSState *xics = XICS_COMMON(dev);
- ICSState *ics;
- int i, rc;
- Error *error = NULL;
+ int rc;
struct kvm_create_device xics_create_device = {
.type = KVM_DEV_TYPE_XICS,
.flags = 0,
@@ -439,72 +407,24 @@ static void xics_kvm_realize(DeviceState *dev, Error **errp)
goto fail;
}
- xicskvm->kernel_xics_fd = xics_create_device.fd;
-
- QLIST_FOREACH(ics, &xics->ics, list) {
- object_property_set_bool(OBJECT(ics), true, "realized", &error);
- if (error) {
- error_propagate(errp, error);
- goto fail;
- }
- }
-
- assert(xics->nr_servers);
- for (i = 0; i < xics->nr_servers; i++) {
- object_property_set_bool(OBJECT(&xics->ss[i]), true, "realized",
- &error);
- if (error) {
- error_propagate(errp, error);
- goto fail;
- }
- }
+ kernel_xics_fd = xics_create_device.fd;
kvm_kernel_irqchip = true;
kvm_msi_via_irqfd_allowed = true;
kvm_gsi_direct_mapping = true;
- return;
+ return rc;
fail:
kvmppc_define_rtas_kernel_token(0, "ibm,set-xive");
kvmppc_define_rtas_kernel_token(0, "ibm,get-xive");
kvmppc_define_rtas_kernel_token(0, "ibm,int-on");
kvmppc_define_rtas_kernel_token(0, "ibm,int-off");
+ return -1;
}
-static void xics_kvm_initfn(Object *obj)
-{
- XICSState *xics = XICS_COMMON(obj);
- ICSState *ics;
-
- ics = ICS_SIMPLE(object_new(TYPE_ICS_KVM));
- object_property_add_child(obj, "ics", OBJECT(ics), NULL);
- ics->xics = xics;
- QLIST_INSERT_HEAD(&xics->ics, ics, list);
-}
-
-static void xics_kvm_class_init(ObjectClass *oc, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(oc);
- XICSStateClass *xsc = XICS_COMMON_CLASS(oc);
-
- dc->realize = xics_kvm_realize;
- xsc->cpu_setup = xics_kvm_cpu_setup;
- xsc->set_nr_irqs = xics_kvm_set_nr_irqs;
- xsc->set_nr_servers = xics_kvm_set_nr_servers;
-}
-
-static const TypeInfo xics_spapr_kvm_info = {
- .name = TYPE_XICS_SPAPR_KVM,
- .parent = TYPE_XICS_COMMON,
- .instance_size = sizeof(KVMXICSState),
- .class_init = xics_kvm_class_init,
- .instance_init = xics_kvm_initfn,
-};
-
static void xics_kvm_register_types(void)
{
- type_register_static(&xics_spapr_kvm_info);
type_register_static(&ics_kvm_info);
type_register_static(&icp_kvm_info);
}
diff --git a/hw/intc/xics_spapr.c b/hw/intc/xics_spapr.c
index 2e3f1c5e95..84d24b2837 100644
--- a/hw/intc/xics_spapr.c
+++ b/hw/intc/xics_spapr.c
@@ -44,7 +44,7 @@ static target_ulong h_cppr(PowerPCCPU *cpu, sPAPRMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
CPUState *cs = CPU(cpu);
- ICPState *icp = &spapr->xics->ss[cs->cpu_index];
+ ICPState *icp = xics_icp_get(XICS_FABRIC(spapr), cs->cpu_index);
target_ulong cppr = args[0];
icp_set_cppr(icp, cppr);
@@ -56,12 +56,13 @@ static target_ulong h_ipi(PowerPCCPU *cpu, sPAPRMachineState *spapr,
{
target_ulong server = xics_get_cpu_index_by_dt_id(args[0]);
target_ulong mfrr = args[1];
+ ICPState *icp = xics_icp_get(XICS_FABRIC(spapr), server);
- if (server >= spapr->xics->nr_servers) {
+ if (!icp) {
return H_PARAMETER;
}
- icp_set_mfrr(spapr->xics->ss + server, mfrr);
+ icp_set_mfrr(icp, mfrr);
return H_SUCCESS;
}
@@ -69,7 +70,7 @@ static target_ulong h_xirr(PowerPCCPU *cpu, sPAPRMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
CPUState *cs = CPU(cpu);
- ICPState *icp = &spapr->xics->ss[cs->cpu_index];
+ ICPState *icp = xics_icp_get(XICS_FABRIC(spapr), cs->cpu_index);
uint32_t xirr = icp_accept(icp);
args[0] = xirr;
@@ -80,7 +81,7 @@ static target_ulong h_xirr_x(PowerPCCPU *cpu, sPAPRMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
CPUState *cs = CPU(cpu);
- ICPState *icp = &spapr->xics->ss[cs->cpu_index];
+ ICPState *icp = xics_icp_get(XICS_FABRIC(spapr), cs->cpu_index);
uint32_t xirr = icp_accept(icp);
args[0] = xirr;
@@ -92,7 +93,7 @@ static target_ulong h_eoi(PowerPCCPU *cpu, sPAPRMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
CPUState *cs = CPU(cpu);
- ICPState *icp = &spapr->xics->ss[cs->cpu_index];
+ ICPState *icp = xics_icp_get(XICS_FABRIC(spapr), cs->cpu_index);
target_ulong xirr = args[0];
icp_eoi(icp, xirr);
@@ -103,7 +104,7 @@ static target_ulong h_ipoll(PowerPCCPU *cpu, sPAPRMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
CPUState *cs = CPU(cpu);
- ICPState *icp = &spapr->xics->ss[cs->cpu_index];
+ ICPState *icp = xics_icp_get(XICS_FABRIC(spapr), cs->cpu_index);
uint32_t mfrr;
uint32_t xirr = icp_ipoll(icp, &mfrr);
@@ -118,7 +119,7 @@ static void rtas_set_xive(PowerPCCPU *cpu, sPAPRMachineState *spapr,
uint32_t nargs, target_ulong args,
uint32_t nret, target_ulong rets)
{
- ICSState *ics = QLIST_FIRST(&spapr->xics->ics);
+ ICSState *ics = spapr->ics;
uint32_t nr, srcno, server, priority;
if ((nargs != 3) || (nret != 1)) {
@@ -134,7 +135,7 @@ static void rtas_set_xive(PowerPCCPU *cpu, sPAPRMachineState *spapr,
server = xics_get_cpu_index_by_dt_id(rtas_ld(args, 1));
priority = rtas_ld(args, 2);
- if (!ics_valid_irq(ics, nr) || (server >= ics->xics->nr_servers)
+ if (!ics_valid_irq(ics, nr) || !xics_icp_get(XICS_FABRIC(spapr), server)
|| (priority > 0xff)) {
rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
return;
@@ -151,7 +152,7 @@ static void rtas_get_xive(PowerPCCPU *cpu, sPAPRMachineState *spapr,
uint32_t nargs, target_ulong args,
uint32_t nret, target_ulong rets)
{
- ICSState *ics = QLIST_FIRST(&spapr->xics->ics);
+ ICSState *ics = spapr->ics;
uint32_t nr, srcno;
if ((nargs != 1) || (nret != 3)) {
@@ -181,7 +182,7 @@ static void rtas_int_off(PowerPCCPU *cpu, sPAPRMachineState *spapr,
uint32_t nargs, target_ulong args,
uint32_t nret, target_ulong rets)
{
- ICSState *ics = QLIST_FIRST(&spapr->xics->ics);
+ ICSState *ics = spapr->ics;
uint32_t nr, srcno;
if ((nargs != 1) || (nret != 1)) {
@@ -212,7 +213,7 @@ static void rtas_int_on(PowerPCCPU *cpu, sPAPRMachineState *spapr,
uint32_t nargs, target_ulong args,
uint32_t nret, target_ulong rets)
{
- ICSState *ics = QLIST_FIRST(&spapr->xics->ics);
+ ICSState *ics = spapr->ics;
uint32_t nr, srcno;
if ((nargs != 1) || (nret != 1)) {
@@ -239,36 +240,8 @@ static void rtas_int_on(PowerPCCPU *cpu, sPAPRMachineState *spapr,
rtas_st(rets, 0, RTAS_OUT_SUCCESS);
}
-static void xics_spapr_set_nr_irqs(XICSState *xics, uint32_t nr_irqs,
- Error **errp)
+int xics_spapr_init(sPAPRMachineState *spapr, Error **errp)
{
- ICSState *ics = QLIST_FIRST(&xics->ics);
-
- /* This needs to be deprecated ... */
- xics->nr_irqs = nr_irqs;
- if (ics) {
- ics->nr_irqs = nr_irqs;
- }
-}
-
-static void xics_spapr_set_nr_servers(XICSState *xics, uint32_t nr_servers,
- Error **errp)
-{
- xics_set_nr_servers(xics, nr_servers, TYPE_ICP, errp);
-}
-
-static void xics_spapr_realize(DeviceState *dev, Error **errp)
-{
- XICSState *xics = XICS_SPAPR(dev);
- ICSState *ics;
- Error *error = NULL;
- int i;
-
- if (!xics->nr_servers) {
- error_setg(errp, "Number of servers needs to be greater 0");
- return;
- }
-
/* Registration of global state belongs into realize */
spapr_rtas_register(RTAS_IBM_SET_XIVE, "ibm,set-xive", rtas_set_xive);
spapr_rtas_register(RTAS_IBM_GET_XIVE, "ibm,get-xive", rtas_get_xive);
@@ -281,55 +254,9 @@ static void xics_spapr_realize(DeviceState *dev, Error **errp)
spapr_register_hypercall(H_XIRR_X, h_xirr_x);
spapr_register_hypercall(H_EOI, h_eoi);
spapr_register_hypercall(H_IPOLL, h_ipoll);
-
- QLIST_FOREACH(ics, &xics->ics, list) {
- object_property_set_bool(OBJECT(ics), true, "realized", &error);
- if (error) {
- error_propagate(errp, error);
- return;
- }
- }
-
- for (i = 0; i < xics->nr_servers; i++) {
- object_property_set_bool(OBJECT(&xics->ss[i]), true, "realized",
- &error);
- if (error) {
- error_propagate(errp, error);
- return;
- }
- }
-}
-
-static void xics_spapr_initfn(Object *obj)
-{
- XICSState *xics = XICS_SPAPR(obj);
- ICSState *ics;
-
- ics = ICS_SIMPLE(object_new(TYPE_ICS_SIMPLE));
- object_property_add_child(obj, "ics", OBJECT(ics), NULL);
- ics->xics = xics;
- QLIST_INSERT_HEAD(&xics->ics, ics, list);
-}
-
-static void xics_spapr_class_init(ObjectClass *oc, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(oc);
- XICSStateClass *xsc = XICS_SPAPR_CLASS(oc);
-
- dc->realize = xics_spapr_realize;
- xsc->set_nr_irqs = xics_spapr_set_nr_irqs;
- xsc->set_nr_servers = xics_spapr_set_nr_servers;
+ return 0;
}
-static const TypeInfo xics_spapr_info = {
- .name = TYPE_XICS_SPAPR,
- .parent = TYPE_XICS_COMMON,
- .instance_size = sizeof(XICSState),
- .class_size = sizeof(XICSStateClass),
- .class_init = xics_spapr_class_init,
- .instance_init = xics_spapr_initfn,
-};
-
#define ICS_IRQ_FREE(ics, srcno) \
(!((ics)->irqs[(srcno)].flags & (XICS_FLAGS_IRQ_MASK)))
@@ -354,9 +281,8 @@ static int ics_find_free_block(ICSState *ics, int num, int alignnum)
return -1;
}
-int xics_spapr_alloc(XICSState *xics, int irq_hint, bool lsi, Error **errp)
+int spapr_ics_alloc(ICSState *ics, int irq_hint, bool lsi, Error **errp)
{
- ICSState *ics = QLIST_FIRST(&xics->ics);
int irq;
if (!ics) {
@@ -387,10 +313,9 @@ int xics_spapr_alloc(XICSState *xics, int irq_hint, bool lsi, Error **errp)
* Allocate block of consecutive IRQs, and return the number of the first IRQ in
* the block. If align==true, aligns the first IRQ number to num.
*/
-int xics_spapr_alloc_block(XICSState *xics, int num, bool lsi, bool align,
- Error **errp)
+int spapr_ics_alloc_block(ICSState *ics, int num, bool lsi,
+ bool align, Error **errp)
{
- ICSState *ics = QLIST_FIRST(&xics->ics);
int i, first = -1;
if (!ics) {
@@ -440,20 +365,18 @@ static void ics_free(ICSState *ics, int srcno, int num)
}
}
-void xics_spapr_free(XICSState *xics, int irq, int num)
+void spapr_ics_free(ICSState *ics, int irq, int num)
{
- ICSState *ics = xics_find_source(xics, irq);
-
- if (ics) {
+ if (ics_valid_irq(ics, irq)) {
trace_xics_ics_free(0, irq, num);
ics_free(ics, irq - ics->offset, num);
}
}
-void spapr_dt_xics(XICSState *xics, void *fdt, uint32_t phandle)
+void spapr_dt_xics(int nr_servers, void *fdt, uint32_t phandle)
{
uint32_t interrupt_server_ranges_prop[] = {
- 0, cpu_to_be32(xics->nr_servers),
+ 0, cpu_to_be32(nr_servers),
};
int node;
@@ -470,10 +393,3 @@ void spapr_dt_xics(XICSState *xics, void *fdt, uint32_t phandle)
_FDT(fdt_setprop_cell(fdt, node, "linux,phandle", phandle));
_FDT(fdt_setprop_cell(fdt, node, "phandle", phandle));
}
-
-static void xics_spapr_register_types(void)
-{
- type_register_static(&xics_spapr_info);
-}
-
-type_init(xics_spapr_register_types)
diff --git a/hw/nvram/spapr_nvram.c b/hw/nvram/spapr_nvram.c
index 65ba188555..aa5d2c1f5f 100644
--- a/hw/nvram/spapr_nvram.c
+++ b/hw/nvram/spapr_nvram.c
@@ -141,9 +141,17 @@ static void rtas_nvram_store(PowerPCCPU *cpu, sPAPRMachineState *spapr,
static void spapr_nvram_realize(VIOsPAPRDevice *dev, Error **errp)
{
sPAPRNVRAM *nvram = VIO_SPAPR_NVRAM(dev);
+ int ret;
if (nvram->blk) {
nvram->size = blk_getlength(nvram->blk);
+
+ ret = blk_set_perm(nvram->blk,
+ BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE,
+ BLK_PERM_ALL, errp);
+ if (ret < 0) {
+ return;
+ }
} else {
nvram->size = DEFAULT_NVRAM_SIZE;
}
diff --git a/hw/pci/pci.c b/hw/pci/pci.c
index a563555e7d..273f1e4602 100644
--- a/hw/pci/pci.c
+++ b/hw/pci/pci.c
@@ -1530,6 +1530,34 @@ static const pci_class_desc pci_class_descriptions[] =
{ 0, NULL}
};
+static void pci_for_each_device_under_bus_reverse(PCIBus *bus,
+ void (*fn)(PCIBus *b,
+ PCIDevice *d,
+ void *opaque),
+ void *opaque)
+{
+ PCIDevice *d;
+ int devfn;
+
+ for (devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) {
+ d = bus->devices[ARRAY_SIZE(bus->devices) - 1 - devfn];
+ if (d) {
+ fn(bus, d, opaque);
+ }
+ }
+}
+
+void pci_for_each_device_reverse(PCIBus *bus, int bus_num,
+ void (*fn)(PCIBus *b, PCIDevice *d, void *opaque),
+ void *opaque)
+{
+ bus = pci_find_bus_nr(bus, bus_num);
+
+ if (bus) {
+ pci_for_each_device_under_bus_reverse(bus, fn, opaque);
+ }
+}
+
static void pci_for_each_device_under_bus(PCIBus *bus,
void (*fn)(PCIBus *b, PCIDevice *d,
void *opaque),
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index 87d8366c44..81c6c1c27c 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -63,6 +63,7 @@
#include "qemu/error-report.h"
#include "trace.h"
#include "hw/nmi.h"
+#include "hw/intc/intc.h"
#include "hw/compat.h"
#include "qemu/cutils.h"
@@ -95,37 +96,68 @@
#define HTAB_SIZE(spapr) (1ULL << ((spapr)->htab_shift))
-static XICSState *try_create_xics(const char *type, int nr_servers,
- int nr_irqs, Error **errp)
+static int try_create_xics(sPAPRMachineState *spapr, const char *type_ics,
+ const char *type_icp, int nr_servers,
+ int nr_irqs, Error **errp)
{
- Error *err = NULL;
- DeviceState *dev;
+ XICSFabric *xi = XICS_FABRIC(spapr);
+ Error *err = NULL, *local_err = NULL;
+ ICSState *ics = NULL;
+ int i;
- dev = qdev_create(NULL, type);
- qdev_prop_set_uint32(dev, "nr_servers", nr_servers);
- qdev_prop_set_uint32(dev, "nr_irqs", nr_irqs);
- object_property_set_bool(OBJECT(dev), true, "realized", &err);
+ ics = ICS_SIMPLE(object_new(type_ics));
+ qdev_set_parent_bus(DEVICE(ics), sysbus_get_default());
+ object_property_add_child(OBJECT(spapr), "ics", OBJECT(ics), NULL);
+ object_property_set_int(OBJECT(ics), nr_irqs, "nr-irqs", &err);
+ object_property_add_const_link(OBJECT(ics), "xics", OBJECT(xi), NULL);
+ object_property_set_bool(OBJECT(ics), true, "realized", &local_err);
+ error_propagate(&err, local_err);
if (err) {
- error_propagate(errp, err);
- object_unparent(OBJECT(dev));
- return NULL;
+ goto error;
}
- return XICS_COMMON(dev);
+
+ spapr->icps = g_malloc0(nr_servers * sizeof(ICPState));
+ spapr->nr_servers = nr_servers;
+
+ for (i = 0; i < nr_servers; i++) {
+ ICPState *icp = &spapr->icps[i];
+
+ object_initialize(icp, sizeof(*icp), type_icp);
+ qdev_set_parent_bus(DEVICE(icp), sysbus_get_default());
+ object_property_add_child(OBJECT(spapr), "icp[*]", OBJECT(icp), NULL);
+ object_property_add_const_link(OBJECT(icp), "xics", OBJECT(xi), NULL);
+ object_property_set_bool(OBJECT(icp), true, "realized", &err);
+ if (err) {
+ goto error;
+ }
+ object_unref(OBJECT(icp));
+ }
+
+ spapr->ics = ics;
+ return 0;
+
+error:
+ error_propagate(errp, err);
+ if (ics) {
+ object_unparent(OBJECT(ics));
+ }
+ return -1;
}
-static XICSState *xics_system_init(MachineState *machine,
- int nr_servers, int nr_irqs, Error **errp)
+static int xics_system_init(MachineState *machine,
+ int nr_servers, int nr_irqs, Error **errp)
{
- XICSState *xics = NULL;
+ int rc = -1;
if (kvm_enabled()) {
Error *err = NULL;
- if (machine_kernel_irqchip_allowed(machine)) {
- xics = try_create_xics(TYPE_XICS_SPAPR_KVM, nr_servers, nr_irqs,
- &err);
+ if (machine_kernel_irqchip_allowed(machine) &&
+ !xics_kvm_init(SPAPR_MACHINE(machine), errp)) {
+ rc = try_create_xics(SPAPR_MACHINE(machine), TYPE_ICS_KVM,
+ TYPE_KVM_ICP, nr_servers, nr_irqs, &err);
}
- if (machine_kernel_irqchip_required(machine) && !xics) {
+ if (machine_kernel_irqchip_required(machine) && rc < 0) {
error_reportf_err(err,
"kernel_irqchip requested but unavailable: ");
} else {
@@ -133,11 +165,13 @@ static XICSState *xics_system_init(MachineState *machine,
}
}
- if (!xics) {
- xics = try_create_xics(TYPE_XICS_SPAPR, nr_servers, nr_irqs, errp);
+ if (rc < 0) {
+ xics_spapr_init(SPAPR_MACHINE(machine), errp);
+ rc = try_create_xics(SPAPR_MACHINE(machine), TYPE_ICS_SIMPLE,
+ TYPE_ICP, nr_servers, nr_irqs, errp);
}
- return xics;
+ return rc;
}
static int spapr_fixup_cpu_smt_dt(void *fdt, int offset, PowerPCCPU *cpu,
@@ -924,7 +958,7 @@ static void *spapr_build_fdt(sPAPRMachineState *spapr,
_FDT(fdt_setprop_cell(fdt, 0, "#size-cells", 2));
/* /interrupt controller */
- spapr_dt_xics(spapr->xics, fdt, PHANDLE_XICP);
+ spapr_dt_xics(spapr->nr_servers, fdt, PHANDLE_XICP);
ret = spapr_populate_memory(spapr, fdt);
if (ret < 0) {
@@ -1053,6 +1087,62 @@ static void close_htab_fd(sPAPRMachineState *spapr)
spapr->htab_fd = -1;
}
+static hwaddr spapr_hpt_mask(PPCVirtualHypervisor *vhyp)
+{
+ sPAPRMachineState *spapr = SPAPR_MACHINE(vhyp);
+
+ return HTAB_SIZE(spapr) / HASH_PTEG_SIZE_64 - 1;
+}
+
+static const ppc_hash_pte64_t *spapr_map_hptes(PPCVirtualHypervisor *vhyp,
+ hwaddr ptex, int n)
+{
+ sPAPRMachineState *spapr = SPAPR_MACHINE(vhyp);
+ hwaddr pte_offset = ptex * HASH_PTE_SIZE_64;
+
+ if (!spapr->htab) {
+ /*
+ * HTAB is controlled by KVM. Fetch into temporary buffer
+ */
+ ppc_hash_pte64_t *hptes = g_malloc(n * HASH_PTE_SIZE_64);
+ kvmppc_read_hptes(hptes, ptex, n);
+ return hptes;
+ }
+
+ /*
+ * HTAB is controlled by QEMU. Just point to the internally
+ * accessible PTEG.
+ */
+ return (const ppc_hash_pte64_t *)(spapr->htab + pte_offset);
+}
+
+static void spapr_unmap_hptes(PPCVirtualHypervisor *vhyp,
+ const ppc_hash_pte64_t *hptes,
+ hwaddr ptex, int n)
+{
+ sPAPRMachineState *spapr = SPAPR_MACHINE(vhyp);
+
+ if (!spapr->htab) {
+ g_free((void *)hptes);
+ }
+
+ /* Nothing to do for qemu managed HPT */
+}
+
+static void spapr_store_hpte(PPCVirtualHypervisor *vhyp, hwaddr ptex,
+ uint64_t pte0, uint64_t pte1)
+{
+ sPAPRMachineState *spapr = SPAPR_MACHINE(vhyp);
+ hwaddr offset = ptex * HASH_PTE_SIZE_64;
+
+ if (!spapr->htab) {
+ kvmppc_write_hpte(ptex, pte0, pte1);
+ } else {
+ stq_p(spapr->htab + offset, pte0);
+ stq_p(spapr->htab + offset + HASH_PTE_SIZE_64 / 2, pte1);
+ }
+}
+
static int spapr_hpt_shift_for_ramsize(uint64_t ramsize)
{
int shift;
@@ -1252,6 +1342,13 @@ static int spapr_post_load(void *opaque, int version_id)
sPAPRMachineState *spapr = (sPAPRMachineState *)opaque;
int err = 0;
+ if (!object_dynamic_cast(OBJECT(spapr->ics), TYPE_ICS_KVM)) {
+ int i;
+ for (i = 0; i < spapr->nr_servers; i++) {
+ icp_resend(&spapr->icps[i]);
+ }
+ }
+
/* In earlier versions, there was no separate qdev for the PAPR
* RTC, so the RTC offset was stored directly in sPAPREnvironment.
* So when migrating from those versions, poke the incoming offset
@@ -1902,9 +1999,8 @@ static void ppc_spapr_init(MachineState *machine)
load_limit = MIN(spapr->rma_size, RTAS_MAX_ADDR) - FW_OVERHEAD;
/* Set up Interrupt Controller before we create the VCPUs */
- spapr->xics = xics_system_init(machine,
- DIV_ROUND_UP(max_cpus * smt, smp_threads),
- XICS_IRQS_SPAPR, &error_fatal);
+ xics_system_init(machine, DIV_ROUND_UP(max_cpus * smt, smp_threads),
+ XICS_IRQS_SPAPR, &error_fatal);
/* Set up containers for ibm,client-set-architecture negotiated options */
spapr->ov5 = spapr_ovec_new();
@@ -2872,6 +2968,40 @@ static void spapr_phb_placement(sPAPRMachineState *spapr, uint32_t index,
*mmio64 = SPAPR_PCI_BASE + (index + 1) * SPAPR_PCI_MEM64_WIN_SIZE;
}
+static ICSState *spapr_ics_get(XICSFabric *dev, int irq)
+{
+ sPAPRMachineState *spapr = SPAPR_MACHINE(dev);
+
+ return ics_valid_irq(spapr->ics, irq) ? spapr->ics : NULL;
+}
+
+static void spapr_ics_resend(XICSFabric *dev)
+{
+ sPAPRMachineState *spapr = SPAPR_MACHINE(dev);
+
+ ics_resend(spapr->ics);
+}
+
+static ICPState *spapr_icp_get(XICSFabric *xi, int server)
+{
+ sPAPRMachineState *spapr = SPAPR_MACHINE(xi);
+
+ return (server < spapr->nr_servers) ? &spapr->icps[server] : NULL;
+}
+
+static void spapr_pic_print_info(InterruptStatsProvider *obj,
+ Monitor *mon)
+{
+ sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
+ int i;
+
+ for (i = 0; i < spapr->nr_servers; i++) {
+ icp_pic_print_info(&spapr->icps[i], mon);
+ }
+
+ ics_pic_print_info(spapr->ics, mon);
+}
+
static void spapr_machine_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
@@ -2880,6 +3010,8 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data)
NMIClass *nc = NMI_CLASS(oc);
HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc);
PPCVirtualHypervisorClass *vhc = PPC_VIRTUAL_HYPERVISOR_CLASS(oc);
+ XICSFabricClass *xic = XICS_FABRIC_CLASS(oc);
+ InterruptStatsProviderClass *ispc = INTERRUPT_STATS_PROVIDER_CLASS(oc);
mc->desc = "pSeries Logical Partition (PAPR compliant)";
@@ -2891,7 +3023,7 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data)
mc->init = ppc_spapr_init;
mc->reset = ppc_spapr_reset;
mc->block_default_type = IF_SCSI;
- mc->max_cpus = 255;
+ mc->max_cpus = 1024;
mc->no_parallel = 1;
mc->default_boot_order = "";
mc->default_ram_size = 512 * M_BYTE;
@@ -2913,6 +3045,14 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data)
nc->nmi_monitor_handler = spapr_nmi;
smc->phb_placement = spapr_phb_placement;
vhc->hypercall = emulate_spapr_hypercall;
+ vhc->hpt_mask = spapr_hpt_mask;
+ vhc->map_hptes = spapr_map_hptes;
+ vhc->unmap_hptes = spapr_unmap_hptes;
+ vhc->store_hpte = spapr_store_hpte;
+ xic->ics_get = spapr_ics_get;
+ xic->ics_resend = spapr_ics_resend;
+ xic->icp_get = spapr_icp_get;
+ ispc->print_info = spapr_pic_print_info;
}
static const TypeInfo spapr_machine_info = {
@@ -2929,6 +3069,8 @@ static const TypeInfo spapr_machine_info = {
{ TYPE_NMI },
{ TYPE_HOTPLUG_HANDLER },
{ TYPE_PPC_VIRTUAL_HYPERVISOR },
+ { TYPE_XICS_FABRIC },
+ { TYPE_INTERRUPT_STATS_PROVIDER },
{ }
},
};
diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c
index 55cd0456eb..90d682fe33 100644
--- a/hw/ppc/spapr_cpu_core.c
+++ b/hw/ppc/spapr_cpu_core.c
@@ -13,10 +13,12 @@
#include "hw/boards.h"
#include "qapi/error.h"
#include "sysemu/cpus.h"
+#include "sysemu/kvm.h"
#include "target/ppc/kvm_ppc.h"
#include "hw/ppc/ppc.h"
#include "target/ppc/mmu-hash64.h"
#include "sysemu/numa.h"
+#include "qemu/error-report.h"
static void spapr_cpu_reset(void *opaque)
{
@@ -34,15 +36,26 @@ static void spapr_cpu_reset(void *opaque)
env->spr[SPR_HIOR] = 0;
- ppc_hash64_set_external_hpt(cpu, spapr->htab, spapr->htab_shift,
- &error_fatal);
+ /*
+ * This is a hack for the benefit of KVM PR - it abuses the SDR1
+ * slot in kvm_sregs to communicate the userspace address of the
+ * HPT
+ */
+ if (kvm_enabled()) {
+ env->spr[SPR_SDR1] = (target_ulong)(uintptr_t)spapr->htab
+ | (spapr->htab_shift - 18);
+ if (kvmppc_put_books_sregs(cpu) < 0) {
+ error_report("Unable to update SDR1 in KVM");
+ exit(1);
+ }
+ }
}
static void spapr_cpu_destroy(PowerPCCPU *cpu)
{
sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
- xics_cpu_destroy(spapr->xics, cpu);
+ xics_cpu_destroy(XICS_FABRIC(spapr), cpu);
qemu_unregister_reset(spapr_cpu_reset, cpu);
}
@@ -57,8 +70,7 @@ static void spapr_cpu_init(sPAPRMachineState *spapr, PowerPCCPU *cpu,
cpu_ppc_tb_init(env, SPAPR_TIMEBASE_FREQ);
/* Enable PAPR mode in TCG or KVM */
- cpu_ppc_set_vhyp(cpu, PPC_VIRTUAL_HYPERVISOR(spapr));
- cpu_ppc_set_papr(cpu);
+ cpu_ppc_set_papr(cpu, PPC_VIRTUAL_HYPERVISOR(spapr));
if (cpu->max_compat) {
Error *local_err = NULL;
@@ -76,7 +88,7 @@ static void spapr_cpu_init(sPAPRMachineState *spapr, PowerPCCPU *cpu,
cs->numa_node = i;
}
- xics_cpu_setup(spapr->xics, cpu);
+ xics_cpu_setup(XICS_FABRIC(spapr), cpu);
qemu_register_reset(spapr_cpu_reset, cpu);
spapr_cpu_reset(cpu);
diff --git a/hw/ppc/spapr_events.c b/hw/ppc/spapr_events.c
index f85a9c32a7..24a5758e62 100644
--- a/hw/ppc/spapr_events.c
+++ b/hw/ppc/spapr_events.c
@@ -481,7 +481,7 @@ static void spapr_powerdown_req(Notifier *n, void *opaque)
rtas_event_log_queue(RTAS_LOG_TYPE_EPOW, new_epow, true);
- qemu_irq_pulse(xics_get_qirq(spapr->xics,
+ qemu_irq_pulse(xics_get_qirq(XICS_FABRIC(spapr),
rtas_event_log_to_irq(spapr,
RTAS_LOG_TYPE_EPOW)));
}
@@ -574,7 +574,7 @@ static void spapr_hotplug_req_event(uint8_t hp_id, uint8_t hp_action,
rtas_event_log_queue(RTAS_LOG_TYPE_HOTPLUG, new_hp, true);
- qemu_irq_pulse(xics_get_qirq(spapr->xics,
+ qemu_irq_pulse(xics_get_qirq(XICS_FABRIC(spapr),
rtas_event_log_to_irq(spapr,
RTAS_LOG_TYPE_HOTPLUG)));
}
@@ -695,7 +695,7 @@ static void check_exception(PowerPCCPU *cpu, sPAPRMachineState *spapr,
spapr_event_sources_get_source(spapr->event_sources, i);
g_assert(source->enabled);
- qemu_irq_pulse(xics_get_qirq(spapr->xics, source->irq));
+ qemu_irq_pulse(xics_get_qirq(XICS_FABRIC(spapr), source->irq));
}
}
@@ -752,7 +752,7 @@ void spapr_events_init(sPAPRMachineState *spapr)
spapr->event_sources = spapr_event_sources_new();
spapr_event_sources_register(spapr->event_sources, EVENT_CLASS_EPOW,
- xics_spapr_alloc(spapr->xics, 0, false,
+ spapr_ics_alloc(spapr->ics, 0, false,
&error_fatal));
/* NOTE: if machine supports modern/dedicated hotplug event source,
@@ -765,7 +765,7 @@ void spapr_events_init(sPAPRMachineState *spapr)
*/
if (spapr->use_hotplug_event_source) {
spapr_event_sources_register(spapr->event_sources, EVENT_CLASS_HOT_PLUG,
- xics_spapr_alloc(spapr->xics, 0, false,
+ spapr_ics_alloc(spapr->ics, 0, false,
&error_fatal));
}
diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
index 42d20e0b92..f05a90ed2c 100644
--- a/hw/ppc/spapr_hcall.c
+++ b/hw/ppc/spapr_hcall.c
@@ -47,12 +47,12 @@ static bool has_spr(PowerPCCPU *cpu, int spr)
return cpu->env.spr_cb[spr].name != NULL;
}
-static inline bool valid_pte_index(CPUPPCState *env, target_ulong pte_index)
+static inline bool valid_ptex(PowerPCCPU *cpu, target_ulong ptex)
{
/*
- * hash value/pteg group index is normalized by htab_mask
+ * hash value/pteg group index is normalized by HPT mask
*/
- if (((pte_index & ~7ULL) / HPTES_PER_GROUP) & ~env->htab_mask) {
+ if (((ptex & ~7ULL) / HPTES_PER_GROUP) & ~ppc_hash64_hpt_mask(cpu)) {
return false;
}
return true;
@@ -77,15 +77,14 @@ static bool is_ram_address(sPAPRMachineState *spapr, hwaddr addr)
static target_ulong h_enter(PowerPCCPU *cpu, sPAPRMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
- CPUPPCState *env = &cpu->env;
target_ulong flags = args[0];
- target_ulong pte_index = args[1];
+ target_ulong ptex = args[1];
target_ulong pteh = args[2];
target_ulong ptel = args[3];
unsigned apshift;
target_ulong raddr;
- target_ulong index;
- uint64_t token;
+ target_ulong slot;
+ const ppc_hash_pte64_t *hptes;
apshift = ppc_hash64_hpte_page_shift_noslb(cpu, pteh, ptel);
if (!apshift) {
@@ -116,36 +115,36 @@ static target_ulong h_enter(PowerPCCPU *cpu, sPAPRMachineState *spapr,
pteh &= ~0x60ULL;
- if (!valid_pte_index(env, pte_index)) {
+ if (!valid_ptex(cpu, ptex)) {
return H_PARAMETER;
}
- index = 0;
+ slot = ptex & 7ULL;
+ ptex = ptex & ~7ULL;
+
if (likely((flags & H_EXACT) == 0)) {
- pte_index &= ~7ULL;
- token = ppc_hash64_start_access(cpu, pte_index);
- for (; index < 8; index++) {
- if (!(ppc_hash64_load_hpte0(cpu, token, index) & HPTE64_V_VALID)) {
+ hptes = ppc_hash64_map_hptes(cpu, ptex, HPTES_PER_GROUP);
+ for (slot = 0; slot < 8; slot++) {
+ if (!(ppc_hash64_hpte0(cpu, hptes, slot) & HPTE64_V_VALID)) {
break;
}
}
- ppc_hash64_stop_access(cpu, token);
- if (index == 8) {
+ ppc_hash64_unmap_hptes(cpu, hptes, ptex, HPTES_PER_GROUP);
+ if (slot == 8) {
return H_PTEG_FULL;
}
} else {
- token = ppc_hash64_start_access(cpu, pte_index);
- if (ppc_hash64_load_hpte0(cpu, token, 0) & HPTE64_V_VALID) {
- ppc_hash64_stop_access(cpu, token);
+ hptes = ppc_hash64_map_hptes(cpu, ptex + slot, 1);
+ if (ppc_hash64_hpte0(cpu, hptes, 0) & HPTE64_V_VALID) {
+ ppc_hash64_unmap_hptes(cpu, hptes, ptex + slot, 1);
return H_PTEG_FULL;
}
- ppc_hash64_stop_access(cpu, token);
+ ppc_hash64_unmap_hptes(cpu, hptes, ptex, 1);
}
- ppc_hash64_store_hpte(cpu, pte_index + index,
- pteh | HPTE64_V_HPTE_DIRTY, ptel);
+ ppc_hash64_store_hpte(cpu, ptex + slot, pteh | HPTE64_V_HPTE_DIRTY, ptel);
- args[0] = pte_index + index;
+ args[0] = ptex + slot;
return H_SUCCESS;
}
@@ -161,18 +160,17 @@ static RemoveResult remove_hpte(PowerPCCPU *cpu, target_ulong ptex,
target_ulong flags,
target_ulong *vp, target_ulong *rp)
{
- CPUPPCState *env = &cpu->env;
- uint64_t token;
+ const ppc_hash_pte64_t *hptes;
target_ulong v, r;
- if (!valid_pte_index(env, ptex)) {
+ if (!valid_ptex(cpu, ptex)) {
return REMOVE_PARM;
}
- token = ppc_hash64_start_access(cpu, ptex);
- v = ppc_hash64_load_hpte0(cpu, token, 0);
- r = ppc_hash64_load_hpte1(cpu, token, 0);
- ppc_hash64_stop_access(cpu, token);
+ hptes = ppc_hash64_map_hptes(cpu, ptex, 1);
+ v = ppc_hash64_hpte0(cpu, hptes, 0);
+ r = ppc_hash64_hpte1(cpu, hptes, 0);
+ ppc_hash64_unmap_hptes(cpu, hptes, ptex, 1);
if ((v & HPTE64_V_VALID) == 0 ||
((flags & H_AVPN) && (v & ~0x7fULL) != avpn) ||
@@ -191,11 +189,11 @@ static target_ulong h_remove(PowerPCCPU *cpu, sPAPRMachineState *spapr,
{
CPUPPCState *env = &cpu->env;
target_ulong flags = args[0];
- target_ulong pte_index = args[1];
+ target_ulong ptex = args[1];
target_ulong avpn = args[2];
RemoveResult ret;
- ret = remove_hpte(cpu, pte_index, avpn, flags,
+ ret = remove_hpte(cpu, ptex, avpn, flags,
&args[0], &args[1]);
switch (ret) {
@@ -291,19 +289,19 @@ static target_ulong h_protect(PowerPCCPU *cpu, sPAPRMachineState *spapr,
{
CPUPPCState *env = &cpu->env;
target_ulong flags = args[0];
- target_ulong pte_index = args[1];
+ target_ulong ptex = args[1];
target_ulong avpn = args[2];
- uint64_t token;
+ const ppc_hash_pte64_t *hptes;
target_ulong v, r;
- if (!valid_pte_index(env, pte_index)) {
+ if (!valid_ptex(cpu, ptex)) {
return H_PARAMETER;
}
- token = ppc_hash64_start_access(cpu, pte_index);
- v = ppc_hash64_load_hpte0(cpu, token, 0);
- r = ppc_hash64_load_hpte1(cpu, token, 0);
- ppc_hash64_stop_access(cpu, token);
+ hptes = ppc_hash64_map_hptes(cpu, ptex, 1);
+ v = ppc_hash64_hpte0(cpu, hptes, 0);
+ r = ppc_hash64_hpte1(cpu, hptes, 0);
+ ppc_hash64_unmap_hptes(cpu, hptes, ptex, 1);
if ((v & HPTE64_V_VALID) == 0 ||
((flags & H_AVPN) && (v & ~0x7fULL) != avpn)) {
@@ -315,36 +313,35 @@ static target_ulong h_protect(PowerPCCPU *cpu, sPAPRMachineState *spapr,
r |= (flags << 55) & HPTE64_R_PP0;
r |= (flags << 48) & HPTE64_R_KEY_HI;
r |= flags & (HPTE64_R_PP | HPTE64_R_N | HPTE64_R_KEY_LO);
- ppc_hash64_store_hpte(cpu, pte_index,
+ ppc_hash64_store_hpte(cpu, ptex,
(v & ~HPTE64_V_VALID) | HPTE64_V_HPTE_DIRTY, 0);
- ppc_hash64_tlb_flush_hpte(cpu, pte_index, v, r);
+ ppc_hash64_tlb_flush_hpte(cpu, ptex, v, r);
/* Flush the tlb */
check_tlb_flush(env, true);
/* Don't need a memory barrier, due to qemu's global lock */
- ppc_hash64_store_hpte(cpu, pte_index, v | HPTE64_V_HPTE_DIRTY, r);
+ ppc_hash64_store_hpte(cpu, ptex, v | HPTE64_V_HPTE_DIRTY, r);
return H_SUCCESS;
}
static target_ulong h_read(PowerPCCPU *cpu, sPAPRMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
- CPUPPCState *env = &cpu->env;
target_ulong flags = args[0];
- target_ulong pte_index = args[1];
+ target_ulong ptex = args[1];
uint8_t *hpte;
int i, ridx, n_entries = 1;
- if (!valid_pte_index(env, pte_index)) {
+ if (!valid_ptex(cpu, ptex)) {
return H_PARAMETER;
}
if (flags & H_READ_4) {
/* Clear the two low order bits */
- pte_index &= ~(3ULL);
+ ptex &= ~(3ULL);
n_entries = 4;
}
- hpte = env->external_htab + (pte_index * HASH_PTE_SIZE_64);
+ hpte = spapr->htab + (ptex * HASH_PTE_SIZE_64);
for (i = 0, ridx = 0; i < n_entries; i++) {
args[ridx++] = ldq_p(hpte);
diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c
index fd6fc1d953..2a3499eaf8 100644
--- a/hw/ppc/spapr_pci.c
+++ b/hw/ppc/spapr_pci.c
@@ -43,6 +43,7 @@
#include "hw/pci/pci_bridge.h"
#include "hw/pci/pci_bus.h"
+#include "hw/pci/pci_ids.h"
#include "hw/ppc/spapr_drc.h"
#include "sysemu/device_tree.h"
#include "sysemu/kvm.h"
@@ -325,7 +326,7 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPRMachineState *spapr,
return;
}
- xics_spapr_free(spapr->xics, msi->first_irq, msi->num);
+ spapr_ics_free(spapr->ics, msi->first_irq, msi->num);
if (msi_present(pdev)) {
spapr_msi_setmsg(pdev, 0, false, 0, 0);
}
@@ -363,7 +364,7 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPRMachineState *spapr,
}
/* Allocate MSIs */
- irq = xics_spapr_alloc_block(spapr->xics, req_num, false,
+ irq = spapr_ics_alloc_block(spapr->ics, req_num, false,
ret_intr_type == RTAS_TYPE_MSI, &err);
if (err) {
error_reportf_err(err, "Can't allocate MSIs for device %x: ",
@@ -374,7 +375,7 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPRMachineState *spapr,
/* Release previous MSIs */
if (msi) {
- xics_spapr_free(spapr->xics, msi->first_irq, msi->num);
+ spapr_ics_free(spapr->ics, msi->first_irq, msi->num);
g_hash_table_remove(phb->msi, &config_addr);
}
@@ -736,7 +737,7 @@ static void spapr_msi_write(void *opaque, hwaddr addr,
trace_spapr_pci_msi_write(addr, data, irq);
- qemu_irq_pulse(xics_get_qirq(spapr->xics, irq));
+ qemu_irq_pulse(xics_get_qirq(XICS_FABRIC(spapr), irq));
}
static const MemoryRegionOps spapr_msi_ops = {
@@ -946,6 +947,274 @@ static void populate_resource_props(PCIDevice *d, ResourceProps *rp)
rp->assigned_len = assigned_idx * sizeof(ResourceFields);
}
+typedef struct PCIClass PCIClass;
+typedef struct PCISubClass PCISubClass;
+typedef struct PCIIFace PCIIFace;
+
+struct PCIIFace {
+ int iface;
+ const char *name;
+};
+
+struct PCISubClass {
+ int subclass;
+ const char *name;
+ const PCIIFace *iface;
+};
+
+struct PCIClass {
+ const char *name;
+ const PCISubClass *subc;
+};
+
+static const PCISubClass undef_subclass[] = {
+ { PCI_CLASS_NOT_DEFINED_VGA, "display", NULL },
+ { 0xFF, NULL, NULL },
+};
+
+static const PCISubClass mass_subclass[] = {
+ { PCI_CLASS_STORAGE_SCSI, "scsi", NULL },
+ { PCI_CLASS_STORAGE_IDE, "ide", NULL },
+ { PCI_CLASS_STORAGE_FLOPPY, "fdc", NULL },
+ { PCI_CLASS_STORAGE_IPI, "ipi", NULL },
+ { PCI_CLASS_STORAGE_RAID, "raid", NULL },
+ { PCI_CLASS_STORAGE_ATA, "ata", NULL },
+ { PCI_CLASS_STORAGE_SATA, "sata", NULL },
+ { PCI_CLASS_STORAGE_SAS, "sas", NULL },
+ { 0xFF, NULL, NULL },
+};
+
+static const PCISubClass net_subclass[] = {
+ { PCI_CLASS_NETWORK_ETHERNET, "ethernet", NULL },
+ { PCI_CLASS_NETWORK_TOKEN_RING, "token-ring", NULL },
+ { PCI_CLASS_NETWORK_FDDI, "fddi", NULL },
+ { PCI_CLASS_NETWORK_ATM, "atm", NULL },
+ { PCI_CLASS_NETWORK_ISDN, "isdn", NULL },
+ { PCI_CLASS_NETWORK_WORLDFIP, "worldfip", NULL },
+ { PCI_CLASS_NETWORK_PICMG214, "picmg", NULL },
+ { 0xFF, NULL, NULL },
+};
+
+static const PCISubClass displ_subclass[] = {
+ { PCI_CLASS_DISPLAY_VGA, "vga", NULL },
+ { PCI_CLASS_DISPLAY_XGA, "xga", NULL },
+ { PCI_CLASS_DISPLAY_3D, "3d-controller", NULL },
+ { 0xFF, NULL, NULL },
+};
+
+static const PCISubClass media_subclass[] = {
+ { PCI_CLASS_MULTIMEDIA_VIDEO, "video", NULL },
+ { PCI_CLASS_MULTIMEDIA_AUDIO, "sound", NULL },
+ { PCI_CLASS_MULTIMEDIA_PHONE, "telephony", NULL },
+ { 0xFF, NULL, NULL },
+};
+
+static const PCISubClass mem_subclass[] = {
+ { PCI_CLASS_MEMORY_RAM, "memory", NULL },
+ { PCI_CLASS_MEMORY_FLASH, "flash", NULL },
+ { 0xFF, NULL, NULL },
+};
+
+static const PCISubClass bridg_subclass[] = {
+ { PCI_CLASS_BRIDGE_HOST, "host", NULL },
+ { PCI_CLASS_BRIDGE_ISA, "isa", NULL },
+ { PCI_CLASS_BRIDGE_EISA, "eisa", NULL },
+ { PCI_CLASS_BRIDGE_MC, "mca", NULL },
+ { PCI_CLASS_BRIDGE_PCI, "pci", NULL },
+ { PCI_CLASS_BRIDGE_PCMCIA, "pcmcia", NULL },
+ { PCI_CLASS_BRIDGE_NUBUS, "nubus", NULL },
+ { PCI_CLASS_BRIDGE_CARDBUS, "cardbus", NULL },
+ { PCI_CLASS_BRIDGE_RACEWAY, "raceway", NULL },
+ { PCI_CLASS_BRIDGE_PCI_SEMITP, "semi-transparent-pci", NULL },
+ { PCI_CLASS_BRIDGE_IB_PCI, "infiniband", NULL },
+ { 0xFF, NULL, NULL },
+};
+
+static const PCISubClass comm_subclass[] = {
+ { PCI_CLASS_COMMUNICATION_SERIAL, "serial", NULL },
+ { PCI_CLASS_COMMUNICATION_PARALLEL, "parallel", NULL },
+ { PCI_CLASS_COMMUNICATION_MULTISERIAL, "multiport-serial", NULL },
+ { PCI_CLASS_COMMUNICATION_MODEM, "modem", NULL },
+ { PCI_CLASS_COMMUNICATION_GPIB, "gpib", NULL },
+ { PCI_CLASS_COMMUNICATION_SC, "smart-card", NULL },
+ { 0xFF, NULL, NULL, },
+};
+
+static const PCIIFace pic_iface[] = {
+ { PCI_CLASS_SYSTEM_PIC_IOAPIC, "io-apic" },
+ { PCI_CLASS_SYSTEM_PIC_IOXAPIC, "io-xapic" },
+ { 0xFF, NULL },
+};
+
+static const PCISubClass sys_subclass[] = {
+ { PCI_CLASS_SYSTEM_PIC, "interrupt-controller", pic_iface },
+ { PCI_CLASS_SYSTEM_DMA, "dma-controller", NULL },
+ { PCI_CLASS_SYSTEM_TIMER, "timer", NULL },
+ { PCI_CLASS_SYSTEM_RTC, "rtc", NULL },
+ { PCI_CLASS_SYSTEM_PCI_HOTPLUG, "hot-plug-controller", NULL },
+ { PCI_CLASS_SYSTEM_SDHCI, "sd-host-controller", NULL },
+ { 0xFF, NULL, NULL },
+};
+
+static const PCISubClass inp_subclass[] = {
+ { PCI_CLASS_INPUT_KEYBOARD, "keyboard", NULL },
+ { PCI_CLASS_INPUT_PEN, "pen", NULL },
+ { PCI_CLASS_INPUT_MOUSE, "mouse", NULL },
+ { PCI_CLASS_INPUT_SCANNER, "scanner", NULL },
+ { PCI_CLASS_INPUT_GAMEPORT, "gameport", NULL },
+ { 0xFF, NULL, NULL },
+};
+
+static const PCISubClass dock_subclass[] = {
+ { PCI_CLASS_DOCKING_GENERIC, "dock", NULL },
+ { 0xFF, NULL, NULL },
+};
+
+static const PCISubClass cpu_subclass[] = {
+ { PCI_CLASS_PROCESSOR_PENTIUM, "pentium", NULL },
+ { PCI_CLASS_PROCESSOR_POWERPC, "powerpc", NULL },
+ { PCI_CLASS_PROCESSOR_MIPS, "mips", NULL },
+ { PCI_CLASS_PROCESSOR_CO, "co-processor", NULL },
+ { 0xFF, NULL, NULL },
+};
+
+static const PCIIFace usb_iface[] = {
+ { PCI_CLASS_SERIAL_USB_UHCI, "usb-uhci" },
+ { PCI_CLASS_SERIAL_USB_OHCI, "usb-ohci", },
+ { PCI_CLASS_SERIAL_USB_EHCI, "usb-ehci" },
+ { PCI_CLASS_SERIAL_USB_XHCI, "usb-xhci" },
+ { PCI_CLASS_SERIAL_USB_UNKNOWN, "usb-unknown" },
+ { PCI_CLASS_SERIAL_USB_DEVICE, "usb-device" },
+ { 0xFF, NULL },
+};
+
+static const PCISubClass ser_subclass[] = {
+ { PCI_CLASS_SERIAL_FIREWIRE, "firewire", NULL },
+ { PCI_CLASS_SERIAL_ACCESS, "access-bus", NULL },
+ { PCI_CLASS_SERIAL_SSA, "ssa", NULL },
+ { PCI_CLASS_SERIAL_USB, "usb", usb_iface },
+ { PCI_CLASS_SERIAL_FIBER, "fibre-channel", NULL },
+ { PCI_CLASS_SERIAL_SMBUS, "smb", NULL },
+ { PCI_CLASS_SERIAL_IB, "infiniband", NULL },
+ { PCI_CLASS_SERIAL_IPMI, "ipmi", NULL },
+ { PCI_CLASS_SERIAL_SERCOS, "sercos", NULL },
+ { PCI_CLASS_SERIAL_CANBUS, "canbus", NULL },
+ { 0xFF, NULL, NULL },
+};
+
+static const PCISubClass wrl_subclass[] = {
+ { PCI_CLASS_WIRELESS_IRDA, "irda", NULL },
+ { PCI_CLASS_WIRELESS_CIR, "consumer-ir", NULL },
+ { PCI_CLASS_WIRELESS_RF_CONTROLLER, "rf-controller", NULL },
+ { PCI_CLASS_WIRELESS_BLUETOOTH, "bluetooth", NULL },
+ { PCI_CLASS_WIRELESS_BROADBAND, "broadband", NULL },
+ { 0xFF, NULL, NULL },
+};
+
+static const PCISubClass sat_subclass[] = {
+ { PCI_CLASS_SATELLITE_TV, "satellite-tv", NULL },
+ { PCI_CLASS_SATELLITE_AUDIO, "satellite-audio", NULL },
+ { PCI_CLASS_SATELLITE_VOICE, "satellite-voice", NULL },
+ { PCI_CLASS_SATELLITE_DATA, "satellite-data", NULL },
+ { 0xFF, NULL, NULL },
+};
+
+static const PCISubClass crypt_subclass[] = {
+ { PCI_CLASS_CRYPT_NETWORK, "network-encryption", NULL },
+ { PCI_CLASS_CRYPT_ENTERTAINMENT,
+ "entertainment-encryption", NULL },
+ { 0xFF, NULL, NULL },
+};
+
+static const PCISubClass spc_subclass[] = {
+ { PCI_CLASS_SP_DPIO, "dpio", NULL },
+ { PCI_CLASS_SP_PERF, "counter", NULL },
+ { PCI_CLASS_SP_SYNCH, "measurement", NULL },
+ { PCI_CLASS_SP_MANAGEMENT, "management-card", NULL },
+ { 0xFF, NULL, NULL },
+};
+
+static const PCIClass pci_classes[] = {
+ { "legacy-device", undef_subclass },
+ { "mass-storage", mass_subclass },
+ { "network", net_subclass },
+ { "display", displ_subclass, },
+ { "multimedia-device", media_subclass },
+ { "memory-controller", mem_subclass },
+ { "unknown-bridge", bridg_subclass },
+ { "communication-controller", comm_subclass},
+ { "system-peripheral", sys_subclass },
+ { "input-controller", inp_subclass },
+ { "docking-station", dock_subclass },
+ { "cpu", cpu_subclass },
+ { "serial-bus", ser_subclass },
+ { "wireless-controller", wrl_subclass },
+ { "intelligent-io", NULL },
+ { "satellite-device", sat_subclass },
+ { "encryption", crypt_subclass },
+ { "data-processing-controller", spc_subclass },
+};
+
+static const char *pci_find_device_name(uint8_t class, uint8_t subclass,
+ uint8_t iface)
+{
+ const PCIClass *pclass;
+ const PCISubClass *psubclass;
+ const PCIIFace *piface;
+ const char *name;
+
+ if (class >= ARRAY_SIZE(pci_classes)) {
+ return "pci";
+ }
+
+ pclass = pci_classes + class;
+ name = pclass->name;
+
+ if (pclass->subc == NULL) {
+ return name;
+ }
+
+ psubclass = pclass->subc;
+ while ((psubclass->subclass & 0xff) != 0xff) {
+ if ((psubclass->subclass & 0xff) == subclass) {
+ name = psubclass->name;
+ break;
+ }
+ psubclass++;
+ }
+
+ piface = psubclass->iface;
+ if (piface == NULL) {
+ return name;
+ }
+ while ((piface->iface & 0xff) != 0xff) {
+ if ((piface->iface & 0xff) == iface) {
+ name = piface->name;
+ break;
+ }
+ piface++;
+ }
+
+ return name;
+}
+
+static void pci_get_node_name(char *nodename, int len, PCIDevice *dev)
+{
+ int slot = PCI_SLOT(dev->devfn);
+ int func = PCI_FUNC(dev->devfn);
+ uint32_t ccode = pci_default_read_config(dev, PCI_CLASS_PROG, 3);
+ const char *name;
+
+ name = pci_find_device_name((ccode >> 16) & 0xff, (ccode >> 8) & 0xff,
+ ccode & 0xff);
+
+ if (func != 0) {
+ snprintf(nodename, len, "%s@%x,%x", name, slot, func);
+ } else {
+ snprintf(nodename, len, "%s@%x", name, slot);
+ }
+}
+
static uint32_t spapr_phb_get_pci_drc_index(sPAPRPHBState *phb,
PCIDevice *pdev);
@@ -957,6 +1226,7 @@ static int spapr_populate_pci_child_dt(PCIDevice *dev, void *fdt, int offset,
int pci_status, err;
char *buf = NULL;
uint32_t drc_index = spapr_phb_get_pci_drc_index(sphb, dev);
+ uint32_t ccode = pci_default_read_config(dev, PCI_CLASS_PROG, 3);
uint32_t max_msi, max_msix;
if (pci_default_read_config(dev, PCI_HEADER_TYPE, 1) ==
@@ -971,8 +1241,7 @@ static int spapr_populate_pci_child_dt(PCIDevice *dev, void *fdt, int offset,
pci_default_read_config(dev, PCI_DEVICE_ID, 2)));
_FDT(fdt_setprop_cell(fdt, offset, "revision-id",
pci_default_read_config(dev, PCI_REVISION_ID, 1)));
- _FDT(fdt_setprop_cell(fdt, offset, "class-code",
- pci_default_read_config(dev, PCI_CLASS_PROG, 3)));
+ _FDT(fdt_setprop_cell(fdt, offset, "class-code", ccode));
if (pci_default_read_config(dev, PCI_INTERRUPT_PIN, 1)) {
_FDT(fdt_setprop_cell(fdt, offset, "interrupts",
pci_default_read_config(dev, PCI_INTERRUPT_PIN, 1)));
@@ -1013,11 +1282,10 @@ static int spapr_populate_pci_child_dt(PCIDevice *dev, void *fdt, int offset,
_FDT(fdt_setprop(fdt, offset, "udf-supported", NULL, 0));
}
- /* NOTE: this is normally generated by firmware via path/unit name,
- * but in our case we must set it manually since it does not get
- * processed by OF beforehand
- */
- _FDT(fdt_setprop_string(fdt, offset, "name", "pci"));
+ _FDT(fdt_setprop_string(fdt, offset, "name",
+ pci_find_device_name((ccode >> 16) & 0xff,
+ (ccode >> 8) & 0xff,
+ ccode & 0xff)));
buf = spapr_phb_get_loc_code(sphb, dev);
if (!buf) {
error_report("Failed setting the ibm,loc-code");
@@ -1061,15 +1329,9 @@ static int spapr_create_pci_child_dt(sPAPRPHBState *phb, PCIDevice *dev,
void *fdt, int node_offset)
{
int offset, ret;
- int slot = PCI_SLOT(dev->devfn);
- int func = PCI_FUNC(dev->devfn);
char nodename[FDT_NAME_MAX];
- if (func != 0) {
- snprintf(nodename, FDT_NAME_MAX, "pci@%x,%x", slot, func);
- } else {
- snprintf(nodename, FDT_NAME_MAX, "pci@%x", slot);
- }
+ pci_get_node_name(nodename, FDT_NAME_MAX, dev);
offset = fdt_add_subnode(fdt, node_offset, nodename);
ret = spapr_populate_pci_child_dt(dev, fdt, offset, phb);
@@ -1485,7 +1747,7 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp)
uint32_t irq;
Error *local_err = NULL;
- irq = xics_spapr_alloc_block(spapr->xics, 1, true, false, &local_err);
+ irq = spapr_ics_alloc_block(spapr->ics, 1, true, false, &local_err);
if (local_err) {
error_propagate(errp, local_err);
error_prepend(errp, "can't allocate LSIs: ");
@@ -1782,9 +2044,9 @@ static void spapr_populate_pci_devices_dt(PCIBus *bus, PCIDevice *pdev,
s_fdt.fdt = p->fdt;
s_fdt.node_off = offset;
s_fdt.sphb = p->sphb;
- pci_for_each_device(sec_bus, pci_bus_num(sec_bus),
- spapr_populate_pci_devices_dt,
- &s_fdt);
+ pci_for_each_device_reverse(sec_bus, pci_bus_num(sec_bus),
+ spapr_populate_pci_devices_dt,
+ &s_fdt);
}
static void spapr_phb_pci_enumerate_bridge(PCIBus *bus, PCIDevice *pdev,
@@ -1953,9 +2215,9 @@ int spapr_populate_pci_dt(sPAPRPHBState *phb,
s_fdt.fdt = fdt;
s_fdt.node_off = bus_off;
s_fdt.sphb = phb;
- pci_for_each_device(bus, pci_bus_num(bus),
- spapr_populate_pci_devices_dt,
- &s_fdt);
+ pci_for_each_device_reverse(bus, pci_bus_num(bus),
+ spapr_populate_pci_devices_dt,
+ &s_fdt);
ret = spapr_drc_populate_dt(fdt, bus_off, OBJECT(phb),
SPAPR_DR_CONNECTOR_TYPE_PCI);
diff --git a/hw/ppc/spapr_vio.c b/hw/ppc/spapr_vio.c
index 8bfc5f971f..a0ee4fd265 100644
--- a/hw/ppc/spapr_vio.c
+++ b/hw/ppc/spapr_vio.c
@@ -454,7 +454,7 @@ static void spapr_vio_busdev_realize(DeviceState *qdev, Error **errp)
dev->qdev.id = id;
}
- dev->irq = xics_spapr_alloc(spapr->xics, dev->irq, false, &local_err);
+ dev->irq = spapr_ics_alloc(spapr->ics, dev->irq, false, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c
index bbfb5dc289..a53f058621 100644
--- a/hw/scsi/scsi-disk.c
+++ b/hw/scsi/scsi-disk.c
@@ -2240,7 +2240,7 @@ static void scsi_disk_resize_cb(void *opaque)
}
}
-static void scsi_cd_change_media_cb(void *opaque, bool load)
+static void scsi_cd_change_media_cb(void *opaque, bool load, Error **errp)
{
SCSIDiskState *s = opaque;
@@ -2328,7 +2328,13 @@ static void scsi_realize(SCSIDevice *dev, Error **errp)
return;
}
}
- blkconf_apply_backend_options(&dev->conf);
+ blkconf_apply_backend_options(&dev->conf,
+ blk_is_read_only(s->qdev.conf.blk),
+ dev->type == TYPE_DISK, &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
if (s->qdev.conf.discard_granularity == -1) {
s->qdev.conf.discard_granularity =
@@ -2380,7 +2386,7 @@ static void scsi_cd_realize(SCSIDevice *dev, Error **errp)
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
if (!dev->conf.blk) {
- dev->conf.blk = blk_new();
+ dev->conf.blk = blk_new(0, BLK_PERM_ALL);
}
s->qdev.blocksize = 2048;
diff --git a/hw/sd/sd.c b/hw/sd/sd.c
index 8e88e8311a..ba47bff4db 100644
--- a/hw/sd/sd.c
+++ b/hw/sd/sd.c
@@ -458,7 +458,7 @@ static bool sd_get_readonly(SDState *sd)
return sd->wp_switch;
}
-static void sd_cardchange(void *opaque, bool load)
+static void sd_cardchange(void *opaque, bool load, Error **errp)
{
SDState *sd = opaque;
DeviceState *dev = DEVICE(sd);
@@ -1887,6 +1887,7 @@ static void sd_instance_finalize(Object *obj)
static void sd_realize(DeviceState *dev, Error **errp)
{
SDState *sd = SD_CARD(dev);
+ int ret;
if (sd->blk && blk_is_read_only(sd->blk)) {
error_setg(errp, "Cannot use read-only drive as SD card");
@@ -1894,6 +1895,11 @@ static void sd_realize(DeviceState *dev, Error **errp)
}
if (sd->blk) {
+ ret = blk_set_perm(sd->blk, BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE,
+ BLK_PERM_ALL, errp);
+ if (ret < 0) {
+ return;
+ }
blk_set_dev_ops(sd->blk, &sd_block_ops, sd);
}
}
diff --git a/hw/usb/bus.c b/hw/usb/bus.c
index efe4b8e1a6..24f1608b4b 100644
--- a/hw/usb/bus.c
+++ b/hw/usb/bus.c
@@ -8,7 +8,6 @@
#include "monitor/monitor.h"
#include "trace.h"
#include "qemu/cutils.h"
-#include "migration/migration.h"
static void usb_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent);
@@ -688,8 +687,6 @@ USBDevice *usbdevice_create(const char *cmdline)
const char *params;
int len;
USBDevice *dev;
- ObjectClass *klass;
- DeviceClass *dc;
params = strchr(cmdline,':');
if (params) {
@@ -724,22 +721,6 @@ USBDevice *usbdevice_create(const char *cmdline)
return NULL;
}
- klass = object_class_by_name(f->name);
- if (klass == NULL) {
- error_report("Device '%s' not found", f->name);
- return NULL;
- }
-
- dc = DEVICE_CLASS(klass);
-
- if (only_migratable) {
- if (dc->vmsd->unmigratable) {
- error_report("Device %s is not migratable, but --only-migratable "
- "was specified", f->name);
- return NULL;
- }
- }
-
if (f->usbdevice_init) {
dev = f->usbdevice_init(bus, params);
} else {
diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c
index c607f7606d..8a61ec94c8 100644
--- a/hw/usb/dev-storage.c
+++ b/hw/usb/dev-storage.c
@@ -589,6 +589,13 @@ static const struct SCSIBusInfo usb_msd_scsi_info_bot = {
.load_request = usb_msd_load_request,
};
+static void usb_msd_unrealize_storage(USBDevice *dev, Error **errp)
+{
+ MSDState *s = USB_STORAGE_DEV(dev);
+
+ object_unref(OBJECT(&s->bus));
+}
+
static void usb_msd_realize_storage(USBDevice *dev, Error **errp)
{
MSDState *s = USB_STORAGE_DEV(dev);
@@ -603,7 +610,11 @@ static void usb_msd_realize_storage(USBDevice *dev, Error **errp)
blkconf_serial(&s->conf, &dev->serial);
blkconf_blocksizes(&s->conf);
- blkconf_apply_backend_options(&s->conf);
+ blkconf_apply_backend_options(&s->conf, blk_is_read_only(blk), true, &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
/*
* Hack alert: this pretends to be a block device, but it's really
@@ -635,6 +646,13 @@ static void usb_msd_realize_storage(USBDevice *dev, Error **errp)
s->scsi_dev = scsi_dev;
}
+static void usb_msd_unrealize_bot(USBDevice *dev, Error **errp)
+{
+ MSDState *s = USB_STORAGE_DEV(dev);
+
+ object_unref(OBJECT(&s->bus));
+}
+
static void usb_msd_realize_bot(USBDevice *dev, Error **errp)
{
MSDState *s = USB_STORAGE_DEV(dev);
@@ -755,6 +773,7 @@ static void usb_msd_class_initfn_storage(ObjectClass *klass, void *data)
USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
uc->realize = usb_msd_realize_storage;
+ uc->unrealize = usb_msd_unrealize_storage;
dc->props = msd_properties;
}
@@ -817,6 +836,7 @@ static void usb_msd_class_initfn_bot(ObjectClass *klass, void *data)
USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
uc->realize = usb_msd_realize_bot;
+ uc->unrealize = usb_msd_unrealize_bot;
uc->attached_settable = true;
}
diff --git a/hw/usb/dev-uas.c b/hw/usb/dev-uas.c
index 3b26655889..fffc424396 100644
--- a/hw/usb/dev-uas.c
+++ b/hw/usb/dev-uas.c
@@ -896,6 +896,8 @@ static void usb_uas_unrealize(USBDevice *dev, Error **errp)
UASDevice *uas = USB_UAS(dev);
qemu_bh_delete(uas->status_bh);
+
+ object_unref(OBJECT(&uas->bus));
}
static void usb_uas_realize(USBDevice *dev, Error **errp)