From: Michael Roth <mdroth@linux.vnet.ibm.com>
To: qemu-devel@nongnu.org
Cc: aik@ozlabs.ru, agraf@suse.de, ncmike@ncultra.org,
qemu-ppc@nongnu.org, tyreld@linux.vnet.ibm.com,
nfont@linux.vnet.ibm.com
Subject: [Qemu-devel] [PATCH 09/12] spapr_pci: enable basic hotplug operations
Date: Mon, 18 Aug 2014 19:21:55 -0500 [thread overview]
Message-ID: <1408407718-10835-10-git-send-email-mdroth@linux.vnet.ibm.com> (raw)
In-Reply-To: <1408407718-10835-1-git-send-email-mdroth@linux.vnet.ibm.com>
This enables hotplug for PHB bridges. Upon hotplug we generate the
OF-nodes required by PAPR specification and IEEE 1275-1994
"PCI Bus Binding to Open Firmware" for the device.
We associate the corresponding FDT for these nodes with the DrcEntry
corresponding to the slot, which will be fetched via
ibm,configure-connector RTAS calls by the guest as described by PAPR
specification. The FDT is cleaned up in the case of unplug.
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
hw/ppc/spapr_pci.c | 235 +++++++++++++++++++++++++++++++++++++++++++++++--
include/hw/ppc/spapr.h | 1 +
2 files changed, 228 insertions(+), 8 deletions(-)
diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c
index 96a57be..23864ab 100644
--- a/hw/ppc/spapr_pci.c
+++ b/hw/ppc/spapr_pci.c
@@ -87,6 +87,17 @@
#define ENCODE_DRC_STATE(val, m, s) \
(((uint32_t)(val) << (s)) & (uint32_t)(m))
+#define FDT_MAX_SIZE 0x10000
+#define _FDT(exp) \
+ do { \
+ int ret = (exp); \
+ if (ret < 0) { \
+ return ret; \
+ } \
+ } while (0)
+
+static void spapr_drc_state_reset(sPAPRDrcEntry *drc_entry);
+
static sPAPRPHBState *find_phb(sPAPREnvironment *spapr, uint64_t buid)
{
sPAPRPHBState *sphb;
@@ -476,6 +487,22 @@ static void rtas_set_indicator(PowerPCCPU *cpu, sPAPREnvironment *spapr,
/* encode the new value into the correct bit field */
shift = INDICATOR_ISOLATION_SHIFT;
mask = INDICATOR_ISOLATION_MASK;
+ if (drc_entry) {
+ /* transition from unisolated to isolated for a hotplug slot
+ * entails completion of guest-side device unplug/cleanup, so
+ * we can now safely remove the device if qemu is waiting for
+ * it to be released
+ */
+ if (DECODE_DRC_STATE(*pind, mask, shift) != indicator_state) {
+ if (indicator_state == 0 && drc_entry->awaiting_release) {
+ /* device_del has been called and host is waiting
+ * for guest to release/isolate device, go ahead
+ * and remove it now
+ */
+ spapr_drc_state_reset(drc_entry);
+ }
+ }
+ }
break;
case 9002: /* DR */
shift = INDICATOR_DR_SHIFT;
@@ -816,6 +843,198 @@ static AddressSpace *spapr_pci_dma_iommu(PCIBus *bus, void *opaque, int devfn)
return &phb->iommu_as;
}
+static int spapr_populate_pci_child_dt(PCIDevice *dev, void *fdt, int offset,
+ int phb_index)
+{
+ int slot = PCI_SLOT(dev->devfn);
+ char slotname[16];
+ bool is_bridge = 1;
+ sPAPRDrcEntry *drc_entry, *drc_entry_slot;
+ uint32_t reg[RESOURCE_CELLS_TOTAL * 8] = { 0 };
+ uint32_t assigned[RESOURCE_CELLS_TOTAL * 8] = { 0 };
+ int reg_size, assigned_size;
+
+ drc_entry = spapr_phb_to_drc_entry(phb_index + SPAPR_PCI_BASE_BUID);
+ g_assert(drc_entry);
+ drc_entry_slot = &drc_entry->child_entries[slot];
+
+ if (pci_default_read_config(dev, PCI_HEADER_TYPE, 1) ==
+ PCI_HEADER_TYPE_NORMAL) {
+ is_bridge = 0;
+ }
+
+ _FDT(fdt_setprop_cell(fdt, offset, "vendor-id",
+ pci_default_read_config(dev, PCI_VENDOR_ID, 2)));
+ _FDT(fdt_setprop_cell(fdt, offset, "device-id",
+ pci_default_read_config(dev, PCI_DEVICE_ID, 2)));
+ _FDT(fdt_setprop_cell(fdt, offset, "revision-id",
+ pci_default_read_config(dev, PCI_REVISION_ID, 1)));
+ _FDT(fdt_setprop_cell(fdt, offset, "class-code",
+ pci_default_read_config(dev, PCI_CLASS_DEVICE, 2) << 8));
+
+ _FDT(fdt_setprop_cell(fdt, offset, "interrupts",
+ pci_default_read_config(dev, PCI_INTERRUPT_PIN, 1)));
+
+ /* if this device is NOT a bridge */
+ if (!is_bridge) {
+ _FDT(fdt_setprop_cell(fdt, offset, "min-grant",
+ pci_default_read_config(dev, PCI_MIN_GNT, 1)));
+ _FDT(fdt_setprop_cell(fdt, offset, "max-latency",
+ pci_default_read_config(dev, PCI_MAX_LAT, 1)));
+ _FDT(fdt_setprop_cell(fdt, offset, "subsystem-id",
+ pci_default_read_config(dev, PCI_SUBSYSTEM_ID, 2)));
+ _FDT(fdt_setprop_cell(fdt, offset, "subsystem-vendor-id",
+ pci_default_read_config(dev, PCI_SUBSYSTEM_VENDOR_ID, 2)));
+ }
+
+ _FDT(fdt_setprop_cell(fdt, offset, "cache-line-size",
+ pci_default_read_config(dev, PCI_CACHE_LINE_SIZE, 1)));
+
+ /* the following fdt cells are masked off the pci status register */
+ int pci_status = pci_default_read_config(dev, PCI_STATUS, 2);
+ _FDT(fdt_setprop_cell(fdt, offset, "devsel-speed",
+ PCI_STATUS_DEVSEL_MASK & pci_status));
+ _FDT(fdt_setprop_cell(fdt, offset, "fast-back-to-back",
+ PCI_STATUS_FAST_BACK & pci_status));
+ _FDT(fdt_setprop_cell(fdt, offset, "66mhz-capable",
+ PCI_STATUS_66MHZ & pci_status));
+ _FDT(fdt_setprop_cell(fdt, offset, "udf-supported",
+ PCI_STATUS_UDF & pci_status));
+
+ _FDT(fdt_setprop_string(fdt, offset, "name", "pci"));
+ sprintf(slotname, "Slot %d", slot + phb_index * 32);
+ _FDT(fdt_setprop(fdt, offset, "ibm,loc-code", slotname, strlen(slotname)));
+ _FDT(fdt_setprop_cell(fdt, offset, "ibm,my-drc-index",
+ drc_entry_slot->drc_index));
+
+ _FDT(fdt_setprop_cell(fdt, offset, "#address-cells",
+ RESOURCE_CELLS_ADDRESS));
+ _FDT(fdt_setprop_cell(fdt, offset, "#size-cells",
+ RESOURCE_CELLS_SIZE));
+ _FDT(fdt_setprop_cell(fdt, offset, "ibm,req#msi-x",
+ RESOURCE_CELLS_SIZE));
+ fill_resource_props(dev, phb_index, reg, ®_size,
+ assigned, &assigned_size);
+ _FDT(fdt_setprop(fdt, offset, "reg", reg, reg_size));
+ _FDT(fdt_setprop(fdt, offset, "assigned-addresses",
+ assigned, assigned_size));
+
+ return 0;
+}
+
+static int spapr_device_hotplug_add(DeviceState *qdev, PCIDevice *dev)
+{
+ sPAPRPHBState *phb = SPAPR_PCI_HOST_BRIDGE(qdev);
+ sPAPRDrcEntry *drc_entry, *drc_entry_slot;
+ sPAPRConfigureConnectorState *ccs;
+ int slot = PCI_SLOT(dev->devfn);
+ int offset, ret;
+ void *fdt_orig, *fdt;
+ char nodename[512];
+ uint32_t encoded = ENCODE_DRC_STATE(INDICATOR_ENTITY_SENSE_PRESENT,
+ INDICATOR_ENTITY_SENSE_MASK,
+ INDICATOR_ENTITY_SENSE_SHIFT);
+
+ drc_entry = spapr_phb_to_drc_entry(phb->buid);
+ g_assert(drc_entry);
+ drc_entry_slot = &drc_entry->child_entries[slot];
+
+ drc_entry->state &= ~(uint32_t)INDICATOR_ENTITY_SENSE_MASK;
+ drc_entry->state |= encoded; /* DR entity present */
+ drc_entry_slot->state &= ~(uint32_t)INDICATOR_ENTITY_SENSE_MASK;
+ drc_entry_slot->state |= encoded; /* and the slot */
+
+ /* add OF node for pci device and required OF DT properties */
+ fdt_orig = g_malloc0(FDT_MAX_SIZE);
+ offset = fdt_create(fdt_orig, FDT_MAX_SIZE);
+ fdt_begin_node(fdt_orig, "");
+ fdt_end_node(fdt_orig);
+ fdt_finish(fdt_orig);
+
+ fdt = g_malloc0(FDT_MAX_SIZE);
+ fdt_open_into(fdt_orig, fdt, FDT_MAX_SIZE);
+ sprintf(nodename, "pci@%d", slot);
+ offset = fdt_add_subnode(fdt, 0, nodename);
+ ret = spapr_populate_pci_child_dt(dev, fdt, offset, phb->index);
+ g_assert(!ret);
+ g_free(fdt_orig);
+
+ /* hold on to node, configure_connector will pass it to the guest later */
+ ccs = &drc_entry_slot->cc_state;
+ ccs->fdt = fdt;
+ ccs->offset_start = offset;
+ ccs->state = CC_STATE_PENDING;
+ ccs->dev = dev;
+
+ return 0;
+}
+
+/* check whether guest has released/isolated device */
+static bool spapr_drc_state_is_releasable(sPAPRDrcEntry *drc_entry)
+{
+ return !DECODE_DRC_STATE(drc_entry->state,
+ INDICATOR_ISOLATION_MASK,
+ INDICATOR_ISOLATION_SHIFT);
+}
+
+/* finalize device unplug/deletion */
+static void spapr_drc_state_reset(sPAPRDrcEntry *drc_entry)
+{
+ sPAPRConfigureConnectorState *ccs = &drc_entry->cc_state;
+ uint32_t sense_empty = ENCODE_DRC_STATE(INDICATOR_ENTITY_SENSE_EMPTY,
+ INDICATOR_ENTITY_SENSE_MASK,
+ INDICATOR_ENTITY_SENSE_SHIFT);
+
+ g_free(ccs->fdt);
+ ccs->fdt = NULL;
+ object_unparent(OBJECT(ccs->dev));
+ ccs->dev = NULL;
+ ccs->state = CC_STATE_IDLE;
+ drc_entry->state &= ~INDICATOR_ENTITY_SENSE_MASK;
+ drc_entry->state |= sense_empty;
+ drc_entry->awaiting_release = false;
+}
+
+static void spapr_device_hotplug_remove(DeviceState *qdev, PCIDevice *dev)
+{
+ sPAPRPHBState *phb = SPAPR_PCI_HOST_BRIDGE(qdev);
+ sPAPRDrcEntry *drc_entry, *drc_entry_slot;
+ sPAPRConfigureConnectorState *ccs;
+ int slot = PCI_SLOT(dev->devfn);
+
+ drc_entry = spapr_phb_to_drc_entry(phb->buid);
+ g_assert(drc_entry);
+ drc_entry_slot = &drc_entry->child_entries[slot];
+ ccs = &drc_entry_slot->cc_state;
+ /* shouldn't be removing devices we haven't created an fdt for */
+ g_assert(ccs->state != CC_STATE_IDLE);
+ /* if the device has already been released/isolated by guest, go ahead
+ * and remove it now. Otherwise, flag it as pending guest release so it
+ * can be removed later
+ */
+ if (spapr_drc_state_is_releasable(drc_entry_slot)) {
+ spapr_drc_state_reset(drc_entry_slot);
+ } else {
+ if (drc_entry_slot->awaiting_release) {
+ fprintf(stderr, "waiting for guest to release the device");
+ } else {
+ drc_entry_slot->awaiting_release = true;
+ }
+ }
+}
+
+static void spapr_phb_hot_plug(HotplugHandler *plug_handler,
+ DeviceState *plugged_dev, Error **errp)
+{
+ spapr_device_hotplug_add(DEVICE(plug_handler), PCI_DEVICE(plugged_dev));
+}
+
+static void spapr_phb_hot_unplug(HotplugHandler *plug_handler,
+ DeviceState *plugged_dev, Error **errp)
+{
+ spapr_device_hotplug_remove(DEVICE(plug_handler), PCI_DEVICE(plugged_dev));
+}
+
static void spapr_phb_realize(DeviceState *dev, Error **errp)
{
SysBusDevice *s = SYS_BUS_DEVICE(dev);
@@ -903,6 +1122,7 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp)
&sphb->memspace, &sphb->iospace,
PCI_DEVFN(0, 0), PCI_NUM_PINS, TYPE_PCI_BUS);
phb->bus = bus;
+ qbus_set_hotplug_handler(BUS(phb->bus), DEVICE(sphb), NULL);
/*
* Initialize PHB address space.
@@ -1108,6 +1328,7 @@ static void spapr_phb_class_init(ObjectClass *klass, void *data)
PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
sPAPRPHBClass *spc = SPAPR_PCI_HOST_BRIDGE_CLASS(klass);
+ HotplugHandlerClass *hp = HOTPLUG_HANDLER_CLASS(klass);
hc->root_bus_path = spapr_phb_root_bus_path;
dc->realize = spapr_phb_realize;
@@ -1117,6 +1338,8 @@ static void spapr_phb_class_init(ObjectClass *klass, void *data)
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
dc->cannot_instantiate_with_device_add_yet = false;
spc->finish_realize = spapr_phb_finish_realize;
+ hp->plug = spapr_phb_hot_plug;
+ hp->unplug = spapr_phb_hot_unplug;
}
static const TypeInfo spapr_phb_info = {
@@ -1125,6 +1348,10 @@ static const TypeInfo spapr_phb_info = {
.instance_size = sizeof(sPAPRPHBState),
.class_init = spapr_phb_class_init,
.class_size = sizeof(sPAPRPHBClass),
+ .interfaces = (InterfaceInfo[]) {
+ { TYPE_HOTPLUG_HANDLER },
+ { }
+ }
};
PCIHostState *spapr_create_phb(sPAPREnvironment *spapr, int index)
@@ -1304,14 +1531,6 @@ int spapr_populate_pci_dt(sPAPRPHBState *phb,
return bus_off;
}
-#define _FDT(exp) \
- do { \
- int ret = (exp); \
- if (ret < 0) { \
- return ret; \
- } \
- } while (0)
-
/* Write PHB properties */
_FDT(fdt_setprop_string(fdt, bus_off, "device_type", "pci"));
_FDT(fdt_setprop_string(fdt, bus_off, "compatible", "IBM,Logical_PHB"));
diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h
index fac85f8..e08dd2f 100644
--- a/include/hw/ppc/spapr.h
+++ b/include/hw/ppc/spapr.h
@@ -36,6 +36,7 @@ struct sPAPRDrcEntry {
void *fdt;
int fdt_offset;
uint32_t state;
+ bool awaiting_release;
sPAPRConfigureConnectorState cc_state;
sPAPRDrcEntry *child_entries;
};
--
1.9.1
next prev parent reply other threads:[~2014-08-19 0:23 UTC|newest]
Thread overview: 69+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-08-19 0:21 [Qemu-devel] [PATCH v3 00/12] spapr: add support for pci hotplug Michael Roth
2014-08-19 0:21 ` [Qemu-devel] [PATCH 01/12] spapr: populate DRC entries for root dt node Michael Roth
2014-08-26 7:55 ` Alexey Kardashevskiy
2014-08-26 8:24 ` Alexey Kardashevskiy
2014-08-26 15:25 ` Michael Roth
2014-08-26 15:41 ` Michael Roth
2014-08-29 18:27 ` Tyrel Datwyler
2014-08-29 23:15 ` Alexander Graf
2014-08-26 14:56 ` Michael Roth
2014-09-05 0:31 ` [Qemu-devel] [Qemu-ppc] " Tyrel Datwyler
2014-08-26 11:11 ` [Qemu-devel] " Alexander Graf
2014-08-26 16:47 ` Michael Roth
2014-08-26 17:16 ` Alexander Graf
2014-09-03 5:55 ` Bharata B Rao
2014-09-05 22:00 ` Tyrel Datwyler
2014-08-19 0:21 ` [Qemu-devel] [PATCH 02/12] spapr_pci: populate DRC dt entries for PHBs Michael Roth
2014-08-26 8:32 ` Alexey Kardashevskiy
2014-08-26 17:16 ` Michael Roth
2014-08-26 9:09 ` Alexey Kardashevskiy
2014-08-26 17:52 ` Michael Roth
2014-08-26 11:29 ` Alexander Graf
2014-08-26 18:30 ` Michael Roth
2014-08-19 0:21 ` [Qemu-devel] [PATCH 03/12] spapr: add helper to retrieve a PHB/device DrcEntry Michael Roth
2014-08-19 0:21 ` [Qemu-devel] [PATCH 04/12] spapr_pci: add set-indicator RTAS interface Michael Roth
2014-08-26 11:36 ` Alexander Graf
2014-09-05 2:55 ` Nathan Fontenot
2014-09-30 22:08 ` Michael Roth
2014-10-01 14:30 ` Alexander Graf
2014-11-26 4:51 ` Bharata B Rao
2014-11-26 4:54 ` Bharata B Rao
2014-11-26 6:27 ` Michael Roth
2014-12-01 4:57 ` Bharata B Rao
2014-12-23 15:12 ` Michael Roth
2015-01-01 6:35 ` Bharata B Rao
2014-08-19 0:21 ` [Qemu-devel] [PATCH 05/12] spapr_pci: add get/set-power-level RTAS interfaces Michael Roth
2014-08-19 0:21 ` [Qemu-devel] [PATCH 06/12] spapr_pci: add get-sensor-state RTAS interface Michael Roth
2014-09-05 0:34 ` Tyrel Datwyler
2014-08-19 0:21 ` [Qemu-devel] [PATCH 07/12] spapr_pci: add ibm, configure-connector " Michael Roth
2014-08-26 9:12 ` Alexey Kardashevskiy
2014-09-05 3:03 ` Nathan Fontenot
2014-08-26 11:39 ` Alexander Graf
2014-08-19 0:21 ` [Qemu-devel] [PATCH 08/12] pci: allow 0 address for PCI IO regions Michael Roth
2014-08-26 9:14 ` Alexey Kardashevskiy
2014-08-26 11:55 ` Peter Maydell
2014-08-26 18:34 ` Michael Roth
2014-08-26 11:41 ` Alexander Graf
2014-08-27 13:47 ` Michael S. Tsirkin
2014-08-28 21:21 ` Michael Roth
2014-08-28 21:33 ` Peter Maydell
2014-08-28 21:46 ` Michael S. Tsirkin
2014-08-19 0:21 ` Michael Roth [this message]
2014-08-26 9:40 ` [Qemu-devel] [PATCH 09/12] spapr_pci: enable basic hotplug operations Alexey Kardashevskiy
2014-08-26 12:30 ` Alexander Graf
2014-09-03 10:33 ` Bharata B Rao
2014-09-03 23:03 ` Michael Roth
2014-09-04 15:08 ` Bharata B Rao
2014-09-04 16:12 ` Michael Roth
2014-09-04 16:34 ` Michael Roth
2014-09-05 3:10 ` Nathan Fontenot
2014-09-05 17:17 ` [Qemu-devel] [Qemu-ppc] " Tyrel Datwyler
2014-08-19 0:21 ` [Qemu-devel] [PATCH 10/12] spapr_events: re-use EPOW event infrastructure for hotplug events Michael Roth
2014-08-26 9:28 ` Alexey Kardashevskiy
2014-08-19 0:21 ` [Qemu-devel] [PATCH 11/12] spapr_events: event-scan RTAS interface Michael Roth
2014-08-26 9:30 ` Alexey Kardashevskiy
2014-08-29 18:43 ` Tyrel Datwyler
2014-08-19 0:21 ` [Qemu-devel] [PATCH 12/12] spapr_pci: emit hotplug add/remove events during hotplug Michael Roth
2014-08-26 9:35 ` Alexey Kardashevskiy
2014-08-26 12:36 ` Alexander Graf
2014-08-26 9:24 ` [Qemu-devel] [PATCH v3 00/12] spapr: add support for pci hotplug Alexey Kardashevskiy
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1408407718-10835-10-git-send-email-mdroth@linux.vnet.ibm.com \
--to=mdroth@linux.vnet.ibm.com \
--cc=agraf@suse.de \
--cc=aik@ozlabs.ru \
--cc=ncmike@ncultra.org \
--cc=nfont@linux.vnet.ibm.com \
--cc=qemu-devel@nongnu.org \
--cc=qemu-ppc@nongnu.org \
--cc=tyreld@linux.vnet.ibm.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).