summaryrefslogtreecommitdiff
path: root/hw/pci-bridge
diff options
context:
space:
mode:
Diffstat (limited to 'hw/pci-bridge')
-rw-r--r--hw/pci-bridge/dec.h4
-rw-r--r--hw/pci-bridge/ioh3420.c23
-rw-r--r--hw/pci-bridge/pci_bridge_dev.c35
-rw-r--r--hw/pci-bridge/pci_expander_bridge.c56
-rw-r--r--hw/pci-bridge/xio3130_downstream.c21
-rw-r--r--hw/pci-bridge/xio3130_upstream.c19
-rw-r--r--hw/pci-bridge/xio3130_upstream.h2
7 files changed, 88 insertions, 72 deletions
diff --git a/hw/pci-bridge/dec.h b/hw/pci-bridge/dec.h
index 17dc0c2b0..ae17ca736 100644
--- a/hw/pci-bridge/dec.h
+++ b/hw/pci-bridge/dec.h
@@ -1,5 +1,5 @@
-#ifndef DEC_PCI_H
-#define DEC_PCI_H
+#ifndef HW_PCI_BRIDGE_DEC_H
+#define HW_PCI_BRIDGE_DEC_H
#include "qemu-common.h"
diff --git a/hw/pci-bridge/ioh3420.c b/hw/pci-bridge/ioh3420.c
index 0937fa34b..c8b5ac420 100644
--- a/hw/pci-bridge/ioh3420.c
+++ b/hw/pci-bridge/ioh3420.c
@@ -25,6 +25,7 @@
#include "hw/pci/msi.h"
#include "hw/pci/pcie.h"
#include "ioh3420.h"
+#include "qapi/error.h"
#define PCI_DEVICE_ID_IOH_EPORT 0x3420 /* D0:F0 express mode */
#define PCI_DEVICE_ID_IOH_REV 0x2
@@ -97,7 +98,9 @@ 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);
@@ -106,12 +109,16 @@ static int ioh3420_initfn(PCIDevice *d)
if (rc < 0) {
goto err_bridge;
}
+
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);
+ IOH_EP_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_MASKBIT, &err);
if (rc < 0) {
+ assert(rc == -ENOTSUP);
+ error_report_err(err);
goto err_bridge;
}
+
rc = pcie_cap_init(d, IOH_EP_EXP_OFFSET, PCI_EXP_TYPE_ROOT_PORT, p->port);
if (rc < 0) {
goto err_msi;
@@ -120,18 +127,21 @@ static int ioh3420_initfn(PCIDevice *d)
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;
}
- pcie_cap_root_init(d);
+
rc = pcie_aer_init(d, IOH_EP_AER_OFFSET, PCI_ERR_SIZEOF);
if (rc < 0) {
goto err;
}
pcie_aer_root_init(d);
ioh3420_aer_vector_update(d);
+
return 0;
err:
@@ -207,12 +217,3 @@ static void ioh3420_register_types(void)
}
type_init(ioh3420_register_types)
-
-/*
- * Local variables:
- * c-indent-level: 4
- * c-basic-offset: 4
- * tab-width: 8
- * indent-tab-mode: nil
- * End:
- */
diff --git a/hw/pci-bridge/pci_bridge_dev.c b/hw/pci-bridge/pci_bridge_dev.c
index 7b582e96a..5dbd933cc 100644
--- a/hw/pci-bridge/pci_bridge_dev.c
+++ b/hw/pci-bridge/pci_bridge_dev.c
@@ -42,9 +42,10 @@ struct PCIBridgeDev {
MemoryRegion bar;
uint8_t chassis_nr;
-#define PCI_BRIDGE_DEV_F_MSI_REQ 0
-#define PCI_BRIDGE_DEV_F_SHPC_REQ 1
+#define PCI_BRIDGE_DEV_F_SHPC_REQ 0
uint32_t flags;
+
+ OnOffAuto msi;
};
typedef struct PCIBridgeDev PCIBridgeDev;
@@ -53,6 +54,7 @@ static int pci_bridge_dev_initfn(PCIDevice *dev)
PCIBridge *br = PCI_BRIDGE(dev);
PCIBridgeDev *bridge_dev = PCI_BRIDGE_DEV(dev);
int err;
+ Error *local_err = NULL;
pci_bridge_initfn(dev, TYPE_PCI_BUS);
@@ -66,19 +68,33 @@ static int pci_bridge_dev_initfn(PCIDevice *dev)
}
} else {
/* MSI is not applicable without SHPC */
- bridge_dev->flags &= ~(1 << PCI_BRIDGE_DEV_F_MSI_REQ);
+ bridge_dev->msi = ON_OFF_AUTO_OFF;
}
+
err = slotid_cap_init(dev, 0, bridge_dev->chassis_nr, 0);
if (err) {
goto slotid_error;
}
- if ((bridge_dev->flags & (1 << PCI_BRIDGE_DEV_F_MSI_REQ)) &&
- msi_nonbroken) {
- err = msi_init(dev, 0, 1, true, true);
- if (err < 0) {
+
+ if (bridge_dev->msi != ON_OFF_AUTO_OFF) {
+ /* it means SHPC exists, because MSI is needed by SHPC */
+
+ err = msi_init(dev, 0, 1, true, true, &local_err);
+ /* Any error other than -ENOTSUP(board's MSI support is broken)
+ * is a programming error */
+ assert(!err || err == -ENOTSUP);
+ if (err && bridge_dev->msi == ON_OFF_AUTO_ON) {
+ /* Can't satisfy user's explicit msi=on request, fail */
+ error_append_hint(&local_err, "You have to use msi=auto (default) "
+ "or msi=off with this machine type.\n");
+ error_report_err(local_err);
goto msi_error;
}
+ assert(!local_err || bridge_dev->msi == ON_OFF_AUTO_AUTO);
+ /* With msi=auto, we fall back to MSI off silently */
+ error_free(local_err);
}
+
if (shpc_present(dev)) {
/* TODO: spec recommends using 64 bit prefetcheable BAR.
* Check whether that works well. */
@@ -86,6 +102,7 @@ static int pci_bridge_dev_initfn(PCIDevice *dev)
PCI_BASE_ADDRESS_MEM_TYPE_64, &bridge_dev->bar);
}
return 0;
+
msi_error:
slotid_cap_cleanup(dev);
slotid_error:
@@ -143,8 +160,8 @@ static Property pci_bridge_dev_properties[] = {
/* Note: 0 is not a legal chassis number. */
DEFINE_PROP_UINT8(PCI_BRIDGE_DEV_PROP_CHASSIS_NR, PCIBridgeDev, chassis_nr,
0),
- DEFINE_PROP_BIT(PCI_BRIDGE_DEV_PROP_MSI, PCIBridgeDev, flags,
- PCI_BRIDGE_DEV_F_MSI_REQ, true),
+ 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),
DEFINE_PROP_END_OF_LIST(),
diff --git a/hw/pci-bridge/pci_expander_bridge.c b/hw/pci-bridge/pci_expander_bridge.c
index ba320bd85..1cc598f7e 100644
--- a/hw/pci-bridge/pci_expander_bridge.c
+++ b/hw/pci-bridge/pci_expander_bridge.c
@@ -11,6 +11,7 @@
*/
#include "qemu/osdep.h"
+#include "qapi/error.h"
#include "hw/pci/pci.h"
#include "hw/pci/pci_bus.h"
#include "hw/pci/pci_host.h"
@@ -149,6 +150,8 @@ static void pxb_host_class_init(ObjectClass *class, void *data)
PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(class);
dc->fw_name = "pci";
+ /* Reason: Internal part of the pxb/pxb-pcie device, not usable by itself */
+ dc->cannot_instantiate_with_device_add_yet = true;
sbc->explicit_ofw_unit_address = pxb_host_ofw_unit_address;
hc->root_bus_path = pxb_host_root_bus_path;
}
@@ -160,30 +163,25 @@ static const TypeInfo pxb_host_info = {
};
/*
- * Registers the PXB bus as a child of the i440fx root bus.
- *
- * Returns 0 on successs, -1 if i440fx host was not
- * found or the bus number is already in use.
+ * Registers the PXB bus as a child of pci host root bus.
*/
-static int pxb_register_bus(PCIDevice *dev, PCIBus *pxb_bus)
+static void pxb_register_bus(PCIDevice *dev, PCIBus *pxb_bus, Error **errp)
{
PCIBus *bus = dev->bus;
int pxb_bus_num = pci_bus_num(pxb_bus);
if (bus->parent_dev) {
- error_report("PXB devices can be attached only to root bus.");
- return -1;
+ error_setg(errp, "PXB devices can be attached only to root bus");
+ return;
}
QLIST_FOREACH(bus, &bus->child, sibling) {
if (pci_bus_num(bus) == pxb_bus_num) {
- error_report("Bus %d is already in use.", pxb_bus_num);
- return -1;
+ error_setg(errp, "Bus %d is already in use", pxb_bus_num);
+ return;
}
}
QLIST_INSERT_HEAD(&dev->bus->child, pxb_bus, sibling);
-
- return 0;
}
static int pxb_map_irq_fn(PCIDevice *pci_dev, int pin)
@@ -213,17 +211,18 @@ static gint pxb_compare(gconstpointer a, gconstpointer b)
0;
}
-static int pxb_dev_init_common(PCIDevice *dev, bool pcie)
+static void pxb_dev_realize_common(PCIDevice *dev, bool pcie, Error **errp)
{
PXBDev *pxb = convert_to_pxb(dev);
DeviceState *ds, *bds = NULL;
PCIBus *bus;
const char *dev_name = NULL;
+ Error *local_err = NULL;
if (pxb->numa_node != NUMA_NODE_UNASSIGNED &&
pxb->numa_node >= nb_numa_nodes) {
- error_report("Illegal numa node %d.", pxb->numa_node);
- return -EINVAL;
+ error_setg(errp, "Illegal numa node %d", pxb->numa_node);
+ return;
}
if (dev->qdev.id && *dev->qdev.id) {
@@ -248,7 +247,9 @@ static int pxb_dev_init_common(PCIDevice *dev, bool pcie)
PCI_HOST_BRIDGE(ds)->bus = bus;
- if (pxb_register_bus(dev, bus)) {
+ pxb_register_bus(dev, bus, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
goto err_register_bus;
}
@@ -262,23 +263,22 @@ static int pxb_dev_init_common(PCIDevice *dev, bool pcie)
pci_config_set_class(dev->config, PCI_CLASS_BRIDGE_HOST);
pxb_dev_list = g_list_insert_sorted(pxb_dev_list, pxb, pxb_compare);
- return 0;
+ return;
err_register_bus:
object_unref(OBJECT(bds));
object_unparent(OBJECT(bus));
object_unref(OBJECT(ds));
- return -EINVAL;
}
-static int pxb_dev_initfn(PCIDevice *dev)
+static void pxb_dev_realize(PCIDevice *dev, Error **errp)
{
if (pci_bus_is_express(dev->bus)) {
- error_report("pxb devices cannot reside on a PCIe bus!");
- return -EINVAL;
+ error_setg(errp, "pxb devices cannot reside on a PCIe bus");
+ return;
}
- return pxb_dev_init_common(dev, false);
+ pxb_dev_realize_common(dev, false, errp);
}
static void pxb_dev_exitfn(PCIDevice *pci_dev)
@@ -300,7 +300,7 @@ static void pxb_dev_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
- k->init = pxb_dev_initfn;
+ k->realize = pxb_dev_realize;
k->exit = pxb_dev_exitfn;
k->vendor_id = PCI_VENDOR_ID_REDHAT;
k->device_id = PCI_DEVICE_ID_REDHAT_PXB;
@@ -308,6 +308,7 @@ static void pxb_dev_class_init(ObjectClass *klass, void *data)
dc->desc = "PCI Expander Bridge";
dc->props = pxb_dev_properties;
+ dc->hotpluggable = false;
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
}
@@ -318,14 +319,14 @@ static const TypeInfo pxb_dev_info = {
.class_init = pxb_dev_class_init,
};
-static int pxb_pcie_dev_initfn(PCIDevice *dev)
+static void pxb_pcie_dev_realize(PCIDevice *dev, Error **errp)
{
if (!pci_bus_is_express(dev->bus)) {
- error_report("pxb-pcie devices cannot reside on a PCI bus!");
- return -EINVAL;
+ error_setg(errp, "pxb-pcie devices cannot reside on a PCI bus");
+ return;
}
- return pxb_dev_init_common(dev, true);
+ pxb_dev_realize_common(dev, true, errp);
}
static void pxb_pcie_dev_class_init(ObjectClass *klass, void *data)
@@ -333,7 +334,7 @@ static void pxb_pcie_dev_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
- k->init = pxb_pcie_dev_initfn;
+ k->realize = pxb_pcie_dev_realize;
k->exit = pxb_dev_exitfn;
k->vendor_id = PCI_VENDOR_ID_REDHAT;
k->device_id = PCI_DEVICE_ID_REDHAT_PXB_PCIE;
@@ -341,6 +342,7 @@ static void pxb_pcie_dev_class_init(ObjectClass *klass, void *data)
dc->desc = "PCI Express Expander Bridge";
dc->props = pxb_dev_properties;
+ dc->hotpluggable = false;
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
}
diff --git a/hw/pci-bridge/xio3130_downstream.c b/hw/pci-bridge/xio3130_downstream.c
index cf1ee63ab..cef6e1325 100644
--- a/hw/pci-bridge/xio3130_downstream.c
+++ b/hw/pci-bridge/xio3130_downstream.c
@@ -24,6 +24,7 @@
#include "hw/pci/msi.h"
#include "hw/pci/pcie.h"
#include "xio3130_downstream.h"
+#include "qapi/error.h"
#define PCI_DEVICE_ID_TI_XIO3130D 0x8233 /* downstream port */
#define XIO3130_REVISION 0x1
@@ -60,21 +61,26 @@ static int xio3130_downstream_initfn(PCIDevice *d)
PCIEPort *p = PCIE_PORT(d);
PCIESlot *s = PCIE_SLOT(d);
int rc;
+ Error *err = NULL;
pci_bridge_initfn(d, TYPE_PCIE_BUS);
pcie_port_init_reg(d);
rc = msi_init(d, XIO3130_MSI_OFFSET, XIO3130_MSI_NR_VECTOR,
XIO3130_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_64BIT,
- XIO3130_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_MASKBIT);
+ XIO3130_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_MASKBIT, &err);
if (rc < 0) {
+ assert(rc == -ENOTSUP);
+ error_report_err(err);
goto err_bridge;
}
+
rc = pci_bridge_ssvid_init(d, XIO3130_SSVID_OFFSET,
XIO3130_SSVID_SVID, XIO3130_SSVID_SSID);
if (rc < 0) {
goto err_bridge;
}
+
rc = pcie_cap_init(d, XIO3130_EXP_OFFSET, PCI_EXP_TYPE_DOWNSTREAM,
p->port);
if (rc < 0) {
@@ -83,12 +89,14 @@ static int xio3130_downstream_initfn(PCIDevice *d)
pcie_cap_flr_init(d);
pcie_cap_deverr_init(d);
pcie_cap_slot_init(d, s->slot);
+ pcie_cap_arifwd_init(d);
+
pcie_chassis_create(s->chassis);
rc = pcie_chassis_add_slot(s);
if (rc < 0) {
goto err_pcie_cap;
}
- pcie_cap_arifwd_init(d);
+
rc = pcie_aer_init(d, XIO3130_AER_OFFSET, PCI_ERR_SIZEOF);
if (rc < 0) {
goto err;
@@ -195,12 +203,3 @@ static void xio3130_downstream_register_types(void)
}
type_init(xio3130_downstream_register_types)
-
-/*
- * Local variables:
- * c-indent-level: 4
- * c-basic-offset: 4
- * tab-width: 8
- * indent-tab-mode: nil
- * End:
- */
diff --git a/hw/pci-bridge/xio3130_upstream.c b/hw/pci-bridge/xio3130_upstream.c
index 164ef58c4..4ad0440aa 100644
--- a/hw/pci-bridge/xio3130_upstream.c
+++ b/hw/pci-bridge/xio3130_upstream.c
@@ -24,6 +24,7 @@
#include "hw/pci/msi.h"
#include "hw/pci/pcie.h"
#include "xio3130_upstream.h"
+#include "qapi/error.h"
#define PCI_DEVICE_ID_TI_XIO3130U 0x8232 /* upstream port */
#define XIO3130_REVISION 0x2
@@ -56,21 +57,26 @@ static int xio3130_upstream_initfn(PCIDevice *d)
{
PCIEPort *p = PCIE_PORT(d);
int rc;
+ Error *err = NULL;
pci_bridge_initfn(d, TYPE_PCIE_BUS);
pcie_port_init_reg(d);
rc = msi_init(d, XIO3130_MSI_OFFSET, XIO3130_MSI_NR_VECTOR,
XIO3130_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_64BIT,
- XIO3130_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_MASKBIT);
+ XIO3130_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_MASKBIT, &err);
if (rc < 0) {
+ assert(rc == -ENOTSUP);
+ error_report_err(err);
goto err_bridge;
}
+
rc = pci_bridge_ssvid_init(d, XIO3130_SSVID_OFFSET,
XIO3130_SSVID_SVID, XIO3130_SSVID_SSID);
if (rc < 0) {
goto err_bridge;
}
+
rc = pcie_cap_init(d, XIO3130_EXP_OFFSET, PCI_EXP_TYPE_UPSTREAM,
p->port);
if (rc < 0) {
@@ -78,6 +84,7 @@ static int xio3130_upstream_initfn(PCIDevice *d)
}
pcie_cap_flr_init(d);
pcie_cap_deverr_init(d);
+
rc = pcie_aer_init(d, XIO3130_AER_OFFSET, PCI_ERR_SIZEOF);
if (rc < 0) {
goto err;
@@ -167,13 +174,3 @@ static void xio3130_upstream_register_types(void)
}
type_init(xio3130_upstream_register_types)
-
-
-/*
- * Local variables:
- * c-indent-level: 4
- * c-basic-offset: 4
- * tab-width: 8
- * indent-tab-mode: nil
- * End:
- */
diff --git a/hw/pci-bridge/xio3130_upstream.h b/hw/pci-bridge/xio3130_upstream.h
index 08c1d5f75..d0ab7577e 100644
--- a/hw/pci-bridge/xio3130_upstream.h
+++ b/hw/pci-bridge/xio3130_upstream.h
@@ -7,4 +7,4 @@ PCIEPort *xio3130_upstream_init(PCIBus *bus, int devfn, bool multifunction,
const char *bus_name, pci_map_irq_fn map_irq,
uint8_t port);
-#endif /* QEMU_XIO3130_H */
+#endif /* QEMU_XIO3130_UPSTREAM_H */