aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
Diffstat (limited to 'hw')
-rw-r--r--hw/block/dataplane/trace-events5
-rw-r--r--hw/block/nvme.c2
-rw-r--r--hw/block/trace-events5
-rw-r--r--hw/display/qxl.c9
-rw-r--r--hw/display/trace-events1
-rw-r--r--hw/gpio/mpc8xxx.c20
-rw-r--r--hw/i386/intel_iommu.c10
-rw-r--r--hw/i386/pc.c5
-rw-r--r--hw/i386/trace-events8
-rw-r--r--hw/i386/xen/trace-events6
-rw-r--r--hw/input/ps2.c8
-rw-r--r--hw/input/trace-events2
-rw-r--r--hw/intc/trace-events1
-rw-r--r--hw/misc/ivshmem.c8
-rw-r--r--hw/net/e1000e.c2
-rw-r--r--hw/net/fsl_etsec/etsec.c1
-rw-r--r--hw/net/rocker/rocker.c4
-rw-r--r--hw/net/trace-events8
-rw-r--r--hw/net/vmxnet3.c2
-rw-r--r--hw/pci-bridge/Makefile.objs3
-rw-r--r--hw/pci-bridge/gen_pcie_root_port.c87
-rw-r--r--hw/pci-bridge/ioh3420.c121
-rw-r--r--hw/pci-bridge/pci_bridge_dev.c2
-rw-r--r--hw/pci-bridge/pcie_root_port.c171
-rw-r--r--hw/pci/msix.c44
-rw-r--r--hw/pci/pci.c2
-rw-r--r--hw/ppc/Makefile.objs2
-rw-r--r--hw/ppc/e500.c23
-rw-r--r--hw/ppc/pnv.c6
-rw-r--r--hw/ppc/ppc.c73
-rw-r--r--hw/ppc/ppc440_bamboo.c6
-rw-r--r--hw/ppc/ppc_booke.c8
-rw-r--r--hw/ppc/ppce500_spin.c18
-rw-r--r--hw/ppc/prep.c234
-rw-r--r--hw/ppc/prep_systemio.c303
-rw-r--r--hw/ppc/rs6000_mc.c232
-rw-r--r--hw/ppc/spapr.c214
-rw-r--r--hw/ppc/spapr_cpu_core.c38
-rw-r--r--hw/ppc/spapr_hcall.c160
-rw-r--r--hw/ppc/spapr_vio.c10
-rw-r--r--hw/ppc/trace-events13
-rw-r--r--hw/ppc/virtex_ml507.c7
-rw-r--r--hw/s390x/s390-pci-bus.h4
-rw-r--r--hw/s390x/s390-virtio.c2
-rw-r--r--hw/scsi/megasas.c4
-rw-r--r--hw/usb/hcd-xhci.c41
-rw-r--r--hw/usb/host-libusb.c29
-rw-r--r--hw/usb/host-stub.c5
-rw-r--r--hw/usb/trace-events1
-rw-r--r--hw/vfio/pci.c8
-rw-r--r--hw/vfio/trace-events2
-rw-r--r--hw/virtio/vhost.c3
-rw-r--r--hw/virtio/virtio-pci.c4
-rw-r--r--hw/virtio/virtio.c2
-rw-r--r--hw/xen/trace-events13
55 files changed, 1542 insertions, 460 deletions
diff --git a/hw/block/dataplane/trace-events b/hw/block/dataplane/trace-events
new file mode 100644
index 0000000..e07673a
--- /dev/null
+++ b/hw/block/dataplane/trace-events
@@ -0,0 +1,5 @@
+# See docs/tracing.txt for syntax documentation.
+
+# hw/block/dataplane/virtio-blk.c
+virtio_blk_data_plane_start(void *s) "dataplane %p"
+virtio_blk_data_plane_stop(void *s) "dataplane %p"
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
index d479fd2..ae91a18 100644
--- a/hw/block/nvme.c
+++ b/hw/block/nvme.c
@@ -872,7 +872,7 @@ static int nvme_init(PCIDevice *pci_dev)
pci_register_bar(&n->parent_obj, 0,
PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64,
&n->iomem);
- msix_init_exclusive_bar(&n->parent_obj, n->num_queues, 4);
+ msix_init_exclusive_bar(&n->parent_obj, n->num_queues, 4, NULL);
id->vid = cpu_to_le16(pci_get_word(pci_conf + PCI_VENDOR_ID));
id->ssvid = cpu_to_le16(pci_get_word(pci_conf + PCI_SUBSYSTEM_VENDOR_ID));
diff --git a/hw/block/trace-events b/hw/block/trace-events
index d0dd94f..65e83dc 100644
--- a/hw/block/trace-events
+++ b/hw/block/trace-events
@@ -7,11 +7,6 @@ virtio_blk_handle_write(void *req, uint64_t sector, size_t nsectors) "req %p sec
virtio_blk_handle_read(void *req, uint64_t sector, size_t nsectors) "req %p sector %"PRIu64" nsectors %zu"
virtio_blk_submit_multireq(void *mrb, int start, int num_reqs, uint64_t offset, size_t size, bool is_write) "mrb %p start %d num_reqs %d offset %"PRIu64" size %zu is_write %d"
-# hw/block/dataplane/virtio-blk.c
-virtio_blk_data_plane_start(void *s) "dataplane %p"
-virtio_blk_data_plane_stop(void *s) "dataplane %p"
-virtio_blk_data_plane_process_request(void *s, unsigned int out_num, unsigned int in_num, unsigned int head) "dataplane %p out_num %u in_num %u head %u"
-
# hw/block/hd-geometry.c
hd_geometry_lchs_guess(void *blk, int cyls, int heads, int secs) "blk %p LCHS %d %d %d"
hd_geometry_guess(void *blk, uint32_t cyls, uint32_t heads, uint32_t secs, int trans) "blk %p CHS %u %u %u trans %d"
diff --git a/hw/display/qxl.c b/hw/display/qxl.c
index 62d0c80..af4c0ca 100644
--- a/hw/display/qxl.c
+++ b/hw/display/qxl.c
@@ -306,12 +306,11 @@ void qxl_spice_reset_cursor(PCIQXLDevice *qxl)
static ram_addr_t qxl_rom_size(void)
{
- uint32_t required_rom_size = sizeof(QXLRom) + sizeof(QXLModes) +
- sizeof(qxl_modes);
- uint32_t rom_size = 8192; /* two pages */
+#define QXL_REQUIRED_SZ (sizeof(QXLRom) + sizeof(QXLModes) + sizeof(qxl_modes))
+#define QXL_ROM_SZ 8192
- QEMU_BUILD_BUG_ON(required_rom_size > rom_size);
- return rom_size;
+ QEMU_BUILD_BUG_ON(QXL_REQUIRED_SZ > QXL_ROM_SZ);
+ return QXL_ROM_SZ;
}
static void init_qxl_rom(PCIQXLDevice *d)
diff --git a/hw/display/trace-events b/hw/display/trace-events
index 332abab..aadb612 100644
--- a/hw/display/trace-events
+++ b/hw/display/trace-events
@@ -34,7 +34,6 @@ vmware_setmode(uint32_t w, uint32_t h, uint32_t bpp) "%dx%d @ %d bpp"
# hw/display/virtio-gpu.c
virtio_gpu_features(bool virgl) "virgl %d"
virtio_gpu_cmd_get_display_info(void) ""
-virtio_gpu_cmd_get_caps(void) ""
virtio_gpu_cmd_set_scanout(uint32_t id, uint32_t res, uint32_t w, uint32_t h, uint32_t x, uint32_t y) "id %d, res 0x%x, w %d, h %d, x %d, y %d"
virtio_gpu_cmd_res_create_2d(uint32_t res, uint32_t fmt, uint32_t w, uint32_t h) "res 0x%x, fmt 0x%x, w %d, h %d"
virtio_gpu_cmd_res_create_3d(uint32_t res, uint32_t fmt, uint32_t w, uint32_t h, uint32_t d) "res 0x%x, fmt 0x%x, w %d, h %d, d %d"
diff --git a/hw/gpio/mpc8xxx.c b/hw/gpio/mpc8xxx.c
index d149719..e12edb4 100644
--- a/hw/gpio/mpc8xxx.c
+++ b/hw/gpio/mpc8xxx.c
@@ -143,8 +143,10 @@ static void mpc8xxx_gpio_write(void *opaque, hwaddr offset,
mpc8xxx_gpio_update(s);
}
-static void mpc8xxx_gpio_reset(MPC8XXXGPIOState *s)
+static void mpc8xxx_gpio_reset(DeviceState *dev)
{
+ MPC8XXXGPIOState *s = MPC8XXX_GPIO(dev);
+
s->dir = 0;
s->odr = 0;
s->dat = 0;
@@ -180,33 +182,33 @@ static const MemoryRegionOps mpc8xxx_gpio_ops = {
.endianness = DEVICE_BIG_ENDIAN,
};
-static int mpc8xxx_gpio_initfn(SysBusDevice *sbd)
+static void mpc8xxx_gpio_initfn(Object *obj)
{
- DeviceState *dev = DEVICE(sbd);
- MPC8XXXGPIOState *s = MPC8XXX_GPIO(dev);
+ DeviceState *dev = DEVICE(obj);
+ MPC8XXXGPIOState *s = MPC8XXX_GPIO(obj);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
- memory_region_init_io(&s->iomem, OBJECT(s), &mpc8xxx_gpio_ops, s, "mpc8xxx_gpio", 0x1000);
+ memory_region_init_io(&s->iomem, obj, &mpc8xxx_gpio_ops,
+ s, "mpc8xxx_gpio", 0x1000);
sysbus_init_mmio(sbd, &s->iomem);
sysbus_init_irq(sbd, &s->irq);
qdev_init_gpio_in(dev, mpc8xxx_gpio_set_irq, 32);
qdev_init_gpio_out(dev, s->out, 32);
- mpc8xxx_gpio_reset(s);
- return 0;
}
static void mpc8xxx_gpio_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
- k->init = mpc8xxx_gpio_initfn;
dc->vmsd = &vmstate_mpc8xxx_gpio;
+ dc->reset = mpc8xxx_gpio_reset;
}
static const TypeInfo mpc8xxx_gpio_info = {
.name = TYPE_MPC8XXX_GPIO,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(MPC8XXXGPIOState),
+ .instance_init = mpc8xxx_gpio_initfn,
.class_init = mpc8xxx_gpio_class_init,
};
diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c
index ec62239..3270fb9 100644
--- a/hw/i386/intel_iommu.c
+++ b/hw/i386/intel_iommu.c
@@ -1485,8 +1485,16 @@ static bool vtd_process_device_iotlb_desc(IntelIOMMUState *s,
goto done;
}
+ /* According to ATS spec table 2.4:
+ * S = 0, bits 15:12 = xxxx range size: 4K
+ * S = 1, bits 15:12 = xxx0 range size: 8K
+ * S = 1, bits 15:12 = xx01 range size: 16K
+ * S = 1, bits 15:12 = x011 range size: 32K
+ * S = 1, bits 15:12 = 0111 range size: 64K
+ * ...
+ */
if (size) {
- sz = 1 << (ctz64(~(addr | (VTD_PAGE_MASK_4K - 1))) + 1);
+ sz = (VTD_PAGE_SIZE * 2) << cto64(addr >> VTD_PAGE_SHIFT);
addr &= ~(sz - 1);
} else {
sz = VTD_PAGE_SIZE;
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 706e233..e3fcd51 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -1708,6 +1708,11 @@ static void pc_dimm_plug(HotplugHandler *hotplug_dev,
}
if (object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM)) {
+ if (!pcms->acpi_nvdimm_state.is_enabled) {
+ error_setg(&local_err,
+ "nvdimm is not enabled: missing 'nvdimm' in '-M'");
+ goto out;
+ }
nvdimm_plug(&pcms->acpi_nvdimm_state);
}
diff --git a/hw/i386/trace-events b/hw/i386/trace-events
index d2b4973..1cc4a10 100644
--- a/hw/i386/trace-events
+++ b/hw/i386/trace-events
@@ -1,12 +1,5 @@
# See docs/tracing.txt for syntax documentation.
-# hw/i386/xen/xen_platform.c
-xen_platform_log(char *s) "xen platform: %s"
-
-# hw/i386/xen/xen_pvdevice.c
-xen_pv_mmio_read(uint64_t addr) "WARNING: read from Xen PV Device MMIO space (address %"PRIx64")"
-xen_pv_mmio_write(uint64_t addr) "WARNING: write to Xen PV Device MMIO space (address %"PRIx64")"
-
# hw/i386/x86-iommu.c
x86_iommu_iec_notify(bool global, uint32_t index, uint32_t mask) "Notify IEC invalidation: global=%d index=%" PRIu32 " mask=%" PRIu32
@@ -30,7 +23,6 @@ amdvi_devtab_inval(uint8_t bus, uint8_t slot, uint8_t func) "device table entry
amdvi_completion_wait(uint64_t addr, uint64_t data) "completion wait requested with store address 0x%"PRIx64" and store data 0x%"PRIx64
amdvi_control_status(uint64_t val) "MMIO_STATUS state 0x%"PRIx64
amdvi_iotlb_reset(void) "IOTLB exceed size limit - reset "
-amdvi_completion_wait_exec(uint64_t addr, uint64_t data) "completion wait requested with store address 0x%"PRIx64" and store data 0x%"PRIx64
amdvi_dte_get_fail(uint64_t addr, uint32_t offset) "error: failed to access Device Entry devtab 0x%"PRIx64" offset 0x%"PRIx32
amdvi_invalid_dte(uint64_t addr) "PTE entry at 0x%"PRIx64" is invalid "
amdvi_get_pte_hwerror(uint64_t addr) "hardware error eccessing PTE at addr 0x%"PRIx64
diff --git a/hw/i386/xen/trace-events b/hw/i386/xen/trace-events
new file mode 100644
index 0000000..321fe60
--- /dev/null
+++ b/hw/i386/xen/trace-events
@@ -0,0 +1,6 @@
+# hw/i386/xen/xen_platform.c
+xen_platform_log(char *s) "xen platform: %s"
+
+# hw/i386/xen/xen_pvdevice.c
+xen_pv_mmio_read(uint64_t addr) "WARNING: read from Xen PV Device MMIO space (address %"PRIx64")"
+xen_pv_mmio_write(uint64_t addr) "WARNING: write to Xen PV Device MMIO space (address %"PRIx64")"
diff --git a/hw/input/ps2.c b/hw/input/ps2.c
index 8485a4e..1d3a440 100644
--- a/hw/input/ps2.c
+++ b/hw/input/ps2.c
@@ -881,9 +881,11 @@ static void ps2_mouse_event(DeviceState *dev, QemuConsole *src,
InputEvent *evt)
{
static const int bmap[INPUT_BUTTON__MAX] = {
- [INPUT_BUTTON_LEFT] = MOUSE_EVENT_LBUTTON,
- [INPUT_BUTTON_MIDDLE] = MOUSE_EVENT_MBUTTON,
- [INPUT_BUTTON_RIGHT] = MOUSE_EVENT_RBUTTON,
+ [INPUT_BUTTON_LEFT] = PS2_MOUSE_BUTTON_LEFT,
+ [INPUT_BUTTON_MIDDLE] = PS2_MOUSE_BUTTON_MIDDLE,
+ [INPUT_BUTTON_RIGHT] = PS2_MOUSE_BUTTON_RIGHT,
+ [INPUT_BUTTON_SIDE] = PS2_MOUSE_BUTTON_SIDE,
+ [INPUT_BUTTON_EXTRA] = PS2_MOUSE_BUTTON_EXTRA,
};
PS2MouseState *s = (PS2MouseState *)dev;
InputMoveEvent *move;
diff --git a/hw/input/trace-events b/hw/input/trace-events
index 8c4003f..f3bfbed 100644
--- a/hw/input/trace-events
+++ b/hw/input/trace-events
@@ -8,8 +8,6 @@ ps2_reset_keyboard(void *s) "%p"
ps2_write_keyboard(void *opaque, int val) "%p val %d"
ps2_keyboard_set_translation(void *opaque, int mode) "%p mode %d"
ps2_mouse_send_packet(void *s, int dx1, int dy1, int dz1, int b) "%p x %d y %d z %d bs %#x"
-ps2_mouse_event_disabled(void *opaque, int dx, int dy, int dz, int buttons_state, int mouse_dx, int mouse_dy, int mouse_dz) "%p x %d y %d z %d bs %#x mx %d my %d mz %d "
-ps2_mouse_event(void *opaque, int dx, int dy, int dz, int buttons_state, int mouse_dx, int mouse_dy, int mouse_dz) "%p x %d y %d z %d bs %#x mx %d my %d mz %d "
ps2_mouse_fake_event(void *opaque) "%p"
ps2_write_mouse(void *opaque, int val) "%p val %d"
ps2_kbd_reset(void *opaque) "%p"
diff --git a/hw/intc/trace-events b/hw/intc/trace-events
index 92a6171..39a538d 100644
--- a/hw/intc/trace-events
+++ b/hw/intc/trace-events
@@ -67,7 +67,6 @@ xics_alloc(int irq) "irq %d"
xics_alloc_block(int first, int num, bool lsi, int align) "first irq %d, %d irqs, lsi=%d, alignnum %d"
xics_ics_free(int src, int irq, int num) "Source#%d, first irq %d, %d irqs"
xics_ics_free_warn(int src, int irq) "Source#%d, irq %d is already free"
-xics_icp_post_load(uint32_t server_no, uint32_t xirr, uint64_t addr, uint8_t pend) "server_no %d, xirr %#x, xirr_owner 0x%" PRIx64 ", pending %d"
# hw/intc/s390_flic_kvm.c
flic_create_device(int err) "flic: create device failed %d"
diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
index 846e903..bf57e63 100644
--- a/hw/misc/ivshmem.c
+++ b/hw/misc/ivshmem.c
@@ -749,13 +749,13 @@ static void ivshmem_reset(DeviceState *d)
}
}
-static int ivshmem_setup_interrupts(IVShmemState *s)
+static int ivshmem_setup_interrupts(IVShmemState *s, Error **errp)
{
/* allocate QEMU callback data for receiving interrupts */
s->msi_vectors = g_malloc0(s->vectors * sizeof(MSIVector));
if (ivshmem_has_feature(s, IVSHMEM_MSI)) {
- if (msix_init_exclusive_bar(PCI_DEVICE(s), s->vectors, 1)) {
+ if (msix_init_exclusive_bar(PCI_DEVICE(s), s->vectors, 1, errp)) {
return -1;
}
@@ -898,8 +898,8 @@ static void ivshmem_common_realize(PCIDevice *dev, Error **errp)
qemu_chr_fe_set_handlers(&s->server_chr, ivshmem_can_receive,
ivshmem_read, NULL, s, NULL, true);
- if (ivshmem_setup_interrupts(s) < 0) {
- error_setg(errp, "failed to initialize interrupts");
+ if (ivshmem_setup_interrupts(s, errp) < 0) {
+ error_prepend(errp, "Failed to initialize interrupts: ");
return;
}
}
diff --git a/hw/net/e1000e.c b/hw/net/e1000e.c
index 0e9a25b..b0f429b 100644
--- a/hw/net/e1000e.c
+++ b/hw/net/e1000e.c
@@ -292,7 +292,7 @@ e1000e_init_msix(E1000EState *s)
E1000E_MSIX_IDX, E1000E_MSIX_TABLE,
&s->msix,
E1000E_MSIX_IDX, E1000E_MSIX_PBA,
- 0xA0);
+ 0xA0, NULL);
if (res < 0) {
trace_e1000e_msix_init_fail(res);
diff --git a/hw/net/fsl_etsec/etsec.c b/hw/net/fsl_etsec/etsec.c
index fadf9c8..aa2b0d5 100644
--- a/hw/net/fsl_etsec/etsec.c
+++ b/hw/net/fsl_etsec/etsec.c
@@ -29,7 +29,6 @@
#include "qemu/osdep.h"
#include "sysemu/sysemu.h"
#include "hw/sysbus.h"
-#include "trace.h"
#include "hw/ptimer.h"
#include "etsec.h"
#include "registers.h"
diff --git a/hw/net/rocker/rocker.c b/hw/net/rocker/rocker.c
index e9d215a..6e70fdd 100644
--- a/hw/net/rocker/rocker.c
+++ b/hw/net/rocker/rocker.c
@@ -1256,14 +1256,16 @@ static int rocker_msix_init(Rocker *r)
{
PCIDevice *dev = PCI_DEVICE(r);
int err;
+ Error *local_err = NULL;
err = msix_init(dev, ROCKER_MSIX_VEC_COUNT(r->fp_ports),
&r->msix_bar,
ROCKER_PCI_MSIX_BAR_IDX, ROCKER_PCI_MSIX_TABLE_OFFSET,
&r->msix_bar,
ROCKER_PCI_MSIX_BAR_IDX, ROCKER_PCI_MSIX_PBA_OFFSET,
- 0);
+ 0, &local_err);
if (err) {
+ error_report_err(local_err);
return err;
}
diff --git a/hw/net/trace-events b/hw/net/trace-events
index 1a5c909..c714805 100644
--- a/hw/net/trace-events
+++ b/hw/net/trace-events
@@ -63,10 +63,6 @@ net_rx_pkt_l4_csum_validate_entry(void) "Starting L4 checksum validation"
net_rx_pkt_l4_csum_validate_not_xxp(void) "Not a TCP/UDP packet"
net_rx_pkt_l4_csum_validate_udp_with_no_checksum(void) "UDP packet without checksum"
net_rx_pkt_l4_csum_validate_ip4_fragment(void) "IP4 fragment"
-net_rx_pkt_l4_csum_validate_ip4_udp(void) "IP4/UDP packet"
-net_rx_pkt_l4_csum_validate_ip4_tcp(void) "IP4/TCP packet"
-net_rx_pkt_l4_csum_validate_ip6_udp(void) "IP6/UDP packet"
-net_rx_pkt_l4_csum_validate_ip6_tcp(void) "IP6/TCP packet"
net_rx_pkt_l4_csum_validate_csum(bool csum_valid) "Checksum valid: %d"
net_rx_pkt_l4_csum_calc_entry(void) "Starting L4 checksum calculation"
@@ -117,7 +113,6 @@ e1000e_core_mdic_read(uint8_t page, uint32_t addr, uint32_t data) "MDIC READ: PH
e1000e_core_mdic_read_unhandled(uint8_t page, uint32_t addr) "MDIC READ: PHY[%u][%u] UNHANDLED"
e1000e_core_mdic_write(uint8_t page, uint32_t addr, uint32_t data) "MDIC WRITE: PHY[%u][%u] = 0x%x"
e1000e_core_mdic_write_unhandled(uint8_t page, uint32_t addr) "MDIC WRITE: PHY[%u][%u] UNHANDLED"
-e1000e_core_eeeprom_write(uint16_t bit_in, uint16_t bit_out, uint16_t reading) "eeprom bitnum in %d out %d, reading %d"
e1000e_core_ctrl_write(uint64_t index, uint32_t val) "Write CTRL register 0x%"PRIx64", value: 0x%X"
e1000e_core_ctrl_sw_reset(void) "Doing SW reset"
e1000e_core_ctrl_phy_reset(void) "Doing PHY reset"
@@ -159,7 +154,6 @@ e1000e_rx_desc_buff_write(uint8_t idx, uint64_t addr, uint16_t offset, const voi
e1000e_rx_descr(int ridx, uint64_t base, uint8_t len) "Next RX descriptor: ring #%d, PA: 0x%"PRIx64", length: %u"
e1000e_rx_set_rctl(uint32_t rctl) "RCTL = 0x%x"
e1000e_rx_receive_iov(int iovcnt) "Received vector of %d fragments"
-e1000e_rx_packet_size(size_t full, size_t vhdr, size_t data) "Received packet of %zu bytes total, %zu virt header, %zu data"
e1000e_rx_flt_dropped(void) "Received packet dropped by RX filter"
e1000e_rx_written_to_guest(uint32_t causes) "Received packet written to guest (ICR causes %u)"
e1000e_rx_not_written_to_guest(uint32_t causes) "Received packet NOT written to guest (ICR causes %u)"
@@ -196,14 +190,12 @@ e1000e_rx_metadata_ipv6_filtering_disabled(void) "IPv6 RX filtering disabled by
e1000e_vlan_vet(uint16_t vet) "Setting VLAN ethernet type 0x%X"
-e1000e_irq_set_cause(uint32_t cause) "IRQ cause set 0x%x"
e1000e_irq_msi_notify(uint32_t cause) "MSI notify 0x%x"
e1000e_irq_throttling_no_pending_interrupts(void) "No pending interrupts to notify"
e1000e_irq_msi_notify_postponed(void) "Sending MSI postponed by ITR"
e1000e_irq_legacy_notify_postponed(void) "Raising legacy IRQ postponed by ITR"
e1000e_irq_throttling_no_pending_vec(int idx) "No pending interrupts for vector %d"
e1000e_irq_msix_notify_postponed_vec(int idx) "Sending MSI-X postponed by EITR[%d]"
-e1000e_irq_msix_notify(uint32_t cause) "MSI-X notify 0x%x"
e1000e_irq_legacy_notify(bool level) "IRQ line state: %d"
e1000e_irq_msix_notify_vec(uint32_t vector) "MSI-X notify vector 0x%x"
e1000e_irq_postponed_by_xitr(uint32_t reg) "Interrupt postponed by [E]ITR register 0x%x"
diff --git a/hw/net/vmxnet3.c b/hw/net/vmxnet3.c
index 2cb2731..7dd4565 100644
--- a/hw/net/vmxnet3.c
+++ b/hw/net/vmxnet3.c
@@ -2191,7 +2191,7 @@ vmxnet3_init_msix(VMXNET3State *s)
VMXNET3_MSIX_BAR_IDX, VMXNET3_OFF_MSIX_TABLE,
&s->msix_bar,
VMXNET3_MSIX_BAR_IDX, VMXNET3_OFF_MSIX_PBA(s),
- VMXNET3_MSIX_OFFSET(s));
+ VMXNET3_MSIX_OFFSET(s), NULL);
if (0 > res) {
VMW_WRPRN("Failed to initialize MSI-X, error %d", res);
diff --git a/hw/pci-bridge/Makefile.objs b/hw/pci-bridge/Makefile.objs
index f2adfe3..c4683cf 100644
--- a/hw/pci-bridge/Makefile.objs
+++ b/hw/pci-bridge/Makefile.objs
@@ -1,5 +1,6 @@
common-obj-y += pci_bridge_dev.o
-common-obj-y += pci_expander_bridge.o
+common-obj-$(CONFIG_PCIE_PORT) += pcie_root_port.o gen_pcie_root_port.o
+common-obj-$(CONFIG_PXB) += pci_expander_bridge.o
common-obj-$(CONFIG_XIO3130) += xio3130_upstream.o xio3130_downstream.o
common-obj-$(CONFIG_IOH3420) += ioh3420.o
common-obj-$(CONFIG_I82801B11) += i82801b11.o
diff --git a/hw/pci-bridge/gen_pcie_root_port.c b/hw/pci-bridge/gen_pcie_root_port.c
new file mode 100644
index 0000000..8ebffa8
--- /dev/null
+++ b/hw/pci-bridge/gen_pcie_root_port.c
@@ -0,0 +1,87 @@
+/*
+ * Generic PCI Express Root Port emulation
+ *
+ * Copyright (C) 2017 Red Hat Inc
+ *
+ * Authors:
+ * Marcel Apfelbaum <marcel@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "hw/pci/msix.h"
+#include "hw/pci/pcie_port.h"
+
+#define TYPE_GEN_PCIE_ROOT_PORT "pcie-root-port"
+
+#define GEN_PCIE_ROOT_PORT_AER_OFFSET 0x100
+#define GEN_PCIE_ROOT_PORT_MSIX_NR_VECTOR 1
+
+static uint8_t gen_rp_aer_vector(const PCIDevice *d)
+{
+ return 0;
+}
+
+static int gen_rp_interrupts_init(PCIDevice *d, Error **errp)
+{
+ int rc;
+
+ rc = msix_init_exclusive_bar(d, GEN_PCIE_ROOT_PORT_MSIX_NR_VECTOR, 0, errp);
+
+ if (rc < 0) {
+ assert(rc == -ENOTSUP);
+ } else {
+ msix_vector_use(d, 0);
+ }
+
+ return rc;
+}
+
+static void gen_rp_interrupts_uninit(PCIDevice *d)
+{
+ msix_uninit_exclusive_bar(d);
+}
+
+static const VMStateDescription vmstate_rp_dev = {
+ .name = "pcie-root-port",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .post_load = pcie_cap_slot_post_load,
+ .fields = (VMStateField[]) {
+ VMSTATE_PCI_DEVICE(parent_obj.parent_obj.parent_obj, PCIESlot),
+ VMSTATE_STRUCT(parent_obj.parent_obj.parent_obj.exp.aer_log,
+ PCIESlot, 0, vmstate_pcie_aer_log, PCIEAERLog),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void gen_rp_dev_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+ PCIERootPortClass *rpc = PCIE_ROOT_PORT_CLASS(klass);
+
+ k->vendor_id = PCI_VENDOR_ID_REDHAT;
+ k->device_id = PCI_DEVICE_ID_REDHAT_PCIE_RP;
+ dc->desc = "PCI Express Root Port";
+ dc->vmsd = &vmstate_rp_dev;
+ rpc->aer_vector = gen_rp_aer_vector;
+ rpc->interrupts_init = gen_rp_interrupts_init;
+ rpc->interrupts_uninit = gen_rp_interrupts_uninit;
+ rpc->aer_offset = GEN_PCIE_ROOT_PORT_AER_OFFSET;
+}
+
+static const TypeInfo gen_rp_dev_info = {
+ .name = TYPE_GEN_PCIE_ROOT_PORT,
+ .parent = TYPE_PCIE_ROOT_PORT,
+ .class_init = gen_rp_dev_class_init,
+};
+
+ static void gen_rp_register_types(void)
+ {
+ type_register_static(&gen_rp_dev_info);
+ }
+ type_init(gen_rp_register_types)
diff --git a/hw/pci-bridge/ioh3420.c b/hw/pci-bridge/ioh3420.c
index 0eef87a..da4e5bd 100644
--- a/hw/pci-bridge/ioh3420.c
+++ b/hw/pci-bridge/ioh3420.c
@@ -61,119 +61,28 @@ static uint8_t ioh3420_aer_vector(const PCIDevice *d)
return 0;
}
-static void ioh3420_aer_vector_update(PCIDevice *d)
+static int ioh3420_interrupts_init(PCIDevice *d, Error **errp)
{
- pcie_aer_root_set_vector(d, ioh3420_aer_vector(d));
-}
-
-static void ioh3420_write_config(PCIDevice *d,
- uint32_t address, uint32_t val, int len)
-{
- uint32_t root_cmd =
- pci_get_long(d->config + d->exp.aer_cap + PCI_ERR_ROOT_COMMAND);
-
- pci_bridge_write_config(d, address, val, len);
- ioh3420_aer_vector_update(d);
- pcie_cap_slot_write_config(d, address, val, len);
- pcie_aer_write_config(d, address, val, len);
- pcie_aer_root_write_config(d, address, val, len, root_cmd);
-}
-
-static void ioh3420_reset(DeviceState *qdev)
-{
- PCIDevice *d = PCI_DEVICE(qdev);
-
- ioh3420_aer_vector_update(d);
- pcie_cap_root_reset(d);
- pcie_cap_deverr_reset(d);
- pcie_cap_slot_reset(d);
- pcie_cap_arifwd_reset(d);
- pcie_aer_root_reset(d);
- pci_bridge_reset(qdev);
- pci_bridge_disable_base_limit(d);
-}
-
-static int ioh3420_initfn(PCIDevice *d)
-{
- PCIEPort *p = PCIE_PORT(d);
- PCIESlot *s = PCIE_SLOT(d);
int rc;
- Error *err = NULL;
-
- pci_config_set_interrupt_pin(d->config, 1);
- pci_bridge_initfn(d, TYPE_PCIE_BUS);
- pcie_port_init_reg(d);
-
- rc = pci_bridge_ssvid_init(d, IOH_EP_SSVID_OFFSET,
- IOH_EP_SSVID_SVID, IOH_EP_SSVID_SSID);
- if (rc < 0) {
- goto err_bridge;
- }
+ Error *local_err = NULL;
rc = msi_init(d, IOH_EP_MSI_OFFSET, IOH_EP_MSI_NR_VECTOR,
IOH_EP_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_64BIT,
- IOH_EP_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_MASKBIT, &err);
+ IOH_EP_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_MASKBIT,
+ &local_err);
if (rc < 0) {
assert(rc == -ENOTSUP);
- error_report_err(err);
- goto err_bridge;
+ error_propagate(errp, local_err);
}
- rc = pcie_cap_init(d, IOH_EP_EXP_OFFSET, PCI_EXP_TYPE_ROOT_PORT, p->port);
- if (rc < 0) {
- goto err_msi;
- }
-
- pcie_cap_arifwd_init(d);
- pcie_cap_deverr_init(d);
- pcie_cap_slot_init(d, s->slot);
- pcie_cap_root_init(d);
-
- pcie_chassis_create(s->chassis);
- rc = pcie_chassis_add_slot(s);
- if (rc < 0) {
- goto err_pcie_cap;
- }
-
- rc = pcie_aer_init(d, PCI_ERR_VER, IOH_EP_AER_OFFSET,
- PCI_ERR_SIZEOF, &err);
- if (rc < 0) {
- error_report_err(err);
- goto err;
- }
- pcie_aer_root_init(d);
- ioh3420_aer_vector_update(d);
-
- return 0;
-
-err:
- pcie_chassis_del_slot(s);
-err_pcie_cap:
- pcie_cap_exit(d);
-err_msi:
- msi_uninit(d);
-err_bridge:
- pci_bridge_exitfn(d);
return rc;
}
-static void ioh3420_exitfn(PCIDevice *d)
+static void ioh3420_interrupts_uninit(PCIDevice *d)
{
- PCIESlot *s = PCIE_SLOT(d);
-
- pcie_aer_exit(d);
- pcie_chassis_del_slot(s);
- pcie_cap_exit(d);
msi_uninit(d);
- pci_bridge_exitfn(d);
}
-static Property ioh3420_props[] = {
- DEFINE_PROP_BIT(COMPAT_PROP_PCP, PCIDevice, cap_present,
- QEMU_PCIE_SLTCAP_PCP_BITNR, true),
- DEFINE_PROP_END_OF_LIST()
-};
-
static const VMStateDescription vmstate_ioh3420 = {
.name = "ioh-3240-express-root-port",
.version_id = 1,
@@ -191,25 +100,25 @@ static void ioh3420_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+ PCIERootPortClass *rpc = PCIE_ROOT_PORT_CLASS(klass);
- k->is_express = 1;
- k->is_bridge = 1;
- k->config_write = ioh3420_write_config;
- k->init = ioh3420_initfn;
- k->exit = ioh3420_exitfn;
k->vendor_id = PCI_VENDOR_ID_INTEL;
k->device_id = PCI_DEVICE_ID_IOH_EPORT;
k->revision = PCI_DEVICE_ID_IOH_REV;
- set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
dc->desc = "Intel IOH device id 3420 PCIE Root Port";
- dc->reset = ioh3420_reset;
dc->vmsd = &vmstate_ioh3420;
- dc->props = ioh3420_props;
+ rpc->aer_vector = ioh3420_aer_vector;
+ rpc->interrupts_init = ioh3420_interrupts_init;
+ rpc->interrupts_uninit = ioh3420_interrupts_uninit;
+ rpc->exp_offset = IOH_EP_EXP_OFFSET;
+ rpc->aer_offset = IOH_EP_AER_OFFSET;
+ rpc->ssvid_offset = IOH_EP_SSVID_OFFSET;
+ rpc->ssid = IOH_EP_SSVID_SSID;
}
static const TypeInfo ioh3420_info = {
.name = "ioh3420",
- .parent = TYPE_PCIE_SLOT,
+ .parent = TYPE_PCIE_ROOT_PORT,
.class_init = ioh3420_class_init,
};
diff --git a/hw/pci-bridge/pci_bridge_dev.c b/hw/pci-bridge/pci_bridge_dev.c
index 5dbd933..647ad80 100644
--- a/hw/pci-bridge/pci_bridge_dev.c
+++ b/hw/pci-bridge/pci_bridge_dev.c
@@ -163,7 +163,7 @@ static Property pci_bridge_dev_properties[] = {
DEFINE_PROP_ON_OFF_AUTO(PCI_BRIDGE_DEV_PROP_MSI, PCIBridgeDev, msi,
ON_OFF_AUTO_AUTO),
DEFINE_PROP_BIT(PCI_BRIDGE_DEV_PROP_SHPC, PCIBridgeDev, flags,
- PCI_BRIDGE_DEV_F_SHPC_REQ, true),
+ PCI_BRIDGE_DEV_F_SHPC_REQ, false),
DEFINE_PROP_END_OF_LIST(),
};
diff --git a/hw/pci-bridge/pcie_root_port.c b/hw/pci-bridge/pcie_root_port.c
new file mode 100644
index 0000000..cf36318
--- /dev/null
+++ b/hw/pci-bridge/pcie_root_port.c
@@ -0,0 +1,171 @@
+/*
+ * Base class for PCI Express Root Ports
+ *
+ * Copyright (C) 2017 Red Hat Inc
+ *
+ * Authors:
+ * Marcel Apfelbaum <marcel@redhat.com>
+ *
+ * Most of the code was migrated from hw/pci-bridge/ioh3420.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "hw/pci/pcie_port.h"
+
+static void rp_aer_vector_update(PCIDevice *d)
+{
+ PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(d);
+
+ if (rpc->aer_vector) {
+ pcie_aer_root_set_vector(d, rpc->aer_vector(d));
+ }
+}
+
+static void rp_write_config(PCIDevice *d, uint32_t address,
+ uint32_t val, int len)
+{
+ uint32_t root_cmd =
+ pci_get_long(d->config + d->exp.aer_cap + PCI_ERR_ROOT_COMMAND);
+
+ pci_bridge_write_config(d, address, val, len);
+ rp_aer_vector_update(d);
+ pcie_cap_slot_write_config(d, address, val, len);
+ pcie_aer_write_config(d, address, val, len);
+ pcie_aer_root_write_config(d, address, val, len, root_cmd);
+}
+
+static void rp_reset(DeviceState *qdev)
+{
+ PCIDevice *d = PCI_DEVICE(qdev);
+
+ rp_aer_vector_update(d);
+ pcie_cap_root_reset(d);
+ pcie_cap_deverr_reset(d);
+ pcie_cap_slot_reset(d);
+ pcie_cap_arifwd_reset(d);
+ pcie_aer_root_reset(d);
+ pci_bridge_reset(qdev);
+ pci_bridge_disable_base_limit(d);
+}
+
+static void rp_realize(PCIDevice *d, Error **errp)
+{
+ PCIEPort *p = PCIE_PORT(d);
+ PCIESlot *s = PCIE_SLOT(d);
+ PCIDeviceClass *dc = PCI_DEVICE_GET_CLASS(d);
+ PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(d);
+ int rc;
+ Error *local_err = NULL;
+
+ pci_config_set_interrupt_pin(d->config, 1);
+ pci_bridge_initfn(d, TYPE_PCIE_BUS);
+ pcie_port_init_reg(d);
+
+ rc = pci_bridge_ssvid_init(d, rpc->ssvid_offset, dc->vendor_id, rpc->ssid);
+ if (rc < 0) {
+ error_setg(errp, "Can't init SSV ID, error %d", rc);
+ goto err_bridge;
+ }
+
+ if (rpc->interrupts_init) {
+ rc = rpc->interrupts_init(d, &local_err);
+ if (rc < 0) {
+ error_propagate(errp, local_err);
+ goto err_bridge;
+ }
+ }
+
+ rc = pcie_cap_init(d, rpc->exp_offset, PCI_EXP_TYPE_ROOT_PORT, p->port);
+ if (rc < 0) {
+ error_setg(errp, "Can't add Root Port capability, error %d", rc);
+ goto err_int;
+ }
+
+ pcie_cap_arifwd_init(d);
+ pcie_cap_deverr_init(d);
+ pcie_cap_slot_init(d, s->slot);
+ pcie_cap_root_init(d);
+
+ pcie_chassis_create(s->chassis);
+ rc = pcie_chassis_add_slot(s);
+ if (rc < 0) {
+ error_setg(errp, "Can't add chassis slot, error %d", rc);
+ goto err_pcie_cap;
+ }
+
+ rc = pcie_aer_init(d, PCI_ERR_VER, rpc->aer_offset,
+ PCI_ERR_SIZEOF, &local_err);
+ if (rc < 0) {
+ error_propagate(errp, local_err);
+ goto err;
+ }
+ pcie_aer_root_init(d);
+ rp_aer_vector_update(d);
+
+ return;
+
+err:
+ pcie_chassis_del_slot(s);
+err_pcie_cap:
+ pcie_cap_exit(d);
+err_int:
+ if (rpc->interrupts_uninit) {
+ rpc->interrupts_uninit(d);
+ }
+err_bridge:
+ pci_bridge_exitfn(d);
+}
+
+static void rp_exit(PCIDevice *d)
+{
+ PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(d);
+ PCIESlot *s = PCIE_SLOT(d);
+
+ pcie_aer_exit(d);
+ pcie_chassis_del_slot(s);
+ pcie_cap_exit(d);
+ if (rpc->interrupts_uninit) {
+ rpc->interrupts_uninit(d);
+ }
+ pci_bridge_exitfn(d);
+}
+
+static Property rp_props[] = {
+ DEFINE_PROP_BIT(COMPAT_PROP_PCP, PCIDevice, cap_present,
+ QEMU_PCIE_SLTCAP_PCP_BITNR, true),
+ DEFINE_PROP_END_OF_LIST()
+};
+
+static void rp_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->is_express = 1;
+ k->is_bridge = 1;
+ k->config_write = rp_write_config;
+ k->realize = rp_realize;
+ k->exit = rp_exit;
+ set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
+ dc->reset = rp_reset;
+ dc->props = rp_props;
+}
+
+static const TypeInfo rp_info = {
+ .name = TYPE_PCIE_ROOT_PORT,
+ .parent = TYPE_PCIE_SLOT,
+ .class_init = rp_class_init,
+ .abstract = true,
+ .class_size = sizeof(PCIERootPortClass),
+};
+
+static void rp_register_types(void)
+{
+ type_register_static(&rp_info);
+}
+
+type_init(rp_register_types)
diff --git a/hw/pci/msix.c b/hw/pci/msix.c
index ee1714d..bb54e8b 100644
--- a/hw/pci/msix.c
+++ b/hw/pci/msix.c
@@ -21,6 +21,7 @@
#include "hw/pci/pci.h"
#include "hw/xen/xen.h"
#include "qemu/range.h"
+#include "qapi/error.h"
#define MSIX_CAP_LENGTH 12
@@ -238,11 +239,31 @@ static void msix_mask_all(struct PCIDevice *dev, unsigned nentries)
}
}
-/* Initialize the MSI-X structures */
+/*
+ * Make PCI device @dev MSI-X capable
+ * @nentries is the max number of MSI-X vectors that the device support.
+ * @table_bar is the MemoryRegion that MSI-X table structure resides.
+ * @table_bar_nr is number of base address register corresponding to @table_bar.
+ * @table_offset indicates the offset that the MSI-X table structure starts with
+ * in @table_bar.
+ * @pba_bar is the MemoryRegion that the Pending Bit Array structure resides.
+ * @pba_bar_nr is number of base address register corresponding to @pba_bar.
+ * @pba_offset indicates the offset that the Pending Bit Array structure
+ * starts with in @pba_bar.
+ * Non-zero @cap_pos puts capability MSI-X at that offset in PCI config space.
+ * @errp is for returning errors.
+ *
+ * Return 0 on success; set @errp and return -errno on error:
+ * -ENOTSUP means lacking msi support for a msi-capable platform.
+ * -EINVAL means capability overlap, happens when @cap_pos is non-zero,
+ * also means a programming error, except device assignment, which can check
+ * if a real HW is broken.
+ */
int msix_init(struct PCIDevice *dev, unsigned short nentries,
MemoryRegion *table_bar, uint8_t table_bar_nr,
unsigned table_offset, MemoryRegion *pba_bar,
- uint8_t pba_bar_nr, unsigned pba_offset, uint8_t cap_pos)
+ uint8_t pba_bar_nr, unsigned pba_offset, uint8_t cap_pos,
+ Error **errp)
{
int cap;
unsigned table_size, pba_size;
@@ -250,10 +271,12 @@ int msix_init(struct PCIDevice *dev, unsigned short nentries,
/* Nothing to do if MSI is not supported by interrupt controller */
if (!msi_nonbroken) {
+ error_setg(errp, "MSI-X is not supported by interrupt controller");
return -ENOTSUP;
}
if (nentries < 1 || nentries > PCI_MSIX_FLAGS_QSIZE + 1) {
+ error_setg(errp, "The number of MSI-X vectors is invalid");
return -EINVAL;
}
@@ -266,10 +289,13 @@ int msix_init(struct PCIDevice *dev, unsigned short nentries,
table_offset + table_size > memory_region_size(table_bar) ||
pba_offset + pba_size > memory_region_size(pba_bar) ||
(table_offset | pba_offset) & PCI_MSIX_FLAGS_BIRMASK) {
+ error_setg(errp, "table & pba overlap, or they don't fit in BARs,"
+ " or don't align");
return -EINVAL;
}
- cap = pci_add_capability(dev, PCI_CAP_ID_MSIX, cap_pos, MSIX_CAP_LENGTH);
+ cap = pci_add_capability2(dev, PCI_CAP_ID_MSIX,
+ cap_pos, MSIX_CAP_LENGTH, errp);
if (cap < 0) {
return cap;
}
@@ -306,7 +332,7 @@ int msix_init(struct PCIDevice *dev, unsigned short nentries,
}
int msix_init_exclusive_bar(PCIDevice *dev, unsigned short nentries,
- uint8_t bar_nr)
+ uint8_t bar_nr, Error **errp)
{
int ret;
char *name;
@@ -338,7 +364,7 @@ int msix_init_exclusive_bar(PCIDevice *dev, unsigned short nentries,
ret = msix_init(dev, nentries, &dev->msix_exclusive_bar, bar_nr,
0, &dev->msix_exclusive_bar,
bar_nr, bar_pba_offset,
- 0);
+ 0, errp);
if (ret) {
return ret;
}
@@ -447,8 +473,10 @@ void msix_notify(PCIDevice *dev, unsigned vector)
{
MSIMessage msg;
- if (vector >= dev->msix_entries_nr || !dev->msix_entry_used[vector])
+ if (vector >= dev->msix_entries_nr || !dev->msix_entry_used[vector]) {
return;
+ }
+
if (msix_is_masked(dev, vector)) {
msix_set_pending(dev, vector);
return;
@@ -483,8 +511,10 @@ void msix_reset(PCIDevice *dev)
/* Mark vector as used. */
int msix_vector_use(PCIDevice *dev, unsigned vector)
{
- if (vector >= dev->msix_entries_nr)
+ if (vector >= dev->msix_entries_nr) {
return -EINVAL;
+ }
+
dev->msix_entry_used[vector]++;
return 0;
}
diff --git a/hw/pci/pci.c b/hw/pci/pci.c
index 47ca3af..a563555 100644
--- a/hw/pci/pci.c
+++ b/hw/pci/pci.c
@@ -2195,7 +2195,7 @@ static void pci_add_option_rom(PCIDevice *pdev, bool is_default_rom,
snprintf(name, sizeof(name), "%s.rom", object_get_typename(OBJECT(pdev)));
}
pdev->has_rom = true;
- memory_region_init_ram(&pdev->rom, OBJECT(pdev), name, size, &error_fatal);
+ memory_region_init_rom(&pdev->rom, OBJECT(pdev), name, size, &error_fatal);
vmstate_register_ram(&pdev->rom, &pdev->qdev);
ptr = memory_region_get_ram_ptr(&pdev->rom);
load_image(path, ptr);
diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs
index 8025129..0012934 100644
--- a/hw/ppc/Makefile.objs
+++ b/hw/ppc/Makefile.objs
@@ -16,6 +16,8 @@ obj-y += ppc405_boards.o ppc4xx_devs.o ppc405_uc.o ppc440_bamboo.o
obj-y += ppc4xx_pci.o
# PReP
obj-$(CONFIG_PREP) += prep.o
+obj-$(CONFIG_PREP) += prep_systemio.o
+obj-${CONFIG_RS6000_MC} += rs6000_mc.o
# OldWorld PowerMac
obj-$(CONFIG_MAC) += mac_oldworld.o
# NewWorld PowerMac
diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
index cf8b122..f7df238 100644
--- a/hw/ppc/e500.c
+++ b/hw/ppc/e500.c
@@ -827,6 +827,12 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
env = &cpu->env;
cs = CPU(cpu);
+ if (env->mmu_model != POWERPC_MMU_BOOKE206) {
+ fprintf(stderr, "MMU model %i not supported by this machine.\n",
+ env->mmu_model);
+ exit(1);
+ }
+
if (!firstenv) {
firstenv = env;
}
@@ -1049,27 +1055,18 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
boot_info->dt_size = dt_size;
}
-static int e500_ccsr_initfn(SysBusDevice *dev)
+static void e500_ccsr_initfn(Object *obj)
{
- PPCE500CCSRState *ccsr;
-
- ccsr = CCSR(dev);
- memory_region_init(&ccsr->ccsr_space, OBJECT(ccsr), "e500-ccsr",
+ PPCE500CCSRState *ccsr = CCSR(obj);
+ memory_region_init(&ccsr->ccsr_space, obj, "e500-ccsr",
MPC8544_CCSRBAR_SIZE);
- return 0;
-}
-
-static void e500_ccsr_class_init(ObjectClass *klass, void *data)
-{
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
- k->init = e500_ccsr_initfn;
}
static const TypeInfo e500_ccsr_info = {
.name = TYPE_CCSR,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(PPCE500CCSRState),
- .class_init = e500_ccsr_class_init,
+ .instance_init = e500_ccsr_initfn,
};
static void e500_register_types(void)
diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index 83597fe..4fab5c0 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -381,7 +381,7 @@ static void ppc_powernv_init(MachineState *machine)
fw_size = load_image_targphys(fw_filename, FW_LOAD_ADDR, FW_MAX_SIZE);
if (fw_size < 0) {
- hw_error("qemu: could not load OPAL '%s'\n", fw_filename);
+ error_report("qemu: could not load OPAL '%s'", fw_filename);
exit(1);
}
g_free(fw_filename);
@@ -393,8 +393,8 @@ static void ppc_powernv_init(MachineState *machine)
kernel_size = load_image_targphys(machine->kernel_filename,
KERNEL_LOAD_ADDR, 0x2000000);
if (kernel_size < 0) {
- hw_error("qemu: could not load kernel'%s'\n",
- machine->kernel_filename);
+ error_report("qemu: could not load kernel'%s'",
+ machine->kernel_filename);
exit(1);
}
}
diff --git a/hw/ppc/ppc.c b/hw/ppc/ppc.c
index 8945869..d171e60 100644
--- a/hw/ppc/ppc.c
+++ b/hw/ppc/ppc.c
@@ -847,9 +847,8 @@ static void cpu_ppc_set_tb_clk (void *opaque, uint32_t freq)
cpu_ppc_store_purr(cpu, 0x0000000000000000ULL);
}
-static void timebase_pre_save(void *opaque)
+static void timebase_save(PPCTimebase *tb)
{
- PPCTimebase *tb = opaque;
uint64_t ticks = cpu_get_host_ticks();
PowerPCCPU *first_ppc_cpu = POWERPC_CPU(first_cpu);
@@ -858,43 +857,30 @@ static void timebase_pre_save(void *opaque)
return;
}
+ /* not used anymore, we keep it for compatibility */
tb->time_of_the_day_ns = qemu_clock_get_ns(QEMU_CLOCK_HOST);
/*
- * tb_offset is only expected to be changed by migration so
+ * tb_offset is only expected to be changed by QEMU so
* there is no need to update it from KVM here
*/
tb->guest_timebase = ticks + first_ppc_cpu->env.tb_env->tb_offset;
}
-static int timebase_post_load(void *opaque, int version_id)
+static void timebase_load(PPCTimebase *tb)
{
- PPCTimebase *tb_remote = opaque;
CPUState *cpu;
PowerPCCPU *first_ppc_cpu = POWERPC_CPU(first_cpu);
- int64_t tb_off_adj, tb_off, ns_diff;
- int64_t migration_duration_ns, migration_duration_tb, guest_tb, host_ns;
+ int64_t tb_off_adj, tb_off;
unsigned long freq;
if (!first_ppc_cpu->env.tb_env) {
error_report("No timebase object");
- return -1;
+ return;
}
freq = first_ppc_cpu->env.tb_env->tb_freq;
- /*
- * Calculate timebase on the destination side of migration.
- * The destination timebase must be not less than the source timebase.
- * We try to adjust timebase by downtime if host clocks are not
- * too much out of sync (1 second for now).
- */
- host_ns = qemu_clock_get_ns(QEMU_CLOCK_HOST);
- ns_diff = MAX(0, host_ns - tb_remote->time_of_the_day_ns);
- migration_duration_ns = MIN(NANOSECONDS_PER_SECOND, ns_diff);
- migration_duration_tb = muldiv64(freq, migration_duration_ns,
- NANOSECONDS_PER_SECOND);
- guest_tb = tb_remote->guest_timebase + MIN(0, migration_duration_tb);
- tb_off_adj = guest_tb - cpu_get_host_ticks();
+ tb_off_adj = tb->guest_timebase - cpu_get_host_ticks();
tb_off = first_ppc_cpu->env.tb_env->tb_offset;
trace_ppc_tb_adjust(tb_off, tb_off_adj, tb_off_adj - tb_off,
@@ -904,9 +890,44 @@ static int timebase_post_load(void *opaque, int version_id)
CPU_FOREACH(cpu) {
PowerPCCPU *pcpu = POWERPC_CPU(cpu);
pcpu->env.tb_env->tb_offset = tb_off_adj;
+#if defined(CONFIG_KVM)
+ kvm_set_one_reg(cpu, KVM_REG_PPC_TB_OFFSET,
+ &pcpu->env.tb_env->tb_offset);
+#endif
}
+}
- return 0;
+void cpu_ppc_clock_vm_state_change(void *opaque, int running,
+ RunState state)
+{
+ PPCTimebase *tb = opaque;
+
+ if (running) {
+ timebase_load(tb);
+ } else {
+ timebase_save(tb);
+ }
+}
+
+/*
+ * When migrating, read the clock just before migration,
+ * so that the guest clock counts during the events
+ * between:
+ *
+ * * vm_stop()
+ * *
+ * * pre_save()
+ *
+ * This reduces clock difference on migration from 5s
+ * to 0.1s (when max_downtime == 5s), because sending the
+ * final pages of memory (which happens between vm_stop()
+ * and pre_save()) takes max_downtime.
+ */
+static void timebase_pre_save(void *opaque)
+{
+ PPCTimebase *tb = opaque;
+
+ timebase_save(tb);
}
const VMStateDescription vmstate_ppc_timebase = {
@@ -915,7 +936,6 @@ const VMStateDescription vmstate_ppc_timebase = {
.minimum_version_id = 1,
.minimum_version_id_old = 1,
.pre_save = timebase_pre_save,
- .post_load = timebase_post_load,
.fields = (VMStateField []) {
VMSTATE_UINT64(guest_timebase, PPCTimebase),
VMSTATE_INT64(time_of_the_day_ns, PPCTimebase),
@@ -950,13 +970,6 @@ clk_setup_cb cpu_ppc_tb_init (CPUPPCState *env, uint32_t freq)
}
/* Specific helpers for POWER & PowerPC 601 RTC */
-#if 0
-static clk_setup_cb cpu_ppc601_rtc_init (CPUPPCState *env)
-{
- return cpu_ppc_tb_init(env, 7812500);
-}
-#endif
-
void cpu_ppc601_store_rtcu (CPUPPCState *env, uint32_t value)
{
_cpu_ppc_store_tbu(env, value);
diff --git a/hw/ppc/ppc440_bamboo.c b/hw/ppc/ppc440_bamboo.c
index 5c535b1..9d997bf 100644
--- a/hw/ppc/ppc440_bamboo.c
+++ b/hw/ppc/ppc440_bamboo.c
@@ -193,6 +193,12 @@ static void bamboo_init(MachineState *machine)
}
env = &cpu->env;
+ if (env->mmu_model != POWERPC_MMU_BOOKE) {
+ fprintf(stderr, "MMU model %i not supported by this machine.\n",
+ env->mmu_model);
+ exit(1);
+ }
+
qemu_register_reset(main_cpu_reset, cpu);
ppc_booke_timers_init(cpu, 400000000, 0);
ppc_dcr_init(env, NULL, NULL);
diff --git a/hw/ppc/ppc_booke.c b/hw/ppc/ppc_booke.c
index ab8d026..60baffa 100644
--- a/hw/ppc/ppc_booke.c
+++ b/hw/ppc/ppc_booke.c
@@ -198,8 +198,12 @@ static void booke_decr_cb(void *opaque)
booke_update_irq(cpu);
if (env->spr[SPR_BOOKE_TCR] & TCR_ARE) {
- /* Auto Reload */
- cpu_ppc_store_decr(env, env->spr[SPR_BOOKE_DECAR]);
+ /* Do not reload 0, it is already there. It would just trigger
+ * the timer again and lead to infinite loop */
+ if (env->spr[SPR_BOOKE_DECAR] != 0) {
+ /* Auto Reload */
+ cpu_ppc_store_decr(env, env->spr[SPR_BOOKE_DECAR]);
+ }
}
}
diff --git a/hw/ppc/ppce500_spin.c b/hw/ppc/ppce500_spin.c
index eb219ab..69ca2d0 100644
--- a/hw/ppc/ppce500_spin.c
+++ b/hw/ppc/ppce500_spin.c
@@ -54,9 +54,9 @@ typedef struct SpinState {
SpinInfo spin[MAX_CPUS];
} SpinState;
-static void spin_reset(void *opaque)
+static void spin_reset(DeviceState *dev)
{
- SpinState *s = opaque;
+ SpinState *s = E500_SPIN(dev);
int i;
for (i = 0; i < MAX_CPUS; i++) {
@@ -174,30 +174,28 @@ static const MemoryRegionOps spin_rw_ops = {
.endianness = DEVICE_BIG_ENDIAN,
};
-static int ppce500_spin_initfn(SysBusDevice *dev)
+static void ppce500_spin_initfn(Object *obj)
{
+ SysBusDevice *dev = SYS_BUS_DEVICE(obj);
SpinState *s = E500_SPIN(dev);
- memory_region_init_io(&s->iomem, OBJECT(s), &spin_rw_ops, s,
+ memory_region_init_io(&s->iomem, obj, &spin_rw_ops, s,
"e500 spin pv device", sizeof(SpinInfo) * MAX_CPUS);
sysbus_init_mmio(dev, &s->iomem);
-
- qemu_register_reset(spin_reset, s);
-
- return 0;
}
static void ppce500_spin_class_init(ObjectClass *klass, void *data)
{
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
- k->init = ppce500_spin_initfn;
+ dc->reset = spin_reset;
}
static const TypeInfo ppce500_spin_info = {
.name = TYPE_E500_SPIN,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(SpinState),
+ .instance_init = ppce500_spin_initfn,
.class_init = ppce500_spin_class_init,
};
diff --git a/hw/ppc/prep.c b/hw/ppc/prep.c
index 054af1e..ca7959c 100644
--- a/hw/ppc/prep.c
+++ b/hw/ppc/prep.c
@@ -2,6 +2,7 @@
* QEMU PPC PREP hardware System Emulator
*
* Copyright (c) 2003-2007 Jocelyn Mayer
+ * Copyright (c) 2017 Hervé Poussineau
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -43,17 +44,21 @@
#include "hw/isa/pc87312.h"
#include "sysemu/block-backend.h"
#include "sysemu/arch_init.h"
+#include "sysemu/kvm.h"
#include "sysemu/qtest.h"
#include "exec/address-spaces.h"
#include "trace.h"
#include "elf.h"
#include "qemu/cutils.h"
+#include "kvm_ppc.h"
/* SMP is not enabled, for now */
#define MAX_CPUS 1
#define MAX_IDE_BUS 2
+#define CFG_ADDR 0xf0000510
+
#define BIOS_SIZE (1024 * 1024)
#define BIOS_FILENAME "ppc_rom.bin"
#define KERNEL_LOAD_ADDR 0x01000000
@@ -316,6 +321,12 @@ static uint32_t PREP_io_800_readb (void *opaque, uint32_t addr)
#define NVRAM_SIZE 0x2000
+static void fw_cfg_boot_set(void *opaque, const char *boot_device,
+ Error **errp)
+{
+ fw_cfg_modify_i16(opaque, FW_CFG_BOOT_DEVICE, boot_device[0]);
+}
+
static void ppc_prep_reset(void *opaque)
{
PowerPCCPU *cpu = opaque;
@@ -339,13 +350,13 @@ static PortioList prep_port_list;
/* NVRAM helpers */
static inline uint32_t nvram_read(Nvram *nvram, uint32_t addr)
{
- NvramClass *k = NVRAM_GET_CLASS(sysctrl->nvram);
+ NvramClass *k = NVRAM_GET_CLASS(nvram);
return (k->read)(nvram, addr);
}
static inline void nvram_write(Nvram *nvram, uint32_t addr, uint32_t val)
{
- NvramClass *k = NVRAM_GET_CLASS(sysctrl->nvram);
+ NvramClass *k = NVRAM_GET_CLASS(nvram);
(k->write)(nvram, addr, val);
}
@@ -677,4 +688,223 @@ static void prep_machine_init(MachineClass *mc)
mc->default_boot_order = "cad";
}
+static int prep_set_cmos_checksum(DeviceState *dev, void *opaque)
+{
+ uint16_t checksum = *(uint16_t *)opaque;
+ ISADevice *rtc;
+
+ if (object_dynamic_cast(OBJECT(dev), "mc146818rtc")) {
+ rtc = ISA_DEVICE(dev);
+ rtc_set_memory(rtc, 0x2e, checksum & 0xff);
+ rtc_set_memory(rtc, 0x3e, checksum & 0xff);
+ rtc_set_memory(rtc, 0x2f, checksum >> 8);
+ rtc_set_memory(rtc, 0x3f, checksum >> 8);
+ }
+ return 0;
+}
+
+static void ibm_40p_init(MachineState *machine)
+{
+ CPUPPCState *env = NULL;
+ uint16_t cmos_checksum;
+ PowerPCCPU *cpu;
+ DeviceState *dev;
+ SysBusDevice *pcihost;
+ Nvram *m48t59 = NULL;
+ PCIBus *pci_bus;
+ ISABus *isa_bus;
+ void *fw_cfg;
+ int i;
+ uint32_t kernel_base = 0, initrd_base = 0;
+ long kernel_size = 0, initrd_size = 0;
+ char boot_device;
+
+ /* init CPU */
+ if (!machine->cpu_model) {
+ machine->cpu_model = "604";
+ }
+ cpu = cpu_ppc_init(machine->cpu_model);
+ if (!cpu) {
+ error_report("could not initialize CPU '%s'",
+ machine->cpu_model);
+ exit(1);
+ }
+ env = &cpu->env;
+ if (PPC_INPUT(env) != PPC_FLAGS_INPUT_6xx) {
+ error_report("only 6xx bus is supported on this machine");
+ exit(1);
+ }
+
+ if (env->flags & POWERPC_FLAG_RTC_CLK) {
+ /* POWER / PowerPC 601 RTC clock frequency is 7.8125 MHz */
+ cpu_ppc_tb_init(env, 7812500UL);
+ } else {
+ /* Set time-base frequency to 100 Mhz */
+ cpu_ppc_tb_init(env, 100UL * 1000UL * 1000UL);
+ }
+ qemu_register_reset(ppc_prep_reset, cpu);
+
+ /* PCI host */
+ dev = qdev_create(NULL, "raven-pcihost");
+ if (!bios_name) {
+ bios_name = BIOS_FILENAME;
+ }
+ qdev_prop_set_string(dev, "bios-name", bios_name);
+ qdev_prop_set_uint32(dev, "elf-machine", PPC_ELF_MACHINE);
+ pcihost = SYS_BUS_DEVICE(dev);
+ object_property_add_child(qdev_get_machine(), "raven", OBJECT(dev), NULL);
+ qdev_init_nofail(dev);
+ pci_bus = PCI_BUS(qdev_get_child_bus(dev, "pci.0"));
+ if (!pci_bus) {
+ error_report("could not create PCI host controller");
+ exit(1);
+ }
+
+ /* PCI -> ISA bridge */
+ dev = DEVICE(pci_create_simple(pci_bus, PCI_DEVFN(11, 0), "i82378"));
+ qdev_connect_gpio_out(dev, 0,
+ cpu->env.irq_inputs[PPC6xx_INPUT_INT]);
+ sysbus_connect_irq(pcihost, 0, qdev_get_gpio_in(dev, 15));
+ sysbus_connect_irq(pcihost, 1, qdev_get_gpio_in(dev, 13));
+ sysbus_connect_irq(pcihost, 2, qdev_get_gpio_in(dev, 15));
+ sysbus_connect_irq(pcihost, 3, qdev_get_gpio_in(dev, 13));
+ isa_bus = ISA_BUS(qdev_get_child_bus(dev, "isa.0"));
+
+ /* Memory controller */
+ dev = DEVICE(isa_create(isa_bus, "rs6000-mc"));
+ qdev_prop_set_uint32(dev, "ram-size", machine->ram_size);
+ qdev_init_nofail(dev);
+
+ /* initialize CMOS checksums */
+ cmos_checksum = 0x6aa9;
+ qbus_walk_children(BUS(isa_bus), prep_set_cmos_checksum, NULL, NULL, NULL,
+ &cmos_checksum);
+
+ /* initialize audio subsystem */
+ audio_init();
+
+ /* add some more devices */
+ if (defaults_enabled()) {
+ isa_create_simple(isa_bus, "i8042");
+ m48t59 = NVRAM(isa_create_simple(isa_bus, "isa-m48t59"));
+
+ dev = DEVICE(isa_create(isa_bus, "cs4231a"));
+ qdev_prop_set_uint32(dev, "iobase", 0x830);
+ qdev_prop_set_uint32(dev, "irq", 10);
+ qdev_init_nofail(dev);
+
+ dev = DEVICE(isa_create(isa_bus, "pc87312"));
+ qdev_prop_set_uint32(dev, "config", 12);
+ qdev_init_nofail(dev);
+
+ dev = DEVICE(isa_create(isa_bus, "prep-systemio"));
+ qdev_prop_set_uint32(dev, "ibm-planar-id", 0xfc);
+ qdev_prop_set_uint32(dev, "equipment", 0xc0);
+ qdev_init_nofail(dev);
+
+ pci_create_simple(pci_bus, PCI_DEVFN(1, 0), "lsi53c810");
+
+ /* XXX: s3-trio at PCI_DEVFN(2, 0) */
+ pci_vga_init(pci_bus);
+
+ for (i = 0; i < nb_nics; i++) {
+ pci_nic_init_nofail(&nd_table[i], pci_bus, "pcnet",
+ i == 0 ? "3" : NULL);
+ }
+ }
+
+ /* Prepare firmware configuration for OpenBIOS */
+ fw_cfg = fw_cfg_init_mem(CFG_ADDR, CFG_ADDR + 2);
+
+ if (machine->kernel_filename) {
+ /* load kernel */
+ kernel_base = KERNEL_LOAD_ADDR;
+ kernel_size = load_image_targphys(machine->kernel_filename,
+ kernel_base,
+ machine->ram_size - kernel_base);
+ if (kernel_size < 0) {
+ error_report("could not load kernel '%s'",
+ machine->kernel_filename);
+ exit(1);
+ }
+ fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, kernel_base);
+ fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size);
+ /* load initrd */
+ if (machine->initrd_filename) {
+ initrd_base = INITRD_LOAD_ADDR;
+ initrd_size = load_image_targphys(machine->initrd_filename,
+ initrd_base,
+ machine->ram_size - initrd_base);
+ if (initrd_size < 0) {
+ error_report("could not load initial ram disk '%s'",
+ machine->initrd_filename);
+ exit(1);
+ }
+ fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, initrd_base);
+ fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_SIZE, initrd_size);
+ }
+ if (machine->kernel_cmdline && *machine->kernel_cmdline) {
+ fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, CMDLINE_ADDR);
+ pstrcpy_targphys("cmdline", CMDLINE_ADDR, TARGET_PAGE_SIZE,
+ machine->kernel_cmdline);
+ fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA,
+ machine->kernel_cmdline);
+ fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE,
+ strlen(machine->kernel_cmdline) + 1);
+ }
+ boot_device = 'm';
+ } else {
+ boot_device = machine->boot_order[0];
+ }
+
+ fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus);
+ fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)machine->ram_size);
+ fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, ARCH_PREP);
+
+ fw_cfg_add_i16(fw_cfg, FW_CFG_PPC_WIDTH, graphic_width);
+ fw_cfg_add_i16(fw_cfg, FW_CFG_PPC_HEIGHT, graphic_height);
+ fw_cfg_add_i16(fw_cfg, FW_CFG_PPC_DEPTH, graphic_depth);
+
+ fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_IS_KVM, kvm_enabled());
+ if (kvm_enabled()) {
+#ifdef CONFIG_KVM
+ uint8_t *hypercall;
+
+ fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, kvmppc_get_tbfreq());
+ hypercall = g_malloc(16);
+ kvmppc_get_hypercall(env, hypercall, 16);
+ fw_cfg_add_bytes(fw_cfg, FW_CFG_PPC_KVM_HC, hypercall, 16);
+ fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_KVM_PID, getpid());
+#endif
+ } else {
+ fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, NANOSECONDS_PER_SECOND);
+ }
+ fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE, boot_device);
+ qemu_register_boot_set(fw_cfg_boot_set, fw_cfg);
+
+ /* Prepare firmware configuration for Open Hack'Ware */
+ if (m48t59) {
+ PPC_NVRAM_set_params(m48t59, NVRAM_SIZE, "PREP", ram_size,
+ boot_device,
+ kernel_base, kernel_size,
+ machine->kernel_cmdline,
+ initrd_base, initrd_size,
+ /* XXX: need an option to load a NVRAM image */
+ 0,
+ graphic_width, graphic_height, graphic_depth);
+ }
+}
+
+static void ibm_40p_machine_init(MachineClass *mc)
+{
+ mc->desc = "IBM RS/6000 7020 (40p)",
+ mc->init = ibm_40p_init;
+ mc->max_cpus = 1;
+ mc->pci_allow_0_address = true;
+ mc->default_ram_size = 128 * M_BYTE;
+ mc->block_default_type = IF_SCSI;
+ mc->default_boot_order = "c";
+}
+
+DEFINE_MACHINE("40p", ibm_40p_machine_init)
DEFINE_MACHINE("prep", prep_machine_init)
diff --git a/hw/ppc/prep_systemio.c b/hw/ppc/prep_systemio.c
new file mode 100644
index 0000000..50893ec
--- /dev/null
+++ b/hw/ppc/prep_systemio.c
@@ -0,0 +1,303 @@
+/*
+ * QEMU PReP System I/O emulation
+ *
+ * Copyright (c) 2017 Hervé Poussineau
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/isa/isa.h"
+#include "exec/address-spaces.h"
+#include "qemu/error-report.h" /* for error_report() */
+#include "sysemu/sysemu.h" /* for vm_stop() */
+#include "cpu.h"
+#include "trace.h"
+
+#define TYPE_PREP_SYSTEMIO "prep-systemio"
+#define PREP_SYSTEMIO(obj) \
+ OBJECT_CHECK(PrepSystemIoState, (obj), TYPE_PREP_SYSTEMIO)
+
+/* Bit as defined in PowerPC Reference Plaform v1.1, sect. 6.1.5, p. 132 */
+#define PREP_BIT(n) (1 << (7 - (n)))
+
+typedef struct PrepSystemIoState {
+ ISADevice parent_obj;
+ MemoryRegion ppc_parity_mem;
+
+ qemu_irq non_contiguous_io_map_irq;
+ uint8_t sreset; /* 0x0092 */
+ uint8_t equipment; /* 0x080c */
+ uint8_t system_control; /* 0x081c */
+ uint8_t iomap_type; /* 0x0850 */
+ uint8_t ibm_planar_id; /* 0x0852 */
+ qemu_irq softreset_irq;
+ PortioList portio;
+} PrepSystemIoState;
+
+/* PORT 0092 -- Special Port 92 (Read/Write) */
+
+enum {
+ PORT0092_SOFTRESET = PREP_BIT(7),
+ PORT0092_LE_MODE = PREP_BIT(6),
+};
+
+static void prep_port0092_write(void *opaque, uint32_t addr, uint32_t val)
+{
+ PrepSystemIoState *s = opaque;
+
+ trace_prep_systemio_write(addr, val);
+
+ s->sreset = val & PORT0092_SOFTRESET;
+ qemu_set_irq(s->softreset_irq, s->sreset);
+
+ if ((val & PORT0092_LE_MODE) != 0) {
+ /* XXX Not supported yet */
+ error_report("little-endian mode not supported");
+ vm_stop(RUN_STATE_PAUSED);
+ } else {
+ /* Nothing to do */
+ }
+}
+
+static uint32_t prep_port0092_read(void *opaque, uint32_t addr)
+{
+ PrepSystemIoState *s = opaque;
+ trace_prep_systemio_read(addr, s->sreset);
+ return s->sreset;
+}
+
+/* PORT 0808 -- Hardfile Light Register (Write Only) */
+
+enum {
+ PORT0808_HARDFILE_LIGHT_ON = PREP_BIT(7),
+};
+
+static void prep_port0808_write(void *opaque, uint32_t addr, uint32_t val)
+{
+ trace_prep_systemio_write(addr, val);
+}
+
+/* PORT 0810 -- Password Protect 1 Register (Write Only) */
+
+/* reset by port 0x4D in the SIO */
+static void prep_port0810_write(void *opaque, uint32_t addr, uint32_t val)
+{
+ trace_prep_systemio_write(addr, val);
+}
+
+/* PORT 0812 -- Password Protect 2 Register (Write Only) */
+
+/* reset by port 0x4D in the SIO */
+static void prep_port0812_write(void *opaque, uint32_t addr, uint32_t val)
+{
+ trace_prep_systemio_write(addr, val);
+}
+
+/* PORT 0814 -- L2 Invalidate Register (Write Only) */
+
+static void prep_port0814_write(void *opaque, uint32_t addr, uint32_t val)
+{
+ trace_prep_systemio_write(addr, val);
+}
+
+/* PORT 0818 -- Reserved for Keylock (Read Only) */
+
+enum {
+ PORT0818_KEYLOCK_SIGNAL_HIGH = PREP_BIT(7),
+};
+
+static uint32_t prep_port0818_read(void *opaque, uint32_t addr)
+{
+ uint32_t val = 0;
+ trace_prep_systemio_read(addr, val);
+ return val;
+}
+
+/* PORT 080C -- Equipment */
+
+enum {
+ PORT080C_SCSIFUSE = PREP_BIT(1),
+ PORT080C_L2_COPYBACK = PREP_BIT(4),
+ PORT080C_L2_256 = PREP_BIT(5),
+ PORT080C_UPGRADE_CPU = PREP_BIT(6),
+ PORT080C_L2 = PREP_BIT(7),
+};
+
+static uint32_t prep_port080c_read(void *opaque, uint32_t addr)
+{
+ PrepSystemIoState *s = opaque;
+ trace_prep_systemio_read(addr, s->equipment);
+ return s->equipment;
+}
+
+/* PORT 081C -- System Control Register (Read/Write) */
+
+enum {
+ PORT081C_FLOPPY_MOTOR_INHIBIT = PREP_BIT(3),
+ PORT081C_MASK_TEA = PREP_BIT(2),
+ PORT081C_L2_UPDATE_INHIBIT = PREP_BIT(1),
+ PORT081C_L2_CACHEMISS_INHIBIT = PREP_BIT(0),
+};
+
+static void prep_port081c_write(void *opaque, uint32_t addr, uint32_t val)
+{
+ static const uint8_t mask = PORT081C_FLOPPY_MOTOR_INHIBIT |
+ PORT081C_MASK_TEA |
+ PORT081C_L2_UPDATE_INHIBIT |
+ PORT081C_L2_CACHEMISS_INHIBIT;
+ PrepSystemIoState *s = opaque;
+ trace_prep_systemio_write(addr, val);
+ s->system_control = val & mask;
+}
+
+static uint32_t prep_port081c_read(void *opaque, uint32_t addr)
+{
+ PrepSystemIoState *s = opaque;
+ trace_prep_systemio_read(addr, s->system_control);
+ return s->system_control;
+}
+
+/* System Board Identification */
+
+static uint32_t prep_port0852_read(void *opaque, uint32_t addr)
+{
+ PrepSystemIoState *s = opaque;
+ trace_prep_systemio_read(addr, s->ibm_planar_id);
+ return s->ibm_planar_id;
+}
+
+/* PORT 0850 -- I/O Map Type Register (Read/Write) */
+
+enum {
+ PORT0850_IOMAP_NONCONTIGUOUS = PREP_BIT(7),
+};
+
+static uint32_t prep_port0850_read(void *opaque, uint32_t addr)
+{
+ PrepSystemIoState *s = opaque;
+ trace_prep_systemio_read(addr, s->iomap_type);
+ return s->iomap_type;
+}
+
+static void prep_port0850_write(void *opaque, uint32_t addr, uint32_t val)
+{
+ PrepSystemIoState *s = opaque;
+
+ trace_prep_systemio_write(addr, val);
+ qemu_set_irq(s->non_contiguous_io_map_irq,
+ val & PORT0850_IOMAP_NONCONTIGUOUS);
+ s->iomap_type = val & PORT0850_IOMAP_NONCONTIGUOUS;
+}
+
+static const MemoryRegionPortio ppc_io800_port_list[] = {
+ { 0x092, 1, 1, .read = prep_port0092_read,
+ .write = prep_port0092_write, },
+ { 0x808, 1, 1, .write = prep_port0808_write, },
+ { 0x80c, 1, 1, .read = prep_port080c_read, },
+ { 0x810, 1, 1, .write = prep_port0810_write, },
+ { 0x812, 1, 1, .write = prep_port0812_write, },
+ { 0x814, 1, 1, .write = prep_port0814_write, },
+ { 0x818, 1, 1, .read = prep_port0818_read },
+ { 0x81c, 1, 1, .read = prep_port081c_read,
+ .write = prep_port081c_write, },
+ { 0x850, 1, 1, .read = prep_port0850_read,
+ .write = prep_port0850_write, },
+ { 0x852, 1, 1, .read = prep_port0852_read, },
+ PORTIO_END_OF_LIST()
+};
+
+static uint64_t ppc_parity_error_readl(void *opaque, hwaddr addr,
+ unsigned int size)
+{
+ uint32_t val = 0;
+ trace_prep_systemio_read((unsigned int)addr, val);
+ return val;
+}
+
+static const MemoryRegionOps ppc_parity_error_ops = {
+ .read = ppc_parity_error_readl,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ },
+};
+
+static void prep_systemio_realize(DeviceState *dev, Error **errp)
+{
+ ISADevice *isa = ISA_DEVICE(dev);
+ PrepSystemIoState *s = PREP_SYSTEMIO(dev);
+ PowerPCCPU *cpu;
+
+ qdev_init_gpio_out(dev, &s->non_contiguous_io_map_irq, 1);
+ s->iomap_type = PORT0850_IOMAP_NONCONTIGUOUS;
+ qemu_set_irq(s->non_contiguous_io_map_irq,
+ s->iomap_type & PORT0850_IOMAP_NONCONTIGUOUS);
+ cpu = POWERPC_CPU(first_cpu);
+ s->softreset_irq = cpu->env.irq_inputs[PPC6xx_INPUT_HRESET];
+
+ isa_register_portio_list(isa, &s->portio, 0x0, ppc_io800_port_list, s,
+ "systemio800");
+
+ memory_region_init_io(&s->ppc_parity_mem, OBJECT(dev),
+ &ppc_parity_error_ops, s, "ppc-parity", 0x4);
+ memory_region_add_subregion(get_system_memory(), 0xbfffeff0,
+ &s->ppc_parity_mem);
+}
+
+static const VMStateDescription vmstate_prep_systemio = {
+ .name = "prep_systemio",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT8(sreset, PrepSystemIoState),
+ VMSTATE_UINT8(system_control, PrepSystemIoState),
+ VMSTATE_UINT8(iomap_type, PrepSystemIoState),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
+static Property prep_systemio_properties[] = {
+ DEFINE_PROP_UINT8("ibm-planar-id", PrepSystemIoState, ibm_planar_id, 0),
+ DEFINE_PROP_UINT8("equipment", PrepSystemIoState, equipment, 0),
+ DEFINE_PROP_END_OF_LIST()
+};
+
+static void prep_systemio_class_initfn(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->realize = prep_systemio_realize;
+ dc->vmsd = &vmstate_prep_systemio;
+ dc->props = prep_systemio_properties;
+}
+
+static TypeInfo prep_systemio800_info = {
+ .name = TYPE_PREP_SYSTEMIO,
+ .parent = TYPE_ISA_DEVICE,
+ .instance_size = sizeof(PrepSystemIoState),
+ .class_init = prep_systemio_class_initfn,
+};
+
+static void prep_systemio_register_types(void)
+{
+ type_register_static(&prep_systemio800_info);
+}
+
+type_init(prep_systemio_register_types)
diff --git a/hw/ppc/rs6000_mc.c b/hw/ppc/rs6000_mc.c
new file mode 100644
index 0000000..b613565
--- /dev/null
+++ b/hw/ppc/rs6000_mc.c
@@ -0,0 +1,232 @@
+/*
+ * QEMU RS/6000 memory controller
+ *
+ * Copyright (c) 2017 Hervé Poussineau
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) version 3 or any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/isa/isa.h"
+#include "exec/address-spaces.h"
+#include "hw/boards.h"
+#include "qapi/error.h"
+#include "trace.h"
+
+#define TYPE_RS6000MC "rs6000-mc"
+#define RS6000MC_DEVICE(obj) \
+ OBJECT_CHECK(RS6000MCState, (obj), TYPE_RS6000MC)
+
+typedef struct RS6000MCState {
+ ISADevice parent_obj;
+ /* see US patent 5,684,979 for details (expired 2001-11-04) */
+ uint32_t ram_size;
+ bool autoconfigure;
+ MemoryRegion simm[6];
+ unsigned int simm_size[6];
+ uint32_t end_address[8];
+ uint8_t port0820_index;
+ PortioList portio;
+} RS6000MCState;
+
+/* P0RT 0803 -- SIMM ID Register (32/8 MB) (Read Only) */
+
+static uint32_t rs6000mc_port0803_read(void *opaque, uint32_t addr)
+{
+ RS6000MCState *s = opaque;
+ uint32_t val = 0;
+ int socket;
+
+ /* (1 << socket) indicates 32 MB SIMM at given socket */
+ for (socket = 0; socket < 6; socket++) {
+ if (s->simm_size[socket] == 32) {
+ val |= (1 << socket);
+ }
+ }
+
+ trace_rs6000mc_id_read(addr, val);
+ return val;
+}
+
+/* PORT 0804 -- SIMM Presence Register (Read Only) */
+
+static uint32_t rs6000mc_port0804_read(void *opaque, uint32_t addr)
+{
+ RS6000MCState *s = opaque;
+ uint32_t val = 0xff;
+ int socket;
+
+ /* (1 << socket) indicates SIMM absence at given socket */
+ for (socket = 0; socket < 6; socket++) {
+ if (s->simm_size[socket]) {
+ val &= ~(1 << socket);
+ }
+ }
+ s->port0820_index = 0;
+
+ trace_rs6000mc_presence_read(addr, val);
+ return val;
+}
+
+/* Memory Controller Size Programming Register */
+
+static uint32_t rs6000mc_port0820_read(void *opaque, uint32_t addr)
+{
+ RS6000MCState *s = opaque;
+ uint32_t val = s->end_address[s->port0820_index] & 0x1f;
+ s->port0820_index = (s->port0820_index + 1) & 7;
+ trace_rs6000mc_size_read(addr, val);
+ return val;
+}
+
+static void rs6000mc_port0820_write(void *opaque, uint32_t addr, uint32_t val)
+{
+ RS6000MCState *s = opaque;
+ uint8_t socket = val >> 5;
+ uint32_t end_address = val & 0x1f;
+
+ trace_rs6000mc_size_write(addr, val);
+ s->end_address[socket] = end_address;
+ if (socket > 0 && socket < 7) {
+ if (s->simm_size[socket - 1]) {
+ uint32_t size;
+ uint32_t start_address = 0;
+ if (socket > 1) {
+ start_address = s->end_address[socket - 1];
+ }
+
+ size = end_address - start_address;
+ memory_region_set_enabled(&s->simm[socket - 1], size != 0);
+ memory_region_set_address(&s->simm[socket - 1],
+ start_address * 8 * 1024 * 1024);
+ }
+ }
+}
+
+/* Read Memory Parity Error */
+
+enum {
+ PORT0841_NO_ERROR_DETECTED = 0x01,
+};
+
+static uint32_t rs6000mc_port0841_read(void *opaque, uint32_t addr)
+{
+ uint32_t val = PORT0841_NO_ERROR_DETECTED;
+ trace_rs6000mc_parity_read(addr, val);
+ return val;
+}
+
+static const MemoryRegionPortio rs6000mc_port_list[] = {
+ { 0x803, 1, 1, .read = rs6000mc_port0803_read },
+ { 0x804, 1, 1, .read = rs6000mc_port0804_read },
+ { 0x820, 1, 1, .read = rs6000mc_port0820_read,
+ .write = rs6000mc_port0820_write, },
+ { 0x841, 1, 1, .read = rs6000mc_port0841_read },
+ PORTIO_END_OF_LIST()
+};
+
+static void rs6000mc_realize(DeviceState *dev, Error **errp)
+{
+ RS6000MCState *s = RS6000MC_DEVICE(dev);
+ int socket = 0;
+ unsigned int ram_size = s->ram_size / (1024 * 1024);
+
+ while (socket < 6) {
+ if (ram_size >= 64) {
+ s->simm_size[socket] = 32;
+ s->simm_size[socket + 1] = 32;
+ ram_size -= 64;
+ } else if (ram_size >= 16) {
+ s->simm_size[socket] = 8;
+ s->simm_size[socket + 1] = 8;
+ ram_size -= 16;
+ } else {
+ /* Not enough memory */
+ break;
+ }
+ socket += 2;
+ }
+
+ for (socket = 0; socket < 6; socket++) {
+ if (s->simm_size[socket]) {
+ char name[] = "simm.?";
+ name[5] = socket + '0';
+ memory_region_allocate_system_memory(&s->simm[socket], OBJECT(dev),
+ name, s->simm_size[socket]
+ * 1024 * 1024);
+ memory_region_add_subregion_overlap(get_system_memory(), 0,
+ &s->simm[socket], socket);
+ }
+ }
+ if (ram_size) {
+ /* unable to push all requested RAM in SIMMs */
+ error_setg(errp, "RAM size incompatible with this board. "
+ "Try again with something else, like %d MB",
+ s->ram_size / 1024 / 1024 - ram_size);
+ return;
+ }
+
+ if (s->autoconfigure) {
+ uint32_t start_address = 0;
+ for (socket = 0; socket < 6; socket++) {
+ if (s->simm_size[socket]) {
+ memory_region_set_enabled(&s->simm[socket], true);
+ memory_region_set_address(&s->simm[socket], start_address);
+ start_address += memory_region_size(&s->simm[socket]);
+ }
+ }
+ }
+
+ isa_register_portio_list(ISA_DEVICE(dev), &s->portio, 0x0,
+ rs6000mc_port_list, s, "rs6000mc");
+}
+
+static const VMStateDescription vmstate_rs6000mc = {
+ .name = "rs6000-mc",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT8(port0820_index, RS6000MCState),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
+static Property rs6000mc_properties[] = {
+ DEFINE_PROP_UINT32("ram-size", RS6000MCState, ram_size, 0),
+ DEFINE_PROP_BOOL("auto-configure", RS6000MCState, autoconfigure, true),
+ DEFINE_PROP_END_OF_LIST()
+};
+
+static void rs6000mc_class_initfn(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->realize = rs6000mc_realize;
+ dc->vmsd = &vmstate_rs6000mc;
+ dc->props = rs6000mc_properties;
+}
+
+static const TypeInfo rs6000mc_info = {
+ .name = TYPE_RS6000MC,
+ .parent = TYPE_ISA_DEVICE,
+ .instance_size = sizeof(RS6000MCState),
+ .class_init = rs6000mc_class_initfn,
+};
+
+static void rs6000mc_types(void)
+{
+ type_register_static(&rs6000mc_info);
+}
+
+type_init(rs6000mc_types)
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index a642e66..e465d7a 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -148,8 +148,8 @@ static int spapr_fixup_cpu_smt_dt(void *fdt, int offset, PowerPCCPU *cpu,
uint32_t gservers_prop[smt_threads * 2];
int index = ppc_get_vcpu_dt_id(cpu);
- if (cpu->cpu_version) {
- ret = fdt_setprop_cell(fdt, offset, "cpu-version", cpu->cpu_version);
+ if (cpu->compat_pvr) {
+ ret = fdt_setprop_cell(fdt, offset, "cpu-version", cpu->compat_pvr);
if (ret < 0) {
return ret;
}
@@ -206,6 +206,7 @@ static int spapr_fixup_cpu_dt(void *fdt, sPAPRMachineState *spapr)
PowerPCCPU *cpu = POWERPC_CPU(cs);
DeviceClass *dc = DEVICE_GET_CLASS(cs);
int index = ppc_get_vcpu_dt_id(cpu);
+ int compat_smt = MIN(smp_threads, ppc_compat_max_threads(cpu));
if ((index % smt) != 0) {
continue;
@@ -240,8 +241,7 @@ static int spapr_fixup_cpu_dt(void *fdt, sPAPRMachineState *spapr)
return ret;
}
- ret = spapr_fixup_cpu_smt_dt(fdt, offset, cpu,
- ppc_get_compat_smt_threads(cpu));
+ ret = spapr_fixup_cpu_smt_dt(fdt, offset, cpu, compat_smt);
if (ret < 0) {
return ret;
}
@@ -407,6 +407,7 @@ static void spapr_populate_cpu_dt(CPUState *cs, void *fdt, int offset,
size_t page_sizes_prop_size;
uint32_t vcpus_per_socket = smp_threads * smp_cores;
uint32_t pft_size_prop[] = {0, cpu_to_be32(spapr->htab_shift)};
+ int compat_smt = MIN(smp_threads, ppc_compat_max_threads(cpu));
sPAPRDRConnector *drc;
sPAPRDRConnectorClass *drck;
int drc_index;
@@ -494,8 +495,7 @@ static void spapr_populate_cpu_dt(CPUState *cs, void *fdt, int offset,
_FDT(spapr_fixup_cpu_numa_dt(fdt, offset, cs));
- _FDT(spapr_fixup_cpu_smt_dt(fdt, offset, cpu,
- ppc_get_compat_smt_threads(cpu)));
+ _FDT(spapr_fixup_cpu_smt_dt(fdt, offset, cpu, compat_smt));
}
static void spapr_populate_cpus_dt_node(void *fdt, sPAPRMachineState *spapr)
@@ -685,7 +685,6 @@ out:
int spapr_h_cas_compose_response(sPAPRMachineState *spapr,
target_ulong addr, target_ulong size,
- bool cpu_update,
sPAPROptionVector *ov5_updates)
{
void *fdt, *fdt_skel;
@@ -704,9 +703,7 @@ int spapr_h_cas_compose_response(sPAPRMachineState *spapr,
g_free(fdt_skel);
/* Fixup cpu nodes */
- if (cpu_update) {
- _FDT((spapr_fixup_cpu_dt(fdt, spapr)));
- }
+ _FDT((spapr_fixup_cpu_dt(fdt, spapr)));
if (spapr_dt_cas_updates(spapr, fdt, ov5_updates)) {
return -1;
@@ -1008,7 +1005,8 @@ static uint64_t translate_kernel_address(void *opaque, uint64_t addr)
return (addr & 0x0fffffff) + KERNEL_LOAD_ADDR;
}
-static void emulate_spapr_hypercall(PowerPCCPU *cpu)
+static void emulate_spapr_hypercall(PPCVirtualHypervisor *vhyp,
+ PowerPCCPU *cpu)
{
CPUPPCState *env = &cpu->env;
@@ -1753,11 +1751,80 @@ static void spapr_validate_node_memory(MachineState *machine, Error **errp)
}
}
+static void spapr_init_cpus(sPAPRMachineState *spapr)
+{
+ MachineState *machine = MACHINE(spapr);
+ MachineClass *mc = MACHINE_GET_CLASS(machine);
+ char *type = spapr_get_cpu_core_type(machine->cpu_model);
+ int smt = kvmppc_smt_threads();
+ int spapr_max_cores, spapr_cores;
+ int i;
+
+ if (!type) {
+ error_report("Unable to find sPAPR CPU Core definition");
+ exit(1);
+ }
+
+ if (mc->query_hotpluggable_cpus) {
+ if (smp_cpus % smp_threads) {
+ error_report("smp_cpus (%u) must be multiple of threads (%u)",
+ smp_cpus, smp_threads);
+ exit(1);
+ }
+ if (max_cpus % smp_threads) {
+ error_report("max_cpus (%u) must be multiple of threads (%u)",
+ max_cpus, smp_threads);
+ exit(1);
+ }
+
+ spapr_max_cores = max_cpus / smp_threads;
+ spapr_cores = smp_cpus / smp_threads;
+ } else {
+ if (max_cpus != smp_cpus) {
+ error_report("This machine version does not support CPU hotplug");
+ exit(1);
+ }
+
+ spapr_max_cores = QEMU_ALIGN_UP(smp_cpus, smp_threads) / smp_threads;
+ spapr_cores = spapr_max_cores;
+ }
+
+ spapr->cores = g_new0(Object *, spapr_max_cores);
+ for (i = 0; i < spapr_max_cores; i++) {
+ int core_id = i * smp_threads;
+
+ if (mc->query_hotpluggable_cpus) {
+ sPAPRDRConnector *drc =
+ spapr_dr_connector_new(OBJECT(spapr),
+ SPAPR_DR_CONNECTOR_TYPE_CPU,
+ (core_id / smp_threads) * smt);
+
+ qemu_register_reset(spapr_drc_reset, drc);
+ }
+
+ if (i < spapr_cores) {
+ Object *core = object_new(type);
+ int nr_threads = smp_threads;
+
+ /* Handle the partially filled core for older machine types */
+ if ((i + 1) * smp_threads >= smp_cpus) {
+ nr_threads = smp_cpus - i * smp_threads;
+ }
+
+ object_property_set_int(core, nr_threads, "nr-threads",
+ &error_fatal);
+ object_property_set_int(core, core_id, CPU_CORE_PROP_CORE_ID,
+ &error_fatal);
+ object_property_set_bool(core, true, "realized", &error_fatal);
+ }
+ }
+ g_free(type);
+}
+
/* pSeries LPAR / sPAPR hardware init */
static void ppc_spapr_init(MachineState *machine)
{
sPAPRMachineState *spapr = SPAPR_MACHINE(machine);
- MachineClass *mc = MACHINE_GET_CLASS(machine);
sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine);
const char *kernel_filename = machine->kernel_filename;
const char *initrd_filename = machine->initrd_filename;
@@ -1772,28 +1839,11 @@ static void ppc_spapr_init(MachineState *machine)
long load_limit, fw_size;
char *filename;
int smt = kvmppc_smt_threads();
- int spapr_cores = smp_cpus / smp_threads;
- int spapr_max_cores = max_cpus / smp_threads;
-
- if (mc->query_hotpluggable_cpus) {
- if (smp_cpus % smp_threads) {
- error_report("smp_cpus (%u) must be multiple of threads (%u)",
- smp_cpus, smp_threads);
- exit(1);
- }
- if (max_cpus % smp_threads) {
- error_report("max_cpus (%u) must be multiple of threads (%u)",
- max_cpus, smp_threads);
- exit(1);
- }
- }
msi_nonbroken = true;
QLIST_INIT(&spapr->phbs);
- cpu_ppc_hypercall = emulate_spapr_hypercall;
-
/* Allocate RMA if necessary */
rma_alloc_size = kvmppc_alloc_rma(&rma);
@@ -1866,44 +1916,7 @@ static void ppc_spapr_init(MachineState *machine)
ppc_cpu_parse_features(machine->cpu_model);
- if (mc->query_hotpluggable_cpus) {
- char *type = spapr_get_cpu_core_type(machine->cpu_model);
-
- if (type == NULL) {
- error_report("Unable to find sPAPR CPU Core definition");
- exit(1);
- }
-
- spapr->cores = g_new0(Object *, spapr_max_cores);
- for (i = 0; i < spapr_max_cores; i++) {
- int core_id = i * smp_threads;
- sPAPRDRConnector *drc =
- spapr_dr_connector_new(OBJECT(spapr),
- SPAPR_DR_CONNECTOR_TYPE_CPU,
- (core_id / smp_threads) * smt);
-
- qemu_register_reset(spapr_drc_reset, drc);
-
- if (i < spapr_cores) {
- Object *core = object_new(type);
- object_property_set_int(core, smp_threads, "nr-threads",
- &error_fatal);
- object_property_set_int(core, core_id, CPU_CORE_PROP_CORE_ID,
- &error_fatal);
- object_property_set_bool(core, true, "realized", &error_fatal);
- }
- }
- g_free(type);
- } else {
- for (i = 0; i < smp_cpus; i++) {
- PowerPCCPU *cpu = cpu_ppc_init(machine->cpu_model);
- if (cpu == NULL) {
- error_report("Unable to find PowerPC CPU definition");
- exit(1);
- }
- spapr_cpu_init(spapr, cpu, &error_fatal);
- }
- }
+ spapr_init_cpus(spapr);
if (kvm_enabled()) {
/* Enable H_LOGICAL_CI_* so SLOF can talk to in-kernel devices */
@@ -2116,6 +2129,12 @@ static void ppc_spapr_init(MachineState *machine)
qemu_register_reset(spapr_ccs_reset_hook, spapr);
qemu_register_boot_set(spapr_boot_set, spapr);
+
+ /* to stop and start vmclock */
+ if (kvm_enabled()) {
+ qemu_add_vm_change_state_handler(cpu_ppc_clock_vm_state_change,
+ &spapr->tb);
+ }
}
static int spapr_kvm_type(const char *vm_type)
@@ -2185,6 +2204,19 @@ static char *spapr_get_fw_dev_path(FWPathProvider *p, BusState *bus,
}
}
+ /*
+ * SLOF probes the USB devices, and if it recognizes that the device is a
+ * storage device, it changes its name to "storage" instead of "usb-host",
+ * and additionally adds a child node for the SCSI LUN, so the correct
+ * boot path in SLOF is something like .../storage@1/disk@xxx" instead.
+ */
+ if (strcmp("usb-host", qdev_fw_name(dev)) == 0) {
+ USBDevice *usbdev = CAST(USBDevice, dev, TYPE_USB_DEVICE);
+ if (usb_host_dev_is_scsi_storage(usbdev)) {
+ return g_strdup_printf("storage@%s/disk", usbdev->port->path);
+ }
+ }
+
if (phb) {
/* Replace "pci" with "pci@800000020000000" */
return g_strdup_printf("pci@%"PRIX64, phb->buid);
@@ -2252,7 +2284,7 @@ static void spapr_machine_finalizefn(Object *obj)
g_free(spapr->kvm_type);
}
-static void ppc_cpu_do_nmi_on_cpu(CPUState *cs, run_on_cpu_data arg)
+void spapr_do_system_reset_on_cpu(CPUState *cs, run_on_cpu_data arg)
{
cpu_synchronize_state(cs);
ppc_cpu_do_system_reset(cs);
@@ -2263,7 +2295,7 @@ static void spapr_nmi(NMIState *n, int cpu_index, Error **errp)
CPUState *cs;
CPU_FOREACH(cs) {
- async_run_on_cpu(cs, ppc_cpu_do_nmi_on_cpu, RUN_ON_CPU_NULL);
+ async_run_on_cpu(cs, spapr_do_system_reset_on_cpu, RUN_ON_CPU_NULL);
}
}
@@ -2630,8 +2662,8 @@ static void spapr_phb_placement(sPAPRMachineState *spapr, uint32_t index,
* 1TiB 64-bit MMIO windows for each PHB.
*/
const uint64_t base_buid = 0x800000020000000ULL;
- const int max_phbs =
- (SPAPR_PCI_LIMIT - SPAPR_PCI_BASE) / SPAPR_PCI_MEM64_WIN_SIZE - 1;
+#define SPAPR_MAX_PHBS ((SPAPR_PCI_LIMIT - SPAPR_PCI_BASE) / \
+ SPAPR_PCI_MEM64_WIN_SIZE - 1)
int i;
/* Sanity check natural alignments */
@@ -2640,12 +2672,14 @@ static void spapr_phb_placement(sPAPRMachineState *spapr, uint32_t index,
QEMU_BUILD_BUG_ON((SPAPR_PCI_MEM64_WIN_SIZE % SPAPR_PCI_MEM32_WIN_SIZE) != 0);
QEMU_BUILD_BUG_ON((SPAPR_PCI_MEM32_WIN_SIZE % SPAPR_PCI_IO_WIN_SIZE) != 0);
/* Sanity check bounds */
- QEMU_BUILD_BUG_ON((max_phbs * SPAPR_PCI_IO_WIN_SIZE) > SPAPR_PCI_MEM32_WIN_SIZE);
- QEMU_BUILD_BUG_ON((max_phbs * SPAPR_PCI_MEM32_WIN_SIZE) > SPAPR_PCI_MEM64_WIN_SIZE);
-
- if (index >= max_phbs) {
- error_setg(errp, "\"index\" for PAPR PHB is too large (max %u)",
- max_phbs - 1);
+ QEMU_BUILD_BUG_ON((SPAPR_MAX_PHBS * SPAPR_PCI_IO_WIN_SIZE) >
+ SPAPR_PCI_MEM32_WIN_SIZE);
+ QEMU_BUILD_BUG_ON((SPAPR_MAX_PHBS * SPAPR_PCI_MEM32_WIN_SIZE) >
+ SPAPR_PCI_MEM64_WIN_SIZE);
+
+ if (index >= SPAPR_MAX_PHBS) {
+ error_setg(errp, "\"index\" for PAPR PHB is too large (max %llu)",
+ SPAPR_MAX_PHBS - 1);
return;
}
@@ -2666,6 +2700,7 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data)
FWPathProviderClass *fwc = FW_PATH_PROVIDER_CLASS(oc);
NMIClass *nc = NMI_CLASS(oc);
HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc);
+ PPCVirtualHypervisorClass *vhc = PPC_VIRTUAL_HYPERVISOR_CLASS(oc);
mc->desc = "pSeries Logical Partition (PAPR compliant)";
@@ -2697,6 +2732,7 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data)
fwc->get_dev_path = spapr_get_fw_dev_path;
nc->nmi_monitor_handler = spapr_nmi;
smc->phb_placement = spapr_phb_placement;
+ vhc->hypercall = emulate_spapr_hypercall;
}
static const TypeInfo spapr_machine_info = {
@@ -2712,6 +2748,7 @@ static const TypeInfo spapr_machine_info = {
{ TYPE_FW_PATH_PROVIDER },
{ TYPE_NMI },
{ TYPE_HOTPLUG_HANDLER },
+ { TYPE_PPC_VIRTUAL_HYPERVISOR },
{ }
},
};
@@ -2745,18 +2782,37 @@ static const TypeInfo spapr_machine_info = {
type_init(spapr_machine_register_##suffix)
/*
+ * pseries-2.9
+ */
+static void spapr_machine_2_9_instance_options(MachineState *machine)
+{
+}
+
+static void spapr_machine_2_9_class_options(MachineClass *mc)
+{
+ /* Defaults for the latest behaviour inherited from the base class */
+}
+
+DEFINE_SPAPR_MACHINE(2_9, "2.9", true);
+
+/*
* pseries-2.8
*/
+#define SPAPR_COMPAT_2_8 \
+ HW_COMPAT_2_8
+
static void spapr_machine_2_8_instance_options(MachineState *machine)
{
+ spapr_machine_2_9_instance_options(machine);
}
static void spapr_machine_2_8_class_options(MachineClass *mc)
{
- /* Defaults for the latest behaviour inherited from the base class */
+ spapr_machine_2_9_class_options(mc);
+ SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_2_8);
}
-DEFINE_SPAPR_MACHINE(2_8, "2.8", true);
+DEFINE_SPAPR_MACHINE(2_8, "2.8", false);
/*
* pseries-2.7
diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c
index c18632b..9dddaeb 100644
--- a/hw/ppc/spapr_cpu_core.c
+++ b/hw/ppc/spapr_cpu_core.c
@@ -46,7 +46,8 @@ static void spapr_cpu_destroy(PowerPCCPU *cpu)
qemu_unregister_reset(spapr_cpu_reset, cpu);
}
-void spapr_cpu_init(sPAPRMachineState *spapr, PowerPCCPU *cpu, Error **errp)
+static void spapr_cpu_init(sPAPRMachineState *spapr, PowerPCCPU *cpu,
+ Error **errp)
{
CPUPPCState *env = &cpu->env;
CPUState *cs = CPU(cpu);
@@ -56,6 +57,7 @@ void spapr_cpu_init(sPAPRMachineState *spapr, PowerPCCPU *cpu, Error **errp)
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);
if (cpu->max_compat) {
@@ -166,11 +168,11 @@ void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
Error **errp)
{
sPAPRMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
+ MachineClass *mc = MACHINE_GET_CLASS(spapr);
sPAPRCPUCore *core = SPAPR_CPU_CORE(OBJECT(dev));
CPUCore *cc = CPU_CORE(dev);
CPUState *cs = CPU(core->threads);
sPAPRDRConnector *drc;
- sPAPRDRConnectorClass *drck;
Error *local_err = NULL;
void *fdt = NULL;
int fdt_offset = 0;
@@ -180,7 +182,7 @@ void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
drc = spapr_dr_connector_by_id(SPAPR_DR_CONNECTOR_TYPE_CPU, index * smt);
spapr->cores[index] = OBJECT(dev);
- g_assert(drc);
+ g_assert(drc || !mc->query_hotpluggable_cpus);
/*
* Setup CPU DT entries only for hotplugged CPUs. For boot time or
@@ -190,13 +192,15 @@ void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
fdt = spapr_populate_hotplug_cpu_dt(cs, &fdt_offset, spapr);
}
- drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
- drck->attach(drc, dev, fdt, fdt_offset, !dev->hotplugged, &local_err);
- if (local_err) {
- g_free(fdt);
- spapr->cores[index] = NULL;
- error_propagate(errp, local_err);
- return;
+ if (drc) {
+ sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
+ drck->attach(drc, dev, fdt, fdt_offset, !dev->hotplugged, &local_err);
+ if (local_err) {
+ g_free(fdt);
+ spapr->cores[index] = NULL;
+ error_propagate(errp, local_err);
+ return;
+ }
}
if (dev->hotplugged) {
@@ -209,8 +213,11 @@ void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
/*
* Set the right DRC states for cold plugged CPU.
*/
- drck->set_allocation_state(drc, SPAPR_DR_ALLOCATION_STATE_USABLE);
- drck->set_isolation_state(drc, SPAPR_DR_ISOLATION_STATE_UNISOLATED);
+ if (drc) {
+ sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
+ drck->set_allocation_state(drc, SPAPR_DR_ALLOCATION_STATE_USABLE);
+ drck->set_isolation_state(drc, SPAPR_DR_ISOLATION_STATE_UNISOLATED);
+ }
}
}
@@ -227,7 +234,7 @@ void spapr_core_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
char *base_core_type = spapr_get_cpu_core_type(machine->cpu_model);
const char *type = object_get_typename(OBJECT(dev));
- if (!mc->query_hotpluggable_cpus) {
+ if (dev->hotplugged && !mc->query_hotpluggable_cpus) {
error_setg(&local_err, "CPU hotplug not supported for this machine");
goto out;
}
@@ -237,11 +244,6 @@ void spapr_core_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
goto out;
}
- if (cc->nr_threads != smp_threads) {
- error_setg(&local_err, "threads must be %d", smp_threads);
- goto out;
- }
-
if (cc->core_id % smp_threads) {
error_setg(&local_err, "invalid core id %d", cc->core_id);
goto out;
diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
index b2a8e48..42d20e0 100644
--- a/hw/ppc/spapr_hcall.c
+++ b/hw/ppc/spapr_hcall.c
@@ -881,128 +881,105 @@ static target_ulong h_set_mode(PowerPCCPU *cpu, sPAPRMachineState *spapr,
return ret;
}
-typedef struct {
- uint32_t cpu_version;
- Error *err;
-} SetCompatState;
+#define H_SIGNAL_SYS_RESET_ALL -1
+#define H_SIGNAL_SYS_RESET_ALLBUTSELF -2
-static void do_set_compat(CPUState *cs, run_on_cpu_data arg)
+static target_ulong h_signal_sys_reset(PowerPCCPU *cpu,
+ sPAPRMachineState *spapr,
+ target_ulong opcode, target_ulong *args)
{
- PowerPCCPU *cpu = POWERPC_CPU(cs);
- SetCompatState *s = arg.host_ptr;
+ target_long target = args[0];
+ CPUState *cs;
- cpu_synchronize_state(cs);
- ppc_set_compat(cpu, s->cpu_version, &s->err);
-}
+ if (target < 0) {
+ /* Broadcast */
+ if (target < H_SIGNAL_SYS_RESET_ALLBUTSELF) {
+ return H_PARAMETER;
+ }
-#define get_compat_level(cpuver) ( \
- ((cpuver) == CPU_POWERPC_LOGICAL_2_05) ? 2050 : \
- ((cpuver) == CPU_POWERPC_LOGICAL_2_06) ? 2060 : \
- ((cpuver) == CPU_POWERPC_LOGICAL_2_06_PLUS) ? 2061 : \
- ((cpuver) == CPU_POWERPC_LOGICAL_2_07) ? 2070 : 0)
+ CPU_FOREACH(cs) {
+ PowerPCCPU *c = POWERPC_CPU(cs);
-static void cas_handle_compat_cpu(PowerPCCPUClass *pcc, uint32_t pvr,
- unsigned max_lvl, unsigned *compat_lvl,
- unsigned *cpu_version)
-{
- unsigned lvl = get_compat_level(pvr);
- bool is205, is206, is207;
-
- if (!lvl) {
- return;
- }
-
- /* If it is a logical PVR, try to determine the highest level */
- is205 = (pcc->pcr_supported & PCR_COMPAT_2_05) &&
- (lvl == get_compat_level(CPU_POWERPC_LOGICAL_2_05));
- is206 = (pcc->pcr_supported & PCR_COMPAT_2_06) &&
- ((lvl == get_compat_level(CPU_POWERPC_LOGICAL_2_06)) ||
- (lvl == get_compat_level(CPU_POWERPC_LOGICAL_2_06_PLUS)));
- is207 = (pcc->pcr_supported & PCR_COMPAT_2_07) &&
- (lvl == get_compat_level(CPU_POWERPC_LOGICAL_2_07));
-
- if (is205 || is206 || is207) {
- if (!max_lvl) {
- /* User did not set the level, choose the highest */
- if (*compat_lvl <= lvl) {
- *compat_lvl = lvl;
- *cpu_version = pvr;
+ if (target == H_SIGNAL_SYS_RESET_ALLBUTSELF) {
+ if (c == cpu) {
+ continue;
+ }
}
- } else if (max_lvl >= lvl) {
- /* User chose the level, don't set higher than this */
- *compat_lvl = lvl;
- *cpu_version = pvr;
+ run_on_cpu(cs, spapr_do_system_reset_on_cpu, RUN_ON_CPU_NULL);
}
+ return H_SUCCESS;
+
+ } else {
+ /* Unicast */
+ CPU_FOREACH(cs) {
+ if (cpu->cpu_dt_id == target) {
+ run_on_cpu(cs, spapr_do_system_reset_on_cpu, RUN_ON_CPU_NULL);
+ return H_SUCCESS;
+ }
+ }
+ return H_PARAMETER;
}
}
-static target_ulong h_client_architecture_support(PowerPCCPU *cpu_,
+static target_ulong h_client_architecture_support(PowerPCCPU *cpu,
sPAPRMachineState *spapr,
target_ulong opcode,
target_ulong *args)
{
target_ulong list = ppc64_phys_to_real(args[0]);
target_ulong ov_table;
- PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu_);
- CPUState *cs;
- bool cpu_match = false, cpu_update = true;
- unsigned old_cpu_version = cpu_->cpu_version;
- unsigned compat_lvl = 0, cpu_version = 0;
- unsigned max_lvl = get_compat_level(cpu_->max_compat);
- int counter;
+ bool explicit_match = false; /* Matched the CPU's real PVR */
+ uint32_t max_compat = cpu->max_compat;
+ uint32_t best_compat = 0;
+ int i;
sPAPROptionVector *ov5_guest, *ov5_cas_old, *ov5_updates;
- /* Parse PVR list */
- for (counter = 0; counter < 512; ++counter) {
+ /*
+ * We scan the supplied table of PVRs looking for two things
+ * 1. Is our real CPU PVR in the list?
+ * 2. What's the "best" listed logical PVR
+ */
+ for (i = 0; i < 512; ++i) {
uint32_t pvr, pvr_mask;
pvr_mask = ldl_be_phys(&address_space_memory, list);
- list += 4;
- pvr = ldl_be_phys(&address_space_memory, list);
- list += 4;
-
- trace_spapr_cas_pvr_try(pvr);
- if (!max_lvl &&
- ((cpu_->env.spr[SPR_PVR] & pvr_mask) == (pvr & pvr_mask))) {
- cpu_match = true;
- cpu_version = 0;
- } else if (pvr == cpu_->cpu_version) {
- cpu_match = true;
- cpu_version = cpu_->cpu_version;
- } else if (!cpu_match) {
- cas_handle_compat_cpu(pcc, pvr, max_lvl, &compat_lvl, &cpu_version);
- }
- /* Terminator record */
+ pvr = ldl_be_phys(&address_space_memory, list + 4);
+ list += 8;
+
if (~pvr_mask & pvr) {
- break;
+ break; /* Terminator record */
+ }
+
+ if ((cpu->env.spr[SPR_PVR] & pvr_mask) == (pvr & pvr_mask)) {
+ explicit_match = true;
+ } else {
+ if (ppc_check_compat(cpu, pvr, best_compat, max_compat)) {
+ best_compat = pvr;
+ }
}
}
+ if ((best_compat == 0) && (!explicit_match || max_compat)) {
+ /* We couldn't find a suitable compatibility mode, and either
+ * the guest doesn't support "raw" mode for this CPU, or raw
+ * mode is disabled because a maximum compat mode is set */
+ return H_HARDWARE;
+ }
+
/* Parsing finished */
- trace_spapr_cas_pvr(cpu_->cpu_version, cpu_match,
- cpu_version, pcc->pcr_mask);
+ trace_spapr_cas_pvr(cpu->compat_pvr, explicit_match, best_compat);
/* Update CPUs */
- if (old_cpu_version != cpu_version) {
- CPU_FOREACH(cs) {
- SetCompatState s = {
- .cpu_version = cpu_version,
- .err = NULL,
- };
+ if (cpu->compat_pvr != best_compat) {
+ Error *local_err = NULL;
- run_on_cpu(cs, do_set_compat, RUN_ON_CPU_HOST_PTR(&s));
-
- if (s.err) {
- error_report_err(s.err);
- return H_HARDWARE;
- }
+ ppc_set_compat_all(best_compat, &local_err);
+ if (local_err) {
+ error_report_err(local_err);
+ return H_HARDWARE;
}
}
- if (!cpu_version) {
- cpu_update = false;
- }
-
/* For the future use: here @ov_table points to the first option vector */
ov_table = list;
@@ -1028,7 +1005,7 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu_,
if (!spapr->cas_reboot) {
spapr->cas_reboot =
- (spapr_h_cas_compose_response(spapr, args[1], args[2], cpu_update,
+ (spapr_h_cas_compose_response(spapr, args[1], args[2],
ov5_updates) != 0);
}
spapr_ovec_cleanup(ov5_updates);
@@ -1101,6 +1078,7 @@ static void hypercall_register_types(void)
/* hcall-splpar */
spapr_register_hypercall(H_REGISTER_VPA, h_register_vpa);
spapr_register_hypercall(H_CEDE, h_cede);
+ spapr_register_hypercall(H_SIGNAL_SYS_RESET, h_signal_sys_reset);
/* processor register resource access h-calls */
spapr_register_hypercall(H_SET_SPRG0, h_set_sprg0);
diff --git a/hw/ppc/spapr_vio.c b/hw/ppc/spapr_vio.c
index cc1e09c..8bfc5f9 100644
--- a/hw/ppc/spapr_vio.c
+++ b/hw/ppc/spapr_vio.c
@@ -538,21 +538,11 @@ VIOsPAPRBus *spapr_vio_bus_init(void)
return bus;
}
-/* Represents sPAPR hcall VIO devices */
-
-static int spapr_vio_bridge_init(SysBusDevice *dev)
-{
- /* nothing */
- return 0;
-}
-
static void spapr_vio_bridge_class_init(ObjectClass *klass, void *data)
{
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
dc->fw_name = "vdevice";
- k->init = spapr_vio_bridge_init;
}
static const TypeInfo spapr_vio_bridge_info = {
diff --git a/hw/ppc/trace-events b/hw/ppc/trace-events
index 2297ead..f46995c 100644
--- a/hw/ppc/trace-events
+++ b/hw/ppc/trace-events
@@ -15,7 +15,7 @@ spapr_cas_continue(unsigned long n) "Copy changes to the guest: %ld bytes"
# hw/ppc/spapr_hcall.c
spapr_cas_pvr_try(uint32_t pvr) "%x"
-spapr_cas_pvr(uint32_t cur_pvr, bool cpu_match, uint32_t new_pvr, uint64_t pcr) "current=%x, cpu_match=%u, new=%x, compat flags=%"PRIx64
+spapr_cas_pvr(uint32_t cur_pvr, bool explicit_match, uint32_t new_pvr) "current=%x, explicit_match=%u, new=%x"
# hw/ppc/spapr_iommu.c
spapr_iommu_put(uint64_t liobn, uint64_t ioba, uint64_t tce, uint64_t ret) "liobn=%"PRIx64" ioba=0x%"PRIx64" tce=0x%"PRIx64" ret=%"PRId64
@@ -74,3 +74,14 @@ ppc_tb_adjust(uint64_t offs1, uint64_t offs2, int64_t diff, int64_t seconds) "ad
# hw/ppc/prep.c
prep_io_800_writeb(uint32_t addr, uint32_t val) "0x%08" PRIx32 " => 0x%02" PRIx32
prep_io_800_readb(uint32_t addr, uint32_t retval) "0x%08" PRIx32 " <= 0x%02" PRIx32
+
+# hw/ppc/prep_systemio.c
+prep_systemio_read(uint32_t addr, uint32_t val) "read addr=%x val=%x"
+prep_systemio_write(uint32_t addr, uint32_t val) "write addr=%x val=%x"
+
+# hw/ppc/rs6000_mc.c
+rs6000mc_id_read(uint32_t addr, uint32_t val) "read addr=%x val=%x"
+rs6000mc_presence_read(uint32_t addr, uint32_t val) "read addr=%x val=%x"
+rs6000mc_size_read(uint32_t addr, uint32_t val) "read addr=%x val=%x"
+rs6000mc_size_write(uint32_t addr, uint32_t val) "write addr=%x val=%x"
+rs6000mc_parity_read(uint32_t addr, uint32_t val) "read addr=%x val=%x"
diff --git a/hw/ppc/virtex_ml507.c b/hw/ppc/virtex_ml507.c
index b97d966..fdbcf22 100644
--- a/hw/ppc/virtex_ml507.c
+++ b/hw/ppc/virtex_ml507.c
@@ -221,6 +221,13 @@ static void virtex_init(MachineState *machine)
cpu = ppc440_init_xilinx(&ram_size, 1, machine->cpu_model, 400000000);
env = &cpu->env;
+
+ if (env->mmu_model != POWERPC_MMU_BOOKE) {
+ fprintf(stderr, "MMU model %i not supported by this machine.\n",
+ env->mmu_model);
+ exit(1);
+ }
+
qemu_register_reset(main_cpu_reset, cpu);
memory_region_allocate_system_memory(phys_ram, NULL, "ram", ram_size);
diff --git a/hw/s390x/s390-pci-bus.h b/hw/s390x/s390-pci-bus.h
index 0aad9cc..dcbf482 100644
--- a/hw/s390x/s390-pci-bus.h
+++ b/hw/s390x/s390-pci-bus.h
@@ -279,7 +279,7 @@ typedef struct S390PCIIOMMUTable {
S390PCIIOMMU *iommu[PCI_SLOT_MAX];
} S390PCIIOMMUTable;
-typedef struct S390PCIBusDevice {
+struct S390PCIBusDevice {
DeviceState qdev;
PCIDevice *pdev;
ZpciState state;
@@ -301,7 +301,7 @@ typedef struct S390PCIBusDevice {
IndAddr *indicator;
QEMUTimer *release_timer;
QTAILQ_ENTRY(S390PCIBusDevice) link;
-} S390PCIBusDevice;
+};
typedef struct S390PCIBus {
BusState qbus;
diff --git a/hw/s390x/s390-virtio.c b/hw/s390x/s390-virtio.c
index 0a96347..7a3a7fe 100644
--- a/hw/s390x/s390-virtio.c
+++ b/hw/s390x/s390-virtio.c
@@ -204,8 +204,8 @@ void s390_machine_reset(void)
{
S390CPU *ipl_cpu = S390_CPU(qemu_get_cpu(0));
- qemu_devices_reset();
s390_cmma_reset();
+ qemu_devices_reset();
s390_crypto_reset();
/* all cpus are stopped - configure and start the ipl cpu only */
diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c
index 6aad7c9..1a8b04c 100644
--- a/hw/scsi/megasas.c
+++ b/hw/scsi/megasas.c
@@ -2367,9 +2367,11 @@ static void megasas_scsi_realize(PCIDevice *dev, Error **errp)
if (megasas_use_msix(s) &&
msix_init(dev, 15, &s->mmio_io, b->mmio_bar, 0x2000,
- &s->mmio_io, b->mmio_bar, 0x3800, 0x68)) {
+ &s->mmio_io, b->mmio_bar, 0x3800, 0x68, NULL)) {
+ /* TODO: check msix_init's error, and should fail on msix=on */
s->msix = ON_OFF_AUTO_OFF;
}
+
if (pci_is_express(dev)) {
pcie_endpoint_cap_init(dev, 0xa0);
}
diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
index e0b5169..f810678 100644
--- a/hw/usb/hcd-xhci.c
+++ b/hw/usb/hcd-xhci.c
@@ -3627,25 +3627,6 @@ static void usb_xhci_realize(struct PCIDevice *dev, Error **errp)
dev->config[PCI_CACHE_LINE_SIZE] = 0x10;
dev->config[0x60] = 0x30; /* release number */
- usb_xhci_init(xhci);
-
- if (xhci->msi != ON_OFF_AUTO_OFF) {
- ret = msi_init(dev, 0x70, xhci->numintrs, true, false, &err);
- /* Any error other than -ENOTSUP(board's MSI support is broken)
- * is a programming error */
- assert(!ret || ret == -ENOTSUP);
- if (ret && xhci->msi == ON_OFF_AUTO_ON) {
- /* Can't satisfy user's explicit msi=on request, fail */
- error_append_hint(&err, "You have to use msi=auto (default) or "
- "msi=off with this machine type.\n");
- error_propagate(errp, err);
- return;
- }
- assert(!err || xhci->msi == ON_OFF_AUTO_AUTO);
- /* With msi=auto, we fall back to MSI off silently */
- error_free(err);
- }
-
if (xhci->numintrs > MAXINTRS) {
xhci->numintrs = MAXINTRS;
}
@@ -3667,6 +3648,24 @@ static void usb_xhci_realize(struct PCIDevice *dev, Error **errp)
xhci->max_pstreams_mask = 0;
}
+ if (xhci->msi != ON_OFF_AUTO_OFF) {
+ ret = msi_init(dev, 0x70, xhci->numintrs, true, false, &err);
+ /* Any error other than -ENOTSUP(board's MSI support is broken)
+ * is a programming error */
+ assert(!ret || ret == -ENOTSUP);
+ if (ret && xhci->msi == ON_OFF_AUTO_ON) {
+ /* Can't satisfy user's explicit msi=on request, fail */
+ error_append_hint(&err, "You have to use msi=auto (default) or "
+ "msi=off with this machine type.\n");
+ error_propagate(errp, err);
+ return;
+ }
+ assert(!err || xhci->msi == ON_OFF_AUTO_AUTO);
+ /* With msi=auto, we fall back to MSI off silently */
+ error_free(err);
+ }
+
+ usb_xhci_init(xhci);
xhci->mfwrap_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, xhci_mfwrap_timer, xhci);
memory_region_init(&xhci->mem, OBJECT(xhci), "xhci", LEN_REGS);
@@ -3704,11 +3703,11 @@ static void usb_xhci_realize(struct PCIDevice *dev, Error **errp)
}
if (xhci->msix != ON_OFF_AUTO_OFF) {
- /* TODO check for errors */
+ /* TODO check for errors, and should fail when msix=on */
msix_init(dev, xhci->numintrs,
&xhci->mem, 0, OFF_MSIX_TABLE,
&xhci->mem, 0, OFF_MSIX_PBA,
- 0x90);
+ 0x90, NULL);
}
}
diff --git a/hw/usb/host-libusb.c b/hw/usb/host-libusb.c
index bd81d71..7791c6d 100644
--- a/hw/usb/host-libusb.c
+++ b/hw/usb/host-libusb.c
@@ -1707,6 +1707,35 @@ static void usb_host_auto_check(void *unused)
timer_mod(usb_auto_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 2000);
}
+/**
+ * Check whether USB host device has a USB mass storage SCSI interface
+ */
+bool usb_host_dev_is_scsi_storage(USBDevice *ud)
+{
+ USBHostDevice *uhd = USB_HOST_DEVICE(ud);
+ struct libusb_config_descriptor *conf;
+ const struct libusb_interface_descriptor *intf;
+ bool is_scsi_storage = false;
+ int i;
+
+ if (!uhd || libusb_get_active_config_descriptor(uhd->dev, &conf) != 0) {
+ return false;
+ }
+
+ for (i = 0; i < conf->bNumInterfaces; i++) {
+ intf = &conf->interface[i].altsetting[ud->altsetting[i]];
+ if (intf->bInterfaceClass == LIBUSB_CLASS_MASS_STORAGE &&
+ intf->bInterfaceSubClass == 6) { /* 6 means SCSI */
+ is_scsi_storage = true;
+ break;
+ }
+ }
+
+ libusb_free_config_descriptor(conf);
+
+ return is_scsi_storage;
+}
+
void hmp_info_usbhost(Monitor *mon, const QDict *qdict)
{
libusb_device **devs = NULL;
diff --git a/hw/usb/host-stub.c b/hw/usb/host-stub.c
index 6ba65a1..d0268ba 100644
--- a/hw/usb/host-stub.c
+++ b/hw/usb/host-stub.c
@@ -46,3 +46,8 @@ USBDevice *usb_host_device_open(USBBus *bus, const char *devname)
{
return NULL;
}
+
+bool usb_host_dev_is_scsi_storage(USBDevice *ud)
+{
+ return false;
+}
diff --git a/hw/usb/trace-events b/hw/usb/trace-events
index 2d42fd4..fdd1d29 100644
--- a/hw/usb/trace-events
+++ b/hw/usb/trace-events
@@ -60,7 +60,6 @@ usb_ohci_mem_read_bad_offset(uint32_t addr) "%x"
usb_ohci_mem_write_unaligned(uint32_t addr) "at %x"
usb_ohci_mem_write_bad_offset(uint32_t addr) "%x"
usb_ohci_process_lists(uint32_t head, uint32_t cur) "head %x, cur %x"
-usb_ohci_bus_eof_timer_failed(const char *name) "%s: timer_new_ns failed"
usb_ohci_set_frame_interval(const char *name, uint16_t fi_x, uint16_t fi_u) "%s: FrameInterval = 0x%x (%u)"
usb_ohci_hub_power_up(void) "powered up all ports"
usb_ohci_hub_power_down(void) "powered down all ports"
diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
index 882d3a9..332f41d 100644
--- a/hw/vfio/pci.c
+++ b/hw/vfio/pci.c
@@ -1432,6 +1432,7 @@ static void vfio_msix_early_setup(VFIOPCIDevice *vdev, Error **errp)
static int vfio_msix_setup(VFIOPCIDevice *vdev, int pos, Error **errp)
{
int ret;
+ Error *err = NULL;
vdev->msix->pending = g_malloc0(BITS_TO_LONGS(vdev->msix->entries) *
sizeof(unsigned long));
@@ -1439,12 +1440,15 @@ static int vfio_msix_setup(VFIOPCIDevice *vdev, int pos, Error **errp)
vdev->bars[vdev->msix->table_bar].region.mem,
vdev->msix->table_bar, vdev->msix->table_offset,
vdev->bars[vdev->msix->pba_bar].region.mem,
- vdev->msix->pba_bar, vdev->msix->pba_offset, pos);
+ vdev->msix->pba_bar, vdev->msix->pba_offset, pos,
+ &err);
if (ret < 0) {
if (ret == -ENOTSUP) {
+ error_report_err(err);
return 0;
}
- error_setg(errp, "msix_init failed");
+
+ error_propagate(errp, err);
return ret;
}
diff --git a/hw/vfio/trace-events b/hw/vfio/trace-events
index ef81609..8de8281 100644
--- a/hw/vfio/trace-events
+++ b/hw/vfio/trace-events
@@ -46,7 +46,7 @@ vfio_pci_emulated_device_id(const char *name, uint16_t val) "%s %04x"
vfio_pci_emulated_sub_vendor_id(const char *name, uint16_t val) "%s %04x"
vfio_pci_emulated_sub_device_id(const char *name, uint16_t val) "%s %04x"
-# hw/vfio/pci-quirks.
+# hw/vfio/pci-quirks.c
vfio_quirk_rom_blacklisted(const char *name, uint16_t vid, uint16_t did) "%s %04x:%04x"
vfio_quirk_generic_window_address_write(const char *name, const char * region_name, uint64_t data) "%s %s 0x%"PRIx64
vfio_quirk_generic_window_data_read(const char *name, const char * region_name, uint64_t data) "%s %s 0x%"PRIx64
diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
index b124d97..febe519 100644
--- a/hw/virtio/vhost.c
+++ b/hw/virtio/vhost.c
@@ -612,7 +612,8 @@ static void vhost_set_memory(MemoryListener *listener,
static bool vhost_section(MemoryRegionSection *section)
{
- return memory_region_is_ram(section->mr);
+ return memory_region_is_ram(section->mr) &&
+ !memory_region_is_rom(section->mr);
}
static void vhost_begin(MemoryListener *listener)
diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
index b5af2a0..5ce42af 100644
--- a/hw/virtio/virtio-pci.c
+++ b/hw/virtio/virtio-pci.c
@@ -1686,9 +1686,9 @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp)
if (proxy->nvectors) {
int err = msix_init_exclusive_bar(&proxy->pci_dev, proxy->nvectors,
- proxy->msix_bar_idx);
+ proxy->msix_bar_idx, NULL);
if (err) {
- /* Notice when a system that supports MSIx can't initialize it. */
+ /* Notice when a system that supports MSIx can't initialize it */
if (err != -ENOTSUP) {
error_report("unable to init msix vectors to %" PRIu32,
proxy->nvectors);
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index f292a53..6365706 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -1383,7 +1383,7 @@ static void virtio_set_isr(VirtIODevice *vdev, int value)
}
}
-bool virtio_should_notify(VirtIODevice *vdev, VirtQueue *vq)
+static bool virtio_should_notify(VirtIODevice *vdev, VirtQueue *vq)
{
uint16_t old, new;
bool v;
diff --git a/hw/xen/trace-events b/hw/xen/trace-events
new file mode 100644
index 0000000..c4fb6f1
--- /dev/null
+++ b/hw/xen/trace-events
@@ -0,0 +1,13 @@
+# See docs/tracing.txt for syntax documentation.
+
+# include/hw/xen/xen_common.h
+xen_default_ioreq_server(void) ""
+xen_ioreq_server_create(uint32_t id) "id: %u"
+xen_ioreq_server_destroy(uint32_t id) "id: %u"
+xen_ioreq_server_state(uint32_t id, bool enable) "id: %u: enable: %i"
+xen_map_mmio_range(uint32_t id, uint64_t start_addr, uint64_t end_addr) "id: %u start: %#"PRIx64" end: %#"PRIx64
+xen_unmap_mmio_range(uint32_t id, uint64_t start_addr, uint64_t end_addr) "id: %u start: %#"PRIx64" end: %#"PRIx64
+xen_map_portio_range(uint32_t id, uint64_t start_addr, uint64_t end_addr) "id: %u start: %#"PRIx64" end: %#"PRIx64
+xen_unmap_portio_range(uint32_t id, uint64_t start_addr, uint64_t end_addr) "id: %u start: %#"PRIx64" end: %#"PRIx64
+xen_map_pcidev(uint32_t id, uint8_t bus, uint8_t dev, uint8_t func) "id: %u bdf: %02x.%02x.%02x"
+xen_unmap_pcidev(uint32_t id, uint8_t bus, uint8_t dev, uint8_t func) "id: %u bdf: %02x.%02x.%02x"