#include "sysemu/hostmem.h"
#include "sysemu/numa.h"
#include "hw/ppc/spapr_numa.h"
+#include "qemu/log.h"
/* Copied from the kernel arch/powerpc/platforms/pseries/msi.c */
#define RTAS_QUERY_FN 0
return route;
}
+static uint64_t spapr_msi_read(void *opaque, hwaddr addr, unsigned size)
+{
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid access\n", __func__);
+ return 0;
+}
+
/*
* MSI/MSIX memory region implementation.
* The handler handles both MSI and MSIX.
static void spapr_msi_write(void *opaque, hwaddr addr,
uint64_t data, unsigned size)
{
- SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
+ SpaprMachineState *spapr = opaque;
uint32_t irq = data;
trace_spapr_pci_msi_write(addr, data, irq);
}
static const MemoryRegionOps spapr_msi_ops = {
- /* There is no .read as the read result is undefined by PCI spec */
- .read = NULL,
+ /*
+ * .read result is undefined by PCI spec.
+ * define .read method to avoid assert failure in memory_region_init_io
+ */
+ .read = spapr_msi_read,
.write = spapr_msi_write,
.endianness = DEVICE_LITTLE_ENDIAN
};
return offset;
}
+char *spapr_pci_fw_dev_name(PCIDevice *dev)
+{
+ const gchar *basename;
+ int slot = PCI_SLOT(dev->devfn);
+ int func = PCI_FUNC(dev->devfn);
+ uint32_t ccode = pci_default_read_config(dev, PCI_CLASS_PROG, 3);
+
+ basename = dt_name_from_class((ccode >> 16) & 0xff, (ccode >> 8) & 0xff,
+ ccode & 0xff);
+
+ if (func != 0) {
+ return g_strdup_printf("%s@%x,%x", basename, slot, func);
+ } else {
+ return g_strdup_printf("%s@%x", basename, slot);
+ }
+}
+
/* create OF node for pci device and required OF DT properties */
static int spapr_dt_pci_device(SpaprPhbState *sphb, PCIDevice *dev,
void *fdt, int parent_offset)
{
int offset;
- const gchar *basename;
- gchar *nodename;
- int slot = PCI_SLOT(dev->devfn);
- int func = PCI_FUNC(dev->devfn);
+ g_autofree gchar *nodename = spapr_pci_fw_dev_name(dev);
PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev);
ResourceProps rp;
SpaprDrc *drc = drc_from_dev(sphb, dev);
uint32_t pci_status = pci_default_read_config(dev, PCI_STATUS, 2);
gchar *loc_code;
- basename = dt_name_from_class((ccode >> 16) & 0xff, (ccode >> 8) & 0xff,
- ccode & 0xff);
-
- if (func != 0) {
- nodename = g_strdup_printf("%s@%x,%x", basename, slot, func);
- } else {
- nodename = g_strdup_printf("%s@%x", basename, slot);
- }
-
_FDT(offset = fdt_add_subnode(fdt, parent_offset, nodename));
- g_free(nodename);
-
/* in accordance with PAPR+ v2.7 13.6.3, Table 181 */
_FDT(fdt_setprop_cell(fdt, offset, "vendor-id", vendor_id));
_FDT(fdt_setprop_cell(fdt, offset, "device-id", device_id));
return true;
}
-static void spapr_pci_plug(HotplugHandler *plug_handler,
- DeviceState *plugged_dev, Error **errp)
+static void spapr_pci_pre_plug(HotplugHandler *plug_handler,
+ DeviceState *plugged_dev, Error **errp)
{
SpaprPhbState *phb = SPAPR_PCI_HOST_BRIDGE(DEVICE(plug_handler));
PCIDevice *pdev = PCI_DEVICE(plugged_dev);
PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(plugged_dev);
SpaprDrc *drc = drc_from_dev(phb, pdev);
- Error *local_err = NULL;
PCIBus *bus = PCI_BUS(qdev_get_parent_bus(DEVICE(pdev)));
uint32_t slotnr = PCI_SLOT(pdev->devfn);
- /* if DR is disabled we don't need to do anything in the case of
- * hotplug or coldplug callbacks
- */
if (!phb->dr_enabled) {
/* if this is a hotplug operation initiated by the user
* we need to let them know it's not enabled
if (plugged_dev->hotplugged) {
error_setg(errp, QERR_BUS_NO_HOTPLUG,
object_get_typename(OBJECT(phb)));
+ return;
}
- return;
}
- g_assert(drc);
-
if (pc->is_bridge) {
if (!bridge_has_valid_chassis_nr(OBJECT(plugged_dev), errp)) {
return;
}
- spapr_pci_bridge_plug(phb, PCI_BRIDGE(plugged_dev));
}
/* Following the QEMU convention used for PCIe multifunction
*/
if (plugged_dev->hotplugged && bus->devices[PCI_DEVFN(slotnr, 0)] &&
PCI_FUNC(pdev->devfn) != 0) {
- error_setg(errp, "PCI: slot %d function 0 already ocuppied by %s,"
+ error_setg(errp, "PCI: slot %d function 0 already occupied by %s,"
" additional functions can no longer be exposed to guest.",
slotnr, bus->devices[PCI_DEVFN(slotnr, 0)]->name);
+ }
+
+ if (drc && drc->dev) {
+ error_setg(errp, "PCI: slot %d already occupied by %s", slotnr,
+ pci_get_function_0(PCI_DEVICE(drc->dev))->name);
return;
}
+}
+
+static void spapr_pci_plug(HotplugHandler *plug_handler,
+ DeviceState *plugged_dev, Error **errp)
+{
+ SpaprPhbState *phb = SPAPR_PCI_HOST_BRIDGE(DEVICE(plug_handler));
+ PCIDevice *pdev = PCI_DEVICE(plugged_dev);
+ PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(plugged_dev);
+ SpaprDrc *drc = drc_from_dev(phb, pdev);
+ uint32_t slotnr = PCI_SLOT(pdev->devfn);
- spapr_drc_attach(drc, DEVICE(pdev), &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
+ /*
+ * If DR is disabled we don't need to do anything in the case of
+ * hotplug or coldplug callbacks.
+ */
+ if (!phb->dr_enabled) {
return;
}
+ g_assert(drc);
+
+ if (pc->is_bridge) {
+ spapr_pci_bridge_plug(phb, PCI_BRIDGE(plugged_dev));
+ }
+
+ /* spapr_pci_pre_plug() already checked the DRC is attachable */
+ spapr_drc_attach(drc, DEVICE(pdev));
+
/* If this is function 0, signal hotplug for all the device functions.
* Otherwise defer sending the hotplug event.
*/
return 0;
}
+static int spapr_pci_post_save(void *opaque)
+{
+ SpaprPhbState *sphb = opaque;
+
+ g_free(sphb->msi_devs);
+ sphb->msi_devs = NULL;
+ sphb->msi_devs_num = 0;
+ return 0;
+}
+
static int spapr_pci_post_load(void *opaque, int version_id)
{
SpaprPhbState *sphb = opaque;
.version_id = 2,
.minimum_version_id = 2,
.pre_save = spapr_pci_pre_save,
+ .post_save = spapr_pci_post_save,
.post_load = spapr_pci_post_load,
.fields = (VMStateField[]) {
VMSTATE_UINT64_EQUAL(buid, SpaprPhbState, NULL),
/* Supported by TYPE_SPAPR_MACHINE */
dc->user_creatable = true;
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
+ hp->pre_plug = spapr_pci_pre_plug;
hp->plug = spapr_pci_plug;
hp->unplug = spapr_pci_unplug;
hp->unplug_request = spapr_pci_unplug_request;
bool be = *(bool *)opaque;
if (object_dynamic_cast(OBJECT(dev), "VGA")
- || object_dynamic_cast(OBJECT(dev), "secondary-vga")) {
+ || object_dynamic_cast(OBJECT(dev), "secondary-vga")
+ || object_dynamic_cast(OBJECT(dev), "bochs-display")
+ || object_dynamic_cast(OBJECT(dev), "virtio-vga")) {
object_property_set_bool(OBJECT(dev), "big-endian-framebuffer", be,
&error_abort);
}
return 0;
}
-void spapr_pci_switch_vga(bool big_endian)
+void spapr_pci_switch_vga(SpaprMachineState *spapr, bool big_endian)
{
- SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
SpaprPhbState *sphb;
/*