aboutsummaryrefslogtreecommitdiff
path: root/hw/xen/xen_pt.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/xen/xen_pt.c')
-rw-r--r--hw/xen/xen_pt.c164
1 files changed, 106 insertions, 58 deletions
diff --git a/hw/xen/xen_pt.c b/hw/xen/xen_pt.c
index e5a6eff44f..3635d1b39f 100644
--- a/hw/xen/xen_pt.c
+++ b/hw/xen/xen_pt.c
@@ -57,12 +57,25 @@
#include <sys/ioctl.h>
#include "hw/pci/pci.h"
+#include "hw/qdev-properties.h"
+#include "hw/qdev-properties-system.h"
+#include "hw/xen/xen_pt.h"
+#include "hw/xen/xen_igd.h"
#include "hw/xen/xen.h"
-#include "hw/i386/pc.h"
-#include "hw/xen/xen_backend.h"
-#include "xen_pt.h"
+#include "hw/xen/xen-legacy-backend.h"
#include "qemu/range.h"
-#include "exec/address-spaces.h"
+
+static bool has_igd_gfx_passthru;
+
+bool xen_igd_gfx_pt_enabled(void)
+{
+ return has_igd_gfx_passthru;
+}
+
+void xen_igd_gfx_pt_set(bool value, Error **errp)
+{
+ has_igd_gfx_passthru = value;
+}
#define XEN_PT_NR_IRQS (256)
static uint8_t xen_pt_mapped_machine_irq[XEN_PT_NR_IRQS] = {0};
@@ -422,7 +435,7 @@ static uint64_t xen_pt_bar_read(void *o, hwaddr addr,
PCIDevice *d = o;
/* if this function is called, that probably means that there is a
* misconfiguration of the IOMMU. */
- XEN_PT_ERR(d, "Should not read BAR through QEMU. @0x"TARGET_FMT_plx"\n",
+ XEN_PT_ERR(d, "Should not read BAR through QEMU. @0x"HWADDR_FMT_plx"\n",
addr);
return 0;
}
@@ -431,7 +444,7 @@ static void xen_pt_bar_write(void *o, hwaddr addr, uint64_t val,
{
PCIDevice *d = o;
/* Same comment as xen_pt_bar_read function */
- XEN_PT_ERR(d, "Should not write BAR through QEMU. @0x"TARGET_FMT_plx"\n",
+ XEN_PT_ERR(d, "Should not write BAR through QEMU. @0x"HWADDR_FMT_plx"\n",
addr);
}
@@ -476,7 +489,7 @@ static int xen_pt_register_regions(XenPCIPassthroughState *s, uint16_t *cmd)
pci_register_bar(&s->dev, i, type, &s->bar[i]);
XEN_PT_LOG(&s->dev, "IO region %i registered (size=0x%08"PRIx64
- " base_addr=0x%08"PRIx64" type: %#x)\n",
+ " base_addr=0x%08"PRIx64" type: 0x%x)\n",
i, r->size, r->base_addr, type);
}
@@ -565,7 +578,7 @@ static void xen_pt_check_bar_overlap(PCIBus *bus, PCIDevice *d, void *opaque)
if (ranges_overlap(arg->addr, arg->size, r->addr, r->size)) {
XEN_PT_WARN(&s->dev,
"Overlapped to device [%02x:%02x.%d] Region: %i"
- " (addr: %#"FMT_PCIBUS", len: %#"FMT_PCIBUS")\n",
+ " (addr: 0x%"FMT_PCIBUS", len: 0x%"FMT_PCIBUS")\n",
pci_bus_num(bus), PCI_SLOT(d->devfn),
PCI_FUNC(d->devfn), i, r->addr, r->size);
arg->rc = true;
@@ -602,11 +615,11 @@ static void xen_pt_region_update(XenPCIPassthroughState *s,
}
args.type = d->io_regions[bar].type;
- pci_for_each_device(pci_get_bus(d), pci_dev_bus_num(d),
- xen_pt_check_bar_overlap, &args);
+ pci_for_each_device_under_bus(pci_get_bus(d),
+ xen_pt_check_bar_overlap, &args);
if (args.rc) {
- XEN_PT_WARN(d, "Region: %d (addr: %#"FMT_PCIBUS
- ", len: %#"FMT_PCIBUS") is overlapped.\n",
+ XEN_PT_WARN(d, "Region: %d (addr: 0x%"FMT_PCIBUS
+ ", len: 0x%"FMT_PCIBUS") is overlapped.\n",
bar, sec->offset_within_address_space,
int128_get64(sec->size));
}
@@ -676,28 +689,19 @@ static void xen_pt_io_region_del(MemoryListener *l, MemoryRegionSection *sec)
}
static const MemoryListener xen_pt_memory_listener = {
+ .name = "xen-pt-mem",
.region_add = xen_pt_region_add,
.region_del = xen_pt_region_del,
- .priority = 10,
+ .priority = MEMORY_LISTENER_PRIORITY_ACCEL,
};
static const MemoryListener xen_pt_io_listener = {
+ .name = "xen-pt-io",
.region_add = xen_pt_io_region_add,
.region_del = xen_pt_io_region_del,
- .priority = 10,
+ .priority = MEMORY_LISTENER_PRIORITY_ACCEL,
};
-static void
-xen_igd_passthrough_isa_bridge_create(XenPCIPassthroughState *s,
- XenHostPCIDevice *dev)
-{
- uint16_t gpu_dev_id;
- PCIDevice *d = &s->dev;
-
- gpu_dev_id = dev->device_id;
- igd_passthrough_isa_bridge_create(pci_get_bus(d), gpu_dev_id);
-}
-
/* destroy. */
static void xen_pt_destroy(PCIDevice *d) {
@@ -707,7 +711,7 @@ static void xen_pt_destroy(PCIDevice *d) {
uint8_t intx;
int rc;
- if (machine_irq && !xen_host_pci_device_closed(&s->real_device)) {
+ if (machine_irq && !xen_host_pci_device_closed(host_dev)) {
intx = xen_pt_pci_intx(s);
rc = xc_domain_unbind_pt_irq(xen_xc, xen_domid, machine_irq,
PT_IRQ_TYPE_PCI,
@@ -756,37 +760,27 @@ static void xen_pt_destroy(PCIDevice *d) {
memory_listener_unregister(&s->io_listener);
s->listener_set = false;
}
- if (!xen_host_pci_device_closed(&s->real_device)) {
- xen_host_pci_device_put(&s->real_device);
+ if (!xen_host_pci_device_closed(host_dev)) {
+ xen_host_pci_device_put(host_dev);
}
}
/* init */
static void xen_pt_realize(PCIDevice *d, Error **errp)
{
+ ERRP_GUARD();
XenPCIPassthroughState *s = XEN_PT_DEVICE(d);
int i, rc = 0;
uint8_t machine_irq = 0, scratch;
uint16_t cmd = 0;
int pirq = XEN_PT_UNASSIGNED_PIRQ;
- Error *err = NULL;
/* register real device */
XEN_PT_LOG(d, "Assigning real physical device %02x:%02x.%d"
- " to devfn %#x\n",
+ " to devfn 0x%x\n",
s->hostaddr.bus, s->hostaddr.slot, s->hostaddr.function,
s->dev.devfn);
- xen_host_pci_device_get(&s->real_device,
- s->hostaddr.domain, s->hostaddr.bus,
- s->hostaddr.slot, s->hostaddr.function,
- &err);
- if (err) {
- error_append_hint(&err, "Failed to \"open\" the real pci device");
- error_propagate(errp, err);
- return;
- }
-
s->is_virtfn = s->real_device.is_virtfn;
if (s->is_virtfn) {
XEN_PT_LOG(d, "%04x:%02x:%02x.%d is a SR-IOV Virtual Function\n",
@@ -801,8 +795,10 @@ static void xen_pt_realize(PCIDevice *d, Error **errp)
s->io_listener = xen_pt_io_listener;
/* Setup VGA bios for passthrough GFX */
- if ((s->real_device.domain == 0) && (s->real_device.bus == 0) &&
- (s->real_device.dev == 2) && (s->real_device.func == 0)) {
+ if ((s->real_device.domain == XEN_PCI_IGD_DOMAIN) &&
+ (s->real_device.bus == XEN_PCI_IGD_BUS) &&
+ (s->real_device.dev == XEN_PCI_IGD_DEV) &&
+ (s->real_device.func == XEN_PCI_IGD_FN)) {
if (!is_igd_vga_passthrough(&s->real_device)) {
error_setg(errp, "Need to enable igd-passthru if you're trying"
" to passthrough IGD GFX");
@@ -810,11 +806,10 @@ static void xen_pt_realize(PCIDevice *d, Error **errp)
return;
}
- xen_pt_setup_vga(s, &s->real_device, &err);
- if (err) {
- error_append_hint(&err, "Setup VGA BIOS of passthrough"
- " GFX failed");
- error_propagate(errp, err);
+ xen_pt_setup_vga(s, &s->real_device, errp);
+ if (*errp) {
+ error_append_hint(errp, "Setup VGA BIOS of passthrough"
+ " GFX failed");
xen_host_pci_device_put(&s->real_device);
return;
}
@@ -827,10 +822,9 @@ static void xen_pt_realize(PCIDevice *d, Error **errp)
xen_pt_register_regions(s, &cmd);
/* reinitialize each config register to be emulated */
- xen_pt_config_init(s, &err);
- if (err) {
- error_append_hint(&err, "PCI Config space initialisation failed");
- error_report_err(err);
+ xen_pt_config_init(s, errp);
+ if (*errp) {
+ error_append_hint(errp, "PCI Config space initialisation failed");
rc = -1;
goto err_out;
}
@@ -847,10 +841,16 @@ static void xen_pt_realize(PCIDevice *d, Error **errp)
}
machine_irq = s->real_device.irq;
+ if (machine_irq == 0) {
+ XEN_PT_LOG(d, "machine irq is 0\n");
+ cmd |= PCI_COMMAND_INTX_DISABLE;
+ goto out;
+ }
+
rc = xc_physdev_map_pirq(xen_xc, xen_domid, machine_irq, &pirq);
if (rc < 0) {
- error_setg_errno(errp, errno, "Mapping machine irq %u to"
- " pirq %i failed", machine_irq, pirq);
+ XEN_PT_ERR(d, "Mapping machine irq %u to pirq %i failed, (err: %d)\n",
+ machine_irq, pirq, errno);
/* Disable PCI intx assertion (turn on bit10 of devctl) */
cmd |= PCI_COMMAND_INTX_DISABLE;
@@ -871,8 +871,8 @@ static void xen_pt_realize(PCIDevice *d, Error **errp)
PCI_SLOT(d->devfn),
e_intx);
if (rc < 0) {
- error_setg_errno(errp, errno, "Binding of interrupt %u failed",
- e_intx);
+ XEN_PT_ERR(d, "Binding of interrupt %i failed! (err: %d)\n",
+ e_intx, errno);
/* Disable PCI intx assertion (turn on bit10 of devctl) */
cmd |= PCI_COMMAND_INTX_DISABLE;
@@ -880,8 +880,8 @@ static void xen_pt_realize(PCIDevice *d, Error **errp)
if (xen_pt_mapped_machine_irq[machine_irq] == 0) {
if (xc_physdev_unmap_pirq(xen_xc, xen_domid, machine_irq)) {
- error_setg_errno(errp, errno, "Unmapping of machine"
- " interrupt %u failed", machine_irq);
+ XEN_PT_ERR(d, "Unmapping of machine interrupt %i failed!"
+ " (err: %d)\n", machine_irq, errno);
}
}
s->machine_irq = 0;
@@ -944,18 +944,65 @@ static void xen_pci_passthrough_instance_init(Object *obj)
PCI_DEVICE(obj)->cap_present |= QEMU_PCI_CAP_EXPRESS;
}
+void xen_igd_reserve_slot(PCIBus *pci_bus)
+{
+ if (!xen_igd_gfx_pt_enabled()) {
+ return;
+ }
+
+ XEN_PT_LOG(0, "Reserving PCI slot 2 for IGD\n");
+ pci_bus_set_slot_reserved_mask(pci_bus, XEN_PCI_IGD_SLOT_MASK);
+}
+
+static void xen_igd_clear_slot(DeviceState *qdev, Error **errp)
+{
+ ERRP_GUARD();
+ PCIDevice *pci_dev = (PCIDevice *)qdev;
+ XenPCIPassthroughState *s = XEN_PT_DEVICE(pci_dev);
+ XenPTDeviceClass *xpdc = XEN_PT_DEVICE_GET_CLASS(s);
+ PCIBus *pci_bus = pci_get_bus(pci_dev);
+
+ xen_host_pci_device_get(&s->real_device,
+ s->hostaddr.domain, s->hostaddr.bus,
+ s->hostaddr.slot, s->hostaddr.function,
+ errp);
+ if (*errp) {
+ error_append_hint(errp, "Failed to \"open\" the real pci device");
+ return;
+ }
+
+ if (!(pci_bus_get_slot_reserved_mask(pci_bus) & XEN_PCI_IGD_SLOT_MASK)) {
+ xpdc->pci_qdev_realize(qdev, errp);
+ return;
+ }
+
+ if (is_igd_vga_passthrough(&s->real_device) &&
+ s->real_device.domain == XEN_PCI_IGD_DOMAIN &&
+ s->real_device.bus == XEN_PCI_IGD_BUS &&
+ s->real_device.dev == XEN_PCI_IGD_DEV &&
+ s->real_device.func == XEN_PCI_IGD_FN &&
+ s->real_device.vendor_id == PCI_VENDOR_ID_INTEL) {
+ pci_bus_clear_slot_reserved_mask(pci_bus, XEN_PCI_IGD_SLOT_MASK);
+ XEN_PT_LOG(pci_dev, "Intel IGD found, using slot 2\n");
+ }
+ xpdc->pci_qdev_realize(qdev, errp);
+}
+
static void xen_pci_passthrough_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+ XenPTDeviceClass *xpdc = XEN_PT_DEVICE_CLASS(klass);
+ xpdc->pci_qdev_realize = dc->realize;
+ dc->realize = xen_igd_clear_slot;
k->realize = xen_pt_realize;
k->exit = xen_pt_unregister_device;
k->config_read = xen_pt_pci_read_config;
k->config_write = xen_pt_pci_write_config;
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
dc->desc = "Assign an host PCI device with Xen";
- dc->props = xen_pci_passthrough_properties;
+ device_class_set_props(dc, xen_pci_passthrough_properties);
};
static void xen_pci_passthrough_finalize(Object *obj)
@@ -971,6 +1018,7 @@ static const TypeInfo xen_pci_passthrough_info = {
.instance_size = sizeof(XenPCIPassthroughState),
.instance_finalize = xen_pci_passthrough_finalize,
.class_init = xen_pci_passthrough_class_init,
+ .class_size = sizeof(XenPTDeviceClass),
.instance_init = xen_pci_passthrough_instance_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },