Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F144033369
D54646.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
4 KB
Referenced Files
None
Subscribers
None
D54646.diff
View Options
diff --git a/usr.sbin/bhyve/pci_emul.c b/usr.sbin/bhyve/pci_emul.c
--- a/usr.sbin/bhyve/pci_emul.c
+++ b/usr.sbin/bhyve/pci_emul.c
@@ -182,6 +182,20 @@
static int pci_hp_init(struct vmctx *ctx);
+#define PCIHP_ACPI_HID "PNP0A06"
+#define PCIHP_ACPI_DEVNAME "PHPS"
+#define PCIHP_IOMEM_RANGE_NAME "PCI Hotplug metadata"
+
+static const struct acpi_device_emul pcihp_device_emul = {
+ .name = PCIHP_ACPI_DEVNAME,
+ .hid = PCIHP_ACPI_HID,
+};
+
+static int hp_busselect;
+static pthread_mutex_t hp_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t hp_ejectwrite_cond = PTHREAD_COND_INITIALIZER;
+static pthread_cond_t hp_ejectack_cond = PTHREAD_COND_INITIALIZER;
+
static void pci_lintr_route(struct pci_devinst *pi);
static void pci_lintr_update(struct pci_devinst *pi);
@@ -1776,7 +1790,7 @@
error = register_mem(&mr);
assert(error == 0);
- return (0);
+ return (pci_hp_init(ctx));
}
#ifdef __amd64__
@@ -3057,6 +3071,138 @@
}
#endif
+/*
+ * Controls guest access to the per-bus PCI hotplug metadata structures.
+ * The access to the metadata is enforced as follows:
+ * - PCI_EMUL_HP_PCUP_REG - PCI hotadd request bitmap, guest R/O,
+ * - PCI_EMUL_HP_PCDW_REG - PCI hotremove request bitmap, guest R/O,
+ * - PCI_EMUL_HP_EACK_REG - PCI eject ACK bitmap, guest W/O.
+ */
+static int
+pci_hpinfo_handler(struct vcpu *vcpu __unused, int dir, uint64_t addr, int size,
+ uint64_t *val, void *arg1 __unused, long arg2 __unused)
+{
+ struct hpinfo *hi;
+ uint64_t offset;
+ int bus, error;
+
+ /*
+ * All per-bus 'hpinfo' structs are stored
+ * contiguously starting from 'PCI_EMUL_HP_BASE'.
+ */
+ bus = rounddown(addr - PCI_EMUL_HP_BASE, sizeof(struct hpinfo)) /
+ sizeof(struct hpinfo);
+ offset = (addr - PCI_EMUL_HP_BASE) % sizeof(struct hpinfo);
+ if (bus < 0 || bus >= MAXBUSES)
+ return (-1);
+ if (size != 4)
+ return (-1);
+ if (offset < PCI_EMUL_HP_EACK_REG && dir == MEM_F_WRITE)
+ return (-1);
+
+ error = 0;
+ hi = &pci_businfo[bus]->hpinfo;
+ pthread_mutex_lock(&hp_lock);
+ switch (offset) {
+ case PCI_EMUL_HP_PCUP_REG:
+ *val = hi->pciu;
+ hi->pciu = 0;
+ break;
+ case PCI_EMUL_HP_PCDW_REG:
+ *val = hi->pcid;
+ hi->pcid = 0;
+ break;
+ case PCI_EMUL_HP_EACK_REG:
+ if (dir == MEM_F_WRITE) {
+ hi->pcid &= ~((uint32_t)*val);
+ /*
+ * Let the hypervisor know that guest finished detaching
+ * the device and wait until it fully removes the PCI
+ * device to prevent the guest from picking the
+ * partially removed device with a subsequent PCI bus
+ * rescan.
+ */
+ pthread_cond_signal(&hp_ejectwrite_cond);
+ pthread_cond_wait(&hp_ejectack_cond, &hp_lock);
+ } else
+ error = -1;
+ break;
+ default:
+ error = -1;
+ break;
+ }
+ pthread_mutex_unlock(&hp_lock);
+
+ return (error);
+}
+
+static int
+pci_busselect_handler(struct vcpu *vcpu __unused, int dir,
+ uint64_t addr __unused, int size, uint64_t *val, void *arg1 __unused,
+ long arg2 __unused)
+{
+ if (size != 4 || dir != MEM_F_READ)
+ return (-1);
+ *val = hp_busselect;
+
+ return (0);
+}
+
+static int
+pci_hp_init(struct vmctx *ctx)
+{
+ int error;
+ struct mem_range hp_mr, bussel_mr;
+ struct acpi_device *dev;
+
+ error = acpi_device_create(&dev, dev, ctx, &pcihp_device_emul);
+ if (error) {
+ EPRINTLN("%s: Failed to register hotplug metadata ACPI device",
+ __func__);
+ return (error);
+ }
+ error = acpi_device_add_res_fixed_memory32(dev, false, PCI_EMUL_HP_BASE,
+ sizeof(struct hpinfo) * MAXBUSES);
+ if (error) {
+ EPRINTLN(
+ "%s: Failed to initialize hotplug metadata ACPI device",
+ __func__);
+ acpi_device_destroy(dev);
+ return (error);
+ }
+
+ bzero(&hp_mr, sizeof(hp_mr));
+ hp_mr.name = "PCI hotplug metadata";
+ hp_mr.flags = MEM_F_RW;
+ hp_mr.base = PCI_EMUL_HP_BASE;
+ hp_mr.size = sizeof(struct hpinfo) * MAXBUSES;
+ hp_mr.handler = pci_hpinfo_handler;
+ error = register_mem(&hp_mr);
+ if (error) {
+ EPRINTLN(
+ "%s: Failed to register hotplug metadata device handler",
+ __func__);
+ acpi_device_destroy(dev);
+ return (error);
+ }
+
+ bzero(&bussel_mr, sizeof(bussel_mr));
+ bussel_mr.name = "PCI hotplug bus select";
+ bussel_mr.flags = MEM_F_READ;
+ bussel_mr.base = PCI_EMUL_HP_BSEL_ADDR;
+ bussel_mr.size = sizeof(hp_busselect);
+ bussel_mr.handler = pci_busselect_handler;
+ error = register_mem(&bussel_mr);
+ if (error) {
+ EPRINTLN("%s: Failed to register hotplug bus select handler",
+ __func__);
+ acpi_device_destroy(dev);
+ unregister_mem(&hp_mr);
+ return (error);
+ }
+
+ return (0);
+}
static const struct pci_devemu pci_dummy = {
.pe_emu = "dummy",
.pe_init = pci_emul_dinit,
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Wed, Feb 4, 4:23 PM (17 h, 55 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
27619834
Default Alt Text
D54646.diff (4 KB)
Attached To
Mode
D54646: bhyve/pci_emul.c: Add handlers for ACPI PCI hotplug metadata
Attached
Detach File
Event Timeline
Log In to Comment