180b4ecc8SPaolo Bonzini /*
280b4ecc8SPaolo Bonzini * Copyright (c) 2007, Neocleus Corporation.
380b4ecc8SPaolo Bonzini * Copyright (c) 2007, Intel Corporation.
480b4ecc8SPaolo Bonzini *
580b4ecc8SPaolo Bonzini * This work is licensed under the terms of the GNU GPL, version 2. See
680b4ecc8SPaolo Bonzini * the COPYING file in the top-level directory.
780b4ecc8SPaolo Bonzini *
880b4ecc8SPaolo Bonzini * Alex Novik <alex@neocleus.com>
980b4ecc8SPaolo Bonzini * Allen Kay <allen.m.kay@intel.com>
1080b4ecc8SPaolo Bonzini * Guy Zana <guy@neocleus.com>
1180b4ecc8SPaolo Bonzini *
1280b4ecc8SPaolo Bonzini * This file implements direct PCI assignment to a HVM guest
1380b4ecc8SPaolo Bonzini */
1480b4ecc8SPaolo Bonzini
1580b4ecc8SPaolo Bonzini /*
1680b4ecc8SPaolo Bonzini * Interrupt Disable policy:
1780b4ecc8SPaolo Bonzini *
1880b4ecc8SPaolo Bonzini * INTx interrupt:
1980b4ecc8SPaolo Bonzini * Initialize(register_real_device)
2080b4ecc8SPaolo Bonzini * Map INTx(xc_physdev_map_pirq):
2180b4ecc8SPaolo Bonzini * <fail>
2280b4ecc8SPaolo Bonzini * - Set real Interrupt Disable bit to '1'.
2380b4ecc8SPaolo Bonzini * - Set machine_irq and assigned_device->machine_irq to '0'.
2480b4ecc8SPaolo Bonzini * * Don't bind INTx.
2580b4ecc8SPaolo Bonzini *
2680b4ecc8SPaolo Bonzini * Bind INTx(xc_domain_bind_pt_pci_irq):
2780b4ecc8SPaolo Bonzini * <fail>
2880b4ecc8SPaolo Bonzini * - Set real Interrupt Disable bit to '1'.
2980b4ecc8SPaolo Bonzini * - Unmap INTx.
3080b4ecc8SPaolo Bonzini * - Decrement xen_pt_mapped_machine_irq[machine_irq]
3180b4ecc8SPaolo Bonzini * - Set assigned_device->machine_irq to '0'.
3280b4ecc8SPaolo Bonzini *
3380b4ecc8SPaolo Bonzini * Write to Interrupt Disable bit by guest software(xen_pt_cmd_reg_write)
3480b4ecc8SPaolo Bonzini * Write '0'
3580b4ecc8SPaolo Bonzini * - Set real bit to '0' if assigned_device->machine_irq isn't '0'.
3680b4ecc8SPaolo Bonzini *
3780b4ecc8SPaolo Bonzini * Write '1'
3880b4ecc8SPaolo Bonzini * - Set real bit to '1'.
3980b4ecc8SPaolo Bonzini *
4080b4ecc8SPaolo Bonzini * MSI interrupt:
4180b4ecc8SPaolo Bonzini * Initialize MSI register(xen_pt_msi_setup, xen_pt_msi_update)
4280b4ecc8SPaolo Bonzini * Bind MSI(xc_domain_update_msi_irq)
4380b4ecc8SPaolo Bonzini * <fail>
4480b4ecc8SPaolo Bonzini * - Unmap MSI.
4580b4ecc8SPaolo Bonzini * - Set dev->msi->pirq to '-1'.
4680b4ecc8SPaolo Bonzini *
4780b4ecc8SPaolo Bonzini * MSI-X interrupt:
4880b4ecc8SPaolo Bonzini * Initialize MSI-X register(xen_pt_msix_update_one)
4980b4ecc8SPaolo Bonzini * Bind MSI-X(xc_domain_update_msi_irq)
5080b4ecc8SPaolo Bonzini * <fail>
5180b4ecc8SPaolo Bonzini * - Unmap MSI-X.
5280b4ecc8SPaolo Bonzini * - Set entry->pirq to '-1'.
5380b4ecc8SPaolo Bonzini */
5480b4ecc8SPaolo Bonzini
5521cbfe5fSPeter Maydell #include "qemu/osdep.h"
56da34e65cSMarkus Armbruster #include "qapi/error.h"
5780b4ecc8SPaolo Bonzini #include <sys/ioctl.h>
5880b4ecc8SPaolo Bonzini
5980b4ecc8SPaolo Bonzini #include "hw/pci/pci.h"
60a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h"
61ce35e229SEduardo Habkost #include "hw/qdev-properties-system.h"
62f28b958cSPhilippe Mathieu-Daudé #include "hw/xen/xen_pt.h"
63f28b958cSPhilippe Mathieu-Daudé #include "hw/xen/xen_igd.h"
6480b4ecc8SPaolo Bonzini #include "hw/xen/xen.h"
652d0ed5e6SPaul Durrant #include "hw/xen/xen-legacy-backend.h"
6680b4ecc8SPaolo Bonzini #include "qemu/range.h"
6780b4ecc8SPaolo Bonzini
68acd0c941SAnthony PERARD static bool has_igd_gfx_passthru;
69acd0c941SAnthony PERARD
xen_igd_gfx_pt_enabled(void)70acd0c941SAnthony PERARD bool xen_igd_gfx_pt_enabled(void)
71acd0c941SAnthony PERARD {
72acd0c941SAnthony PERARD return has_igd_gfx_passthru;
73acd0c941SAnthony PERARD }
74acd0c941SAnthony PERARD
xen_igd_gfx_pt_set(bool value,Error ** errp)75acd0c941SAnthony PERARD void xen_igd_gfx_pt_set(bool value, Error **errp)
76acd0c941SAnthony PERARD {
77acd0c941SAnthony PERARD has_igd_gfx_passthru = value;
78acd0c941SAnthony PERARD }
7946472d82SPaolo Bonzini
8080b4ecc8SPaolo Bonzini #define XEN_PT_NR_IRQS (256)
8180b4ecc8SPaolo Bonzini static uint8_t xen_pt_mapped_machine_irq[XEN_PT_NR_IRQS] = {0};
8280b4ecc8SPaolo Bonzini
xen_pt_log(const PCIDevice * d,const char * f,...)8380b4ecc8SPaolo Bonzini void xen_pt_log(const PCIDevice *d, const char *f, ...)
8480b4ecc8SPaolo Bonzini {
8580b4ecc8SPaolo Bonzini va_list ap;
8680b4ecc8SPaolo Bonzini
8780b4ecc8SPaolo Bonzini va_start(ap, f);
8880b4ecc8SPaolo Bonzini if (d) {
89cdc57472SDavid Gibson fprintf(stderr, "[%02x:%02x.%d] ", pci_dev_bus_num(d),
9080b4ecc8SPaolo Bonzini PCI_SLOT(d->devfn), PCI_FUNC(d->devfn));
9180b4ecc8SPaolo Bonzini }
9280b4ecc8SPaolo Bonzini vfprintf(stderr, f, ap);
9380b4ecc8SPaolo Bonzini va_end(ap);
9480b4ecc8SPaolo Bonzini }
9580b4ecc8SPaolo Bonzini
9680b4ecc8SPaolo Bonzini /* Config Space */
9780b4ecc8SPaolo Bonzini
xen_pt_pci_config_access_check(PCIDevice * d,uint32_t addr,int len)9880b4ecc8SPaolo Bonzini static int xen_pt_pci_config_access_check(PCIDevice *d, uint32_t addr, int len)
9980b4ecc8SPaolo Bonzini {
10080b4ecc8SPaolo Bonzini /* check offset range */
1014daf6259SAnoob Soman if (addr > 0xFF) {
10280b4ecc8SPaolo Bonzini XEN_PT_ERR(d, "Failed to access register with offset exceeding 0xFF. "
10380b4ecc8SPaolo Bonzini "(addr: 0x%02x, len: %d)\n", addr, len);
10480b4ecc8SPaolo Bonzini return -1;
10580b4ecc8SPaolo Bonzini }
10680b4ecc8SPaolo Bonzini
10780b4ecc8SPaolo Bonzini /* check read size */
10880b4ecc8SPaolo Bonzini if ((len != 1) && (len != 2) && (len != 4)) {
10980b4ecc8SPaolo Bonzini XEN_PT_ERR(d, "Failed to access register with invalid access length. "
11080b4ecc8SPaolo Bonzini "(addr: 0x%02x, len: %d)\n", addr, len);
11180b4ecc8SPaolo Bonzini return -1;
11280b4ecc8SPaolo Bonzini }
11380b4ecc8SPaolo Bonzini
11480b4ecc8SPaolo Bonzini /* check offset alignment */
11580b4ecc8SPaolo Bonzini if (addr & (len - 1)) {
11680b4ecc8SPaolo Bonzini XEN_PT_ERR(d, "Failed to access register with invalid access size "
11780b4ecc8SPaolo Bonzini "alignment. (addr: 0x%02x, len: %d)\n", addr, len);
11880b4ecc8SPaolo Bonzini return -1;
11980b4ecc8SPaolo Bonzini }
12080b4ecc8SPaolo Bonzini
12180b4ecc8SPaolo Bonzini return 0;
12280b4ecc8SPaolo Bonzini }
12380b4ecc8SPaolo Bonzini
xen_pt_bar_offset_to_index(uint32_t offset)12480b4ecc8SPaolo Bonzini int xen_pt_bar_offset_to_index(uint32_t offset)
12580b4ecc8SPaolo Bonzini {
12680b4ecc8SPaolo Bonzini int index = 0;
12780b4ecc8SPaolo Bonzini
12880b4ecc8SPaolo Bonzini /* check Exp ROM BAR */
12980b4ecc8SPaolo Bonzini if (offset == PCI_ROM_ADDRESS) {
13080b4ecc8SPaolo Bonzini return PCI_ROM_SLOT;
13180b4ecc8SPaolo Bonzini }
13280b4ecc8SPaolo Bonzini
13380b4ecc8SPaolo Bonzini /* calculate BAR index */
13480b4ecc8SPaolo Bonzini index = (offset - PCI_BASE_ADDRESS_0) >> 2;
13580b4ecc8SPaolo Bonzini if (index >= PCI_NUM_REGIONS) {
13680b4ecc8SPaolo Bonzini return -1;
13780b4ecc8SPaolo Bonzini }
13880b4ecc8SPaolo Bonzini
13980b4ecc8SPaolo Bonzini return index;
14080b4ecc8SPaolo Bonzini }
14180b4ecc8SPaolo Bonzini
xen_pt_pci_read_config(PCIDevice * d,uint32_t addr,int len)14280b4ecc8SPaolo Bonzini static uint32_t xen_pt_pci_read_config(PCIDevice *d, uint32_t addr, int len)
14380b4ecc8SPaolo Bonzini {
144f9b9d292SGonglei XenPCIPassthroughState *s = XEN_PT_DEVICE(d);
14580b4ecc8SPaolo Bonzini uint32_t val = 0;
14680b4ecc8SPaolo Bonzini XenPTRegGroup *reg_grp_entry = NULL;
14780b4ecc8SPaolo Bonzini XenPTReg *reg_entry = NULL;
14880b4ecc8SPaolo Bonzini int rc = 0;
14980b4ecc8SPaolo Bonzini int emul_len = 0;
15080b4ecc8SPaolo Bonzini uint32_t find_addr = addr;
15180b4ecc8SPaolo Bonzini
15280b4ecc8SPaolo Bonzini if (xen_pt_pci_config_access_check(d, addr, len)) {
15380b4ecc8SPaolo Bonzini goto exit;
15480b4ecc8SPaolo Bonzini }
15580b4ecc8SPaolo Bonzini
15680b4ecc8SPaolo Bonzini /* find register group entry */
15780b4ecc8SPaolo Bonzini reg_grp_entry = xen_pt_find_reg_grp(s, addr);
15880b4ecc8SPaolo Bonzini if (reg_grp_entry) {
15980b4ecc8SPaolo Bonzini /* check 0-Hardwired register group */
16080b4ecc8SPaolo Bonzini if (reg_grp_entry->reg_grp->grp_type == XEN_PT_GRP_TYPE_HARDWIRED) {
16180b4ecc8SPaolo Bonzini /* no need to emulate, just return 0 */
16280b4ecc8SPaolo Bonzini val = 0;
16380b4ecc8SPaolo Bonzini goto exit;
16480b4ecc8SPaolo Bonzini }
16580b4ecc8SPaolo Bonzini }
16680b4ecc8SPaolo Bonzini
16780b4ecc8SPaolo Bonzini /* read I/O device register value */
16880b4ecc8SPaolo Bonzini rc = xen_host_pci_get_block(&s->real_device, addr, (uint8_t *)&val, len);
16980b4ecc8SPaolo Bonzini if (rc < 0) {
17080b4ecc8SPaolo Bonzini XEN_PT_ERR(d, "pci_read_block failed. return value: %d.\n", rc);
17180b4ecc8SPaolo Bonzini memset(&val, 0xff, len);
17280b4ecc8SPaolo Bonzini }
17380b4ecc8SPaolo Bonzini
17480b4ecc8SPaolo Bonzini /* just return the I/O device register value for
17580b4ecc8SPaolo Bonzini * passthrough type register group */
17680b4ecc8SPaolo Bonzini if (reg_grp_entry == NULL) {
17780b4ecc8SPaolo Bonzini goto exit;
17880b4ecc8SPaolo Bonzini }
17980b4ecc8SPaolo Bonzini
18080b4ecc8SPaolo Bonzini /* adjust the read value to appropriate CFC-CFF window */
18180b4ecc8SPaolo Bonzini val <<= (addr & 3) << 3;
18280b4ecc8SPaolo Bonzini emul_len = len;
18380b4ecc8SPaolo Bonzini
18480b4ecc8SPaolo Bonzini /* loop around the guest requested size */
18580b4ecc8SPaolo Bonzini while (emul_len > 0) {
18680b4ecc8SPaolo Bonzini /* find register entry to be emulated */
18780b4ecc8SPaolo Bonzini reg_entry = xen_pt_find_reg(reg_grp_entry, find_addr);
18880b4ecc8SPaolo Bonzini if (reg_entry) {
18980b4ecc8SPaolo Bonzini XenPTRegInfo *reg = reg_entry->reg;
19080b4ecc8SPaolo Bonzini uint32_t real_offset = reg_grp_entry->base_offset + reg->offset;
19180b4ecc8SPaolo Bonzini uint32_t valid_mask = 0xFFFFFFFF >> ((4 - emul_len) << 3);
19280b4ecc8SPaolo Bonzini uint8_t *ptr_val = NULL;
19380b4ecc8SPaolo Bonzini
19480b4ecc8SPaolo Bonzini valid_mask <<= (find_addr - real_offset) << 3;
19580b4ecc8SPaolo Bonzini ptr_val = (uint8_t *)&val + (real_offset & 3);
19680b4ecc8SPaolo Bonzini
19780b4ecc8SPaolo Bonzini /* do emulation based on register size */
19880b4ecc8SPaolo Bonzini switch (reg->size) {
19980b4ecc8SPaolo Bonzini case 1:
20080b4ecc8SPaolo Bonzini if (reg->u.b.read) {
20180b4ecc8SPaolo Bonzini rc = reg->u.b.read(s, reg_entry, ptr_val, valid_mask);
20280b4ecc8SPaolo Bonzini }
20380b4ecc8SPaolo Bonzini break;
20480b4ecc8SPaolo Bonzini case 2:
20580b4ecc8SPaolo Bonzini if (reg->u.w.read) {
20680b4ecc8SPaolo Bonzini rc = reg->u.w.read(s, reg_entry,
20780b4ecc8SPaolo Bonzini (uint16_t *)ptr_val, valid_mask);
20880b4ecc8SPaolo Bonzini }
20980b4ecc8SPaolo Bonzini break;
21080b4ecc8SPaolo Bonzini case 4:
21180b4ecc8SPaolo Bonzini if (reg->u.dw.read) {
21280b4ecc8SPaolo Bonzini rc = reg->u.dw.read(s, reg_entry,
21380b4ecc8SPaolo Bonzini (uint32_t *)ptr_val, valid_mask);
21480b4ecc8SPaolo Bonzini }
21580b4ecc8SPaolo Bonzini break;
21680b4ecc8SPaolo Bonzini }
21780b4ecc8SPaolo Bonzini
21880b4ecc8SPaolo Bonzini if (rc < 0) {
21980b4ecc8SPaolo Bonzini xen_shutdown_fatal_error("Internal error: Invalid read "
22080b4ecc8SPaolo Bonzini "emulation. (%s, rc: %d)\n",
22180b4ecc8SPaolo Bonzini __func__, rc);
22280b4ecc8SPaolo Bonzini return 0;
22380b4ecc8SPaolo Bonzini }
22480b4ecc8SPaolo Bonzini
22580b4ecc8SPaolo Bonzini /* calculate next address to find */
22680b4ecc8SPaolo Bonzini emul_len -= reg->size;
22780b4ecc8SPaolo Bonzini if (emul_len > 0) {
22880b4ecc8SPaolo Bonzini find_addr = real_offset + reg->size;
22980b4ecc8SPaolo Bonzini }
23080b4ecc8SPaolo Bonzini } else {
23180b4ecc8SPaolo Bonzini /* nothing to do with passthrough type register,
23280b4ecc8SPaolo Bonzini * continue to find next byte */
23380b4ecc8SPaolo Bonzini emul_len--;
23480b4ecc8SPaolo Bonzini find_addr++;
23580b4ecc8SPaolo Bonzini }
23680b4ecc8SPaolo Bonzini }
23780b4ecc8SPaolo Bonzini
23880b4ecc8SPaolo Bonzini /* need to shift back before returning them to pci bus emulator */
23980b4ecc8SPaolo Bonzini val >>= ((addr & 3) << 3);
24080b4ecc8SPaolo Bonzini
24180b4ecc8SPaolo Bonzini exit:
24280b4ecc8SPaolo Bonzini XEN_PT_LOG_CONFIG(d, addr, val, len);
24380b4ecc8SPaolo Bonzini return val;
24480b4ecc8SPaolo Bonzini }
24580b4ecc8SPaolo Bonzini
xen_pt_pci_write_config(PCIDevice * d,uint32_t addr,uint32_t val,int len)24680b4ecc8SPaolo Bonzini static void xen_pt_pci_write_config(PCIDevice *d, uint32_t addr,
24780b4ecc8SPaolo Bonzini uint32_t val, int len)
24880b4ecc8SPaolo Bonzini {
249f9b9d292SGonglei XenPCIPassthroughState *s = XEN_PT_DEVICE(d);
25080b4ecc8SPaolo Bonzini int index = 0;
25180b4ecc8SPaolo Bonzini XenPTRegGroup *reg_grp_entry = NULL;
25280b4ecc8SPaolo Bonzini int rc = 0;
2535c83b2f5SJan Beulich uint32_t read_val = 0, wb_mask;
25480b4ecc8SPaolo Bonzini int emul_len = 0;
25580b4ecc8SPaolo Bonzini XenPTReg *reg_entry = NULL;
25680b4ecc8SPaolo Bonzini uint32_t find_addr = addr;
25780b4ecc8SPaolo Bonzini XenPTRegInfo *reg = NULL;
258c25bbf15SJan Beulich bool wp_flag = false;
25980b4ecc8SPaolo Bonzini
26080b4ecc8SPaolo Bonzini if (xen_pt_pci_config_access_check(d, addr, len)) {
26180b4ecc8SPaolo Bonzini return;
26280b4ecc8SPaolo Bonzini }
26380b4ecc8SPaolo Bonzini
26480b4ecc8SPaolo Bonzini XEN_PT_LOG_CONFIG(d, addr, val, len);
26580b4ecc8SPaolo Bonzini
26680b4ecc8SPaolo Bonzini /* check unused BAR register */
26780b4ecc8SPaolo Bonzini index = xen_pt_bar_offset_to_index(addr);
26869976894SJan Beulich if ((index >= 0) && (val != 0)) {
26969976894SJan Beulich uint32_t chk = val;
27069976894SJan Beulich
27169976894SJan Beulich if (index == PCI_ROM_SLOT)
27269976894SJan Beulich chk |= (uint32_t)~PCI_ROM_ADDRESS_MASK;
27369976894SJan Beulich
27469976894SJan Beulich if ((chk != XEN_PT_BAR_ALLF) &&
27580b4ecc8SPaolo Bonzini (s->bases[index].bar_flag == XEN_PT_BAR_FLAG_UNUSED)) {
27669976894SJan Beulich XEN_PT_WARN(d, "Guest attempt to set address to unused "
27769976894SJan Beulich "Base Address Register. (addr: 0x%02x, len: %d)\n",
27869976894SJan Beulich addr, len);
27969976894SJan Beulich }
28080b4ecc8SPaolo Bonzini }
28180b4ecc8SPaolo Bonzini
28280b4ecc8SPaolo Bonzini /* find register group entry */
28380b4ecc8SPaolo Bonzini reg_grp_entry = xen_pt_find_reg_grp(s, addr);
28480b4ecc8SPaolo Bonzini if (reg_grp_entry) {
28580b4ecc8SPaolo Bonzini /* check 0-Hardwired register group */
28680b4ecc8SPaolo Bonzini if (reg_grp_entry->reg_grp->grp_type == XEN_PT_GRP_TYPE_HARDWIRED) {
28780b4ecc8SPaolo Bonzini /* ignore silently */
28880b4ecc8SPaolo Bonzini XEN_PT_WARN(d, "Access to 0-Hardwired register. "
28980b4ecc8SPaolo Bonzini "(addr: 0x%02x, len: %d)\n", addr, len);
29080b4ecc8SPaolo Bonzini return;
29180b4ecc8SPaolo Bonzini }
29280b4ecc8SPaolo Bonzini }
29380b4ecc8SPaolo Bonzini
29480b4ecc8SPaolo Bonzini rc = xen_host_pci_get_block(&s->real_device, addr,
29580b4ecc8SPaolo Bonzini (uint8_t *)&read_val, len);
29680b4ecc8SPaolo Bonzini if (rc < 0) {
29780b4ecc8SPaolo Bonzini XEN_PT_ERR(d, "pci_read_block failed. return value: %d.\n", rc);
29880b4ecc8SPaolo Bonzini memset(&read_val, 0xff, len);
2995c83b2f5SJan Beulich wb_mask = 0;
3005c83b2f5SJan Beulich } else {
3015c83b2f5SJan Beulich wb_mask = 0xFFFFFFFF >> ((4 - len) << 3);
30280b4ecc8SPaolo Bonzini }
30380b4ecc8SPaolo Bonzini
30480b4ecc8SPaolo Bonzini /* pass directly to the real device for passthrough type register group */
30580b4ecc8SPaolo Bonzini if (reg_grp_entry == NULL) {
306c25bbf15SJan Beulich if (!s->permissive) {
307c25bbf15SJan Beulich wb_mask = 0;
308c25bbf15SJan Beulich wp_flag = true;
309c25bbf15SJan Beulich }
31080b4ecc8SPaolo Bonzini goto out;
31180b4ecc8SPaolo Bonzini }
31280b4ecc8SPaolo Bonzini
31380b4ecc8SPaolo Bonzini memory_region_transaction_begin();
31480b4ecc8SPaolo Bonzini pci_default_write_config(d, addr, val, len);
31580b4ecc8SPaolo Bonzini
31680b4ecc8SPaolo Bonzini /* adjust the read and write value to appropriate CFC-CFF window */
31780b4ecc8SPaolo Bonzini read_val <<= (addr & 3) << 3;
31880b4ecc8SPaolo Bonzini val <<= (addr & 3) << 3;
31980b4ecc8SPaolo Bonzini emul_len = len;
32080b4ecc8SPaolo Bonzini
32180b4ecc8SPaolo Bonzini /* loop around the guest requested size */
32280b4ecc8SPaolo Bonzini while (emul_len > 0) {
32380b4ecc8SPaolo Bonzini /* find register entry to be emulated */
32480b4ecc8SPaolo Bonzini reg_entry = xen_pt_find_reg(reg_grp_entry, find_addr);
32580b4ecc8SPaolo Bonzini if (reg_entry) {
32680b4ecc8SPaolo Bonzini reg = reg_entry->reg;
32780b4ecc8SPaolo Bonzini uint32_t real_offset = reg_grp_entry->base_offset + reg->offset;
32880b4ecc8SPaolo Bonzini uint32_t valid_mask = 0xFFFFFFFF >> ((4 - emul_len) << 3);
32980b4ecc8SPaolo Bonzini uint8_t *ptr_val = NULL;
330c25bbf15SJan Beulich uint32_t wp_mask = reg->emu_mask | reg->ro_mask;
33180b4ecc8SPaolo Bonzini
33280b4ecc8SPaolo Bonzini valid_mask <<= (find_addr - real_offset) << 3;
33380b4ecc8SPaolo Bonzini ptr_val = (uint8_t *)&val + (real_offset & 3);
334c25bbf15SJan Beulich if (!s->permissive) {
335c25bbf15SJan Beulich wp_mask |= reg->res_mask;
336c25bbf15SJan Beulich }
337c25bbf15SJan Beulich if (wp_mask == (0xFFFFFFFF >> ((4 - reg->size) << 3))) {
338c25bbf15SJan Beulich wb_mask &= ~((wp_mask >> ((find_addr - real_offset) << 3))
3395c83b2f5SJan Beulich << ((len - emul_len) << 3));
3405c83b2f5SJan Beulich }
34180b4ecc8SPaolo Bonzini
34280b4ecc8SPaolo Bonzini /* do emulation based on register size */
34380b4ecc8SPaolo Bonzini switch (reg->size) {
34480b4ecc8SPaolo Bonzini case 1:
34580b4ecc8SPaolo Bonzini if (reg->u.b.write) {
34680b4ecc8SPaolo Bonzini rc = reg->u.b.write(s, reg_entry, ptr_val,
34780b4ecc8SPaolo Bonzini read_val >> ((real_offset & 3) << 3),
34880b4ecc8SPaolo Bonzini valid_mask);
34980b4ecc8SPaolo Bonzini }
35080b4ecc8SPaolo Bonzini break;
35180b4ecc8SPaolo Bonzini case 2:
35280b4ecc8SPaolo Bonzini if (reg->u.w.write) {
35380b4ecc8SPaolo Bonzini rc = reg->u.w.write(s, reg_entry, (uint16_t *)ptr_val,
35480b4ecc8SPaolo Bonzini (read_val >> ((real_offset & 3) << 3)),
35580b4ecc8SPaolo Bonzini valid_mask);
35680b4ecc8SPaolo Bonzini }
35780b4ecc8SPaolo Bonzini break;
35880b4ecc8SPaolo Bonzini case 4:
35980b4ecc8SPaolo Bonzini if (reg->u.dw.write) {
36080b4ecc8SPaolo Bonzini rc = reg->u.dw.write(s, reg_entry, (uint32_t *)ptr_val,
36180b4ecc8SPaolo Bonzini (read_val >> ((real_offset & 3) << 3)),
36280b4ecc8SPaolo Bonzini valid_mask);
36380b4ecc8SPaolo Bonzini }
36480b4ecc8SPaolo Bonzini break;
36580b4ecc8SPaolo Bonzini }
36680b4ecc8SPaolo Bonzini
36780b4ecc8SPaolo Bonzini if (rc < 0) {
36880b4ecc8SPaolo Bonzini xen_shutdown_fatal_error("Internal error: Invalid write"
36980b4ecc8SPaolo Bonzini " emulation. (%s, rc: %d)\n",
37080b4ecc8SPaolo Bonzini __func__, rc);
37180b4ecc8SPaolo Bonzini return;
37280b4ecc8SPaolo Bonzini }
37380b4ecc8SPaolo Bonzini
37480b4ecc8SPaolo Bonzini /* calculate next address to find */
37580b4ecc8SPaolo Bonzini emul_len -= reg->size;
37680b4ecc8SPaolo Bonzini if (emul_len > 0) {
37780b4ecc8SPaolo Bonzini find_addr = real_offset + reg->size;
37880b4ecc8SPaolo Bonzini }
37980b4ecc8SPaolo Bonzini } else {
38080b4ecc8SPaolo Bonzini /* nothing to do with passthrough type register,
38180b4ecc8SPaolo Bonzini * continue to find next byte */
382c25bbf15SJan Beulich if (!s->permissive) {
383c25bbf15SJan Beulich wb_mask &= ~(0xff << ((len - emul_len) << 3));
384c25bbf15SJan Beulich /* Unused BARs will make it here, but we don't want to issue
385c25bbf15SJan Beulich * warnings for writes to them (bogus writes get dealt with
386c25bbf15SJan Beulich * above).
387c25bbf15SJan Beulich */
388c25bbf15SJan Beulich if (index < 0) {
389c25bbf15SJan Beulich wp_flag = true;
390c25bbf15SJan Beulich }
391c25bbf15SJan Beulich }
39280b4ecc8SPaolo Bonzini emul_len--;
39380b4ecc8SPaolo Bonzini find_addr++;
39480b4ecc8SPaolo Bonzini }
39580b4ecc8SPaolo Bonzini }
39680b4ecc8SPaolo Bonzini
397d3b9facbSKonrad Rzeszutek Wilk /* need to shift back before passing them to xen_host_pci_set_block. */
39880b4ecc8SPaolo Bonzini val >>= (addr & 3) << 3;
39980b4ecc8SPaolo Bonzini
40080b4ecc8SPaolo Bonzini memory_region_transaction_commit();
40180b4ecc8SPaolo Bonzini
40280b4ecc8SPaolo Bonzini out:
403c25bbf15SJan Beulich if (wp_flag && !s->permissive_warned) {
404c25bbf15SJan Beulich s->permissive_warned = true;
405c25bbf15SJan Beulich xen_pt_log(d, "Write-back to unknown field 0x%02x (partially) inhibited (0x%0*x)\n",
406c25bbf15SJan Beulich addr, len * 2, wb_mask);
407c25bbf15SJan Beulich xen_pt_log(d, "If the device doesn't work, try enabling permissive mode\n");
408c25bbf15SJan Beulich xen_pt_log(d, "(unsafe) and if it helps report the problem to xen-devel\n");
409c25bbf15SJan Beulich }
4105c83b2f5SJan Beulich for (index = 0; wb_mask; index += len) {
41180b4ecc8SPaolo Bonzini /* unknown regs are passed through */
4125c83b2f5SJan Beulich while (!(wb_mask & 0xff)) {
4135c83b2f5SJan Beulich index++;
4145c83b2f5SJan Beulich wb_mask >>= 8;
4155c83b2f5SJan Beulich }
4165c83b2f5SJan Beulich len = 0;
4175c83b2f5SJan Beulich do {
4185c83b2f5SJan Beulich len++;
4195c83b2f5SJan Beulich wb_mask >>= 8;
4205c83b2f5SJan Beulich } while (wb_mask & 0xff);
4215c83b2f5SJan Beulich rc = xen_host_pci_set_block(&s->real_device, addr + index,
4225c83b2f5SJan Beulich (uint8_t *)&val + index, len);
42380b4ecc8SPaolo Bonzini
42480b4ecc8SPaolo Bonzini if (rc < 0) {
425d3b9facbSKonrad Rzeszutek Wilk XEN_PT_ERR(d, "xen_host_pci_set_block failed. return value: %d.\n", rc);
42680b4ecc8SPaolo Bonzini }
42780b4ecc8SPaolo Bonzini }
42880b4ecc8SPaolo Bonzini }
42980b4ecc8SPaolo Bonzini
43080b4ecc8SPaolo Bonzini /* register regions */
43180b4ecc8SPaolo Bonzini
xen_pt_bar_read(void * o,hwaddr addr,unsigned size)43280b4ecc8SPaolo Bonzini static uint64_t xen_pt_bar_read(void *o, hwaddr addr,
43380b4ecc8SPaolo Bonzini unsigned size)
43480b4ecc8SPaolo Bonzini {
43580b4ecc8SPaolo Bonzini PCIDevice *d = o;
43680b4ecc8SPaolo Bonzini /* if this function is called, that probably means that there is a
43780b4ecc8SPaolo Bonzini * misconfiguration of the IOMMU. */
438883f2c59SPhilippe Mathieu-Daudé XEN_PT_ERR(d, "Should not read BAR through QEMU. @0x"HWADDR_FMT_plx"\n",
43980b4ecc8SPaolo Bonzini addr);
44080b4ecc8SPaolo Bonzini return 0;
44180b4ecc8SPaolo Bonzini }
xen_pt_bar_write(void * o,hwaddr addr,uint64_t val,unsigned size)44280b4ecc8SPaolo Bonzini static void xen_pt_bar_write(void *o, hwaddr addr, uint64_t val,
44380b4ecc8SPaolo Bonzini unsigned size)
44480b4ecc8SPaolo Bonzini {
44580b4ecc8SPaolo Bonzini PCIDevice *d = o;
44680b4ecc8SPaolo Bonzini /* Same comment as xen_pt_bar_read function */
447883f2c59SPhilippe Mathieu-Daudé XEN_PT_ERR(d, "Should not write BAR through QEMU. @0x"HWADDR_FMT_plx"\n",
44880b4ecc8SPaolo Bonzini addr);
44980b4ecc8SPaolo Bonzini }
45080b4ecc8SPaolo Bonzini
45180b4ecc8SPaolo Bonzini static const MemoryRegionOps ops = {
45280b4ecc8SPaolo Bonzini .endianness = DEVICE_NATIVE_ENDIAN,
45380b4ecc8SPaolo Bonzini .read = xen_pt_bar_read,
45480b4ecc8SPaolo Bonzini .write = xen_pt_bar_write,
45580b4ecc8SPaolo Bonzini };
45680b4ecc8SPaolo Bonzini
xen_pt_register_regions(XenPCIPassthroughState * s,uint16_t * cmd)45781b23ef8SJan Beulich static int xen_pt_register_regions(XenPCIPassthroughState *s, uint16_t *cmd)
45880b4ecc8SPaolo Bonzini {
45980b4ecc8SPaolo Bonzini int i = 0;
46080b4ecc8SPaolo Bonzini XenHostPCIDevice *d = &s->real_device;
46180b4ecc8SPaolo Bonzini
46280b4ecc8SPaolo Bonzini /* Register PIO/MMIO BARs */
46380b4ecc8SPaolo Bonzini for (i = 0; i < PCI_ROM_SLOT; i++) {
46480b4ecc8SPaolo Bonzini XenHostPCIIORegion *r = &d->io_regions[i];
46580b4ecc8SPaolo Bonzini uint8_t type;
46680b4ecc8SPaolo Bonzini
46780b4ecc8SPaolo Bonzini if (r->base_addr == 0 || r->size == 0) {
46880b4ecc8SPaolo Bonzini continue;
46980b4ecc8SPaolo Bonzini }
47080b4ecc8SPaolo Bonzini
47180b4ecc8SPaolo Bonzini s->bases[i].access.u = r->base_addr;
47280b4ecc8SPaolo Bonzini
47380b4ecc8SPaolo Bonzini if (r->type & XEN_HOST_PCI_REGION_TYPE_IO) {
47480b4ecc8SPaolo Bonzini type = PCI_BASE_ADDRESS_SPACE_IO;
47581b23ef8SJan Beulich *cmd |= PCI_COMMAND_IO;
47680b4ecc8SPaolo Bonzini } else {
47780b4ecc8SPaolo Bonzini type = PCI_BASE_ADDRESS_SPACE_MEMORY;
47880b4ecc8SPaolo Bonzini if (r->type & XEN_HOST_PCI_REGION_TYPE_PREFETCH) {
47980b4ecc8SPaolo Bonzini type |= PCI_BASE_ADDRESS_MEM_PREFETCH;
48080b4ecc8SPaolo Bonzini }
48180b4ecc8SPaolo Bonzini if (r->type & XEN_HOST_PCI_REGION_TYPE_MEM_64) {
48280b4ecc8SPaolo Bonzini type |= PCI_BASE_ADDRESS_MEM_TYPE_64;
48380b4ecc8SPaolo Bonzini }
48481b23ef8SJan Beulich *cmd |= PCI_COMMAND_MEMORY;
48580b4ecc8SPaolo Bonzini }
48680b4ecc8SPaolo Bonzini
48722fc860bSPaolo Bonzini memory_region_init_io(&s->bar[i], OBJECT(s), &ops, &s->dev,
48880b4ecc8SPaolo Bonzini "xen-pci-pt-bar", r->size);
48980b4ecc8SPaolo Bonzini pci_register_bar(&s->dev, i, type, &s->bar[i]);
49080b4ecc8SPaolo Bonzini
491fc33b900SAnthony PERARD XEN_PT_LOG(&s->dev, "IO region %i registered (size=0x%08"PRIx64
49201d152c0SXinhao Zhang " base_addr=0x%08"PRIx64" type: 0x%x)\n",
49380b4ecc8SPaolo Bonzini i, r->size, r->base_addr, type);
49480b4ecc8SPaolo Bonzini }
49580b4ecc8SPaolo Bonzini
49680b4ecc8SPaolo Bonzini /* Register expansion ROM address */
49780b4ecc8SPaolo Bonzini if (d->rom.base_addr && d->rom.size) {
49880b4ecc8SPaolo Bonzini uint32_t bar_data = 0;
49980b4ecc8SPaolo Bonzini
50080b4ecc8SPaolo Bonzini /* Re-set BAR reported by OS, otherwise ROM can't be read. */
50180b4ecc8SPaolo Bonzini if (xen_host_pci_get_long(d, PCI_ROM_ADDRESS, &bar_data)) {
50280b4ecc8SPaolo Bonzini return 0;
50380b4ecc8SPaolo Bonzini }
50480b4ecc8SPaolo Bonzini if ((bar_data & PCI_ROM_ADDRESS_MASK) == 0) {
50580b4ecc8SPaolo Bonzini bar_data |= d->rom.base_addr & PCI_ROM_ADDRESS_MASK;
50680b4ecc8SPaolo Bonzini xen_host_pci_set_long(d, PCI_ROM_ADDRESS, bar_data);
50780b4ecc8SPaolo Bonzini }
50880b4ecc8SPaolo Bonzini
50980b4ecc8SPaolo Bonzini s->bases[PCI_ROM_SLOT].access.maddr = d->rom.base_addr;
51080b4ecc8SPaolo Bonzini
511794798e3SAnthony PERARD memory_region_init_io(&s->rom, OBJECT(s), &ops, &s->dev,
51280b4ecc8SPaolo Bonzini "xen-pci-pt-rom", d->rom.size);
51380b4ecc8SPaolo Bonzini pci_register_bar(&s->dev, PCI_ROM_SLOT, PCI_BASE_ADDRESS_MEM_PREFETCH,
51480b4ecc8SPaolo Bonzini &s->rom);
51580b4ecc8SPaolo Bonzini
51680b4ecc8SPaolo Bonzini XEN_PT_LOG(&s->dev, "Expansion ROM registered (size=0x%08"PRIx64
51780b4ecc8SPaolo Bonzini " base_addr=0x%08"PRIx64")\n",
51880b4ecc8SPaolo Bonzini d->rom.size, d->rom.base_addr);
51980b4ecc8SPaolo Bonzini }
52080b4ecc8SPaolo Bonzini
52179814179STiejun Chen xen_pt_register_vga_regions(d);
52280b4ecc8SPaolo Bonzini return 0;
52380b4ecc8SPaolo Bonzini }
52480b4ecc8SPaolo Bonzini
52580b4ecc8SPaolo Bonzini /* region mapping */
52680b4ecc8SPaolo Bonzini
xen_pt_bar_from_region(XenPCIPassthroughState * s,MemoryRegion * mr)52780b4ecc8SPaolo Bonzini static int xen_pt_bar_from_region(XenPCIPassthroughState *s, MemoryRegion *mr)
52880b4ecc8SPaolo Bonzini {
52980b4ecc8SPaolo Bonzini int i = 0;
53080b4ecc8SPaolo Bonzini
53180b4ecc8SPaolo Bonzini for (i = 0; i < PCI_NUM_REGIONS - 1; i++) {
53280b4ecc8SPaolo Bonzini if (mr == &s->bar[i]) {
53380b4ecc8SPaolo Bonzini return i;
53480b4ecc8SPaolo Bonzini }
53580b4ecc8SPaolo Bonzini }
53680b4ecc8SPaolo Bonzini if (mr == &s->rom) {
53780b4ecc8SPaolo Bonzini return PCI_ROM_SLOT;
53880b4ecc8SPaolo Bonzini }
53980b4ecc8SPaolo Bonzini return -1;
54080b4ecc8SPaolo Bonzini }
54180b4ecc8SPaolo Bonzini
54280b4ecc8SPaolo Bonzini /*
54380b4ecc8SPaolo Bonzini * This function checks if an io_region overlaps an io_region from another
54480b4ecc8SPaolo Bonzini * device. The io_region to check is provided with (addr, size and type)
54580b4ecc8SPaolo Bonzini * A callback can be provided and will be called for every region that is
54680b4ecc8SPaolo Bonzini * overlapped.
54780b4ecc8SPaolo Bonzini * The return value indicates if the region is overlappsed */
54880b4ecc8SPaolo Bonzini struct CheckBarArgs {
54980b4ecc8SPaolo Bonzini XenPCIPassthroughState *s;
55080b4ecc8SPaolo Bonzini pcibus_t addr;
55180b4ecc8SPaolo Bonzini pcibus_t size;
55280b4ecc8SPaolo Bonzini uint8_t type;
55380b4ecc8SPaolo Bonzini bool rc;
55480b4ecc8SPaolo Bonzini };
xen_pt_check_bar_overlap(PCIBus * bus,PCIDevice * d,void * opaque)55580b4ecc8SPaolo Bonzini static void xen_pt_check_bar_overlap(PCIBus *bus, PCIDevice *d, void *opaque)
55680b4ecc8SPaolo Bonzini {
55780b4ecc8SPaolo Bonzini struct CheckBarArgs *arg = opaque;
55880b4ecc8SPaolo Bonzini XenPCIPassthroughState *s = arg->s;
55980b4ecc8SPaolo Bonzini uint8_t type = arg->type;
56080b4ecc8SPaolo Bonzini int i;
56180b4ecc8SPaolo Bonzini
56280b4ecc8SPaolo Bonzini if (d->devfn == s->dev.devfn) {
56380b4ecc8SPaolo Bonzini return;
56480b4ecc8SPaolo Bonzini }
56580b4ecc8SPaolo Bonzini
56680b4ecc8SPaolo Bonzini /* xxx: This ignores bridges. */
56780b4ecc8SPaolo Bonzini for (i = 0; i < PCI_NUM_REGIONS; i++) {
56880b4ecc8SPaolo Bonzini const PCIIORegion *r = &d->io_regions[i];
56980b4ecc8SPaolo Bonzini
57080b4ecc8SPaolo Bonzini if (!r->size) {
57180b4ecc8SPaolo Bonzini continue;
57280b4ecc8SPaolo Bonzini }
57380b4ecc8SPaolo Bonzini if ((type & PCI_BASE_ADDRESS_SPACE_IO)
57480b4ecc8SPaolo Bonzini != (r->type & PCI_BASE_ADDRESS_SPACE_IO)) {
57580b4ecc8SPaolo Bonzini continue;
57680b4ecc8SPaolo Bonzini }
57780b4ecc8SPaolo Bonzini
57880b4ecc8SPaolo Bonzini if (ranges_overlap(arg->addr, arg->size, r->addr, r->size)) {
57980b4ecc8SPaolo Bonzini XEN_PT_WARN(&s->dev,
58080b4ecc8SPaolo Bonzini "Overlapped to device [%02x:%02x.%d] Region: %i"
58101d152c0SXinhao Zhang " (addr: 0x%"FMT_PCIBUS", len: 0x%"FMT_PCIBUS")\n",
58280b4ecc8SPaolo Bonzini pci_bus_num(bus), PCI_SLOT(d->devfn),
58380b4ecc8SPaolo Bonzini PCI_FUNC(d->devfn), i, r->addr, r->size);
58480b4ecc8SPaolo Bonzini arg->rc = true;
58580b4ecc8SPaolo Bonzini }
58680b4ecc8SPaolo Bonzini }
58780b4ecc8SPaolo Bonzini }
58880b4ecc8SPaolo Bonzini
xen_pt_region_update(XenPCIPassthroughState * s,MemoryRegionSection * sec,bool adding)58980b4ecc8SPaolo Bonzini static void xen_pt_region_update(XenPCIPassthroughState *s,
59080b4ecc8SPaolo Bonzini MemoryRegionSection *sec, bool adding)
59180b4ecc8SPaolo Bonzini {
59280b4ecc8SPaolo Bonzini PCIDevice *d = &s->dev;
59380b4ecc8SPaolo Bonzini MemoryRegion *mr = sec->mr;
59480b4ecc8SPaolo Bonzini int bar = -1;
59580b4ecc8SPaolo Bonzini int rc;
59680b4ecc8SPaolo Bonzini int op = adding ? DPCI_ADD_MAPPING : DPCI_REMOVE_MAPPING;
59780b4ecc8SPaolo Bonzini struct CheckBarArgs args = {
59880b4ecc8SPaolo Bonzini .s = s,
59980b4ecc8SPaolo Bonzini .addr = sec->offset_within_address_space,
600052e87b0SPaolo Bonzini .size = int128_get64(sec->size),
60180b4ecc8SPaolo Bonzini .rc = false,
60280b4ecc8SPaolo Bonzini };
60380b4ecc8SPaolo Bonzini
60480b4ecc8SPaolo Bonzini bar = xen_pt_bar_from_region(s, mr);
60580b4ecc8SPaolo Bonzini if (bar == -1 && (!s->msix || &s->msix->mmio != mr)) {
60680b4ecc8SPaolo Bonzini return;
60780b4ecc8SPaolo Bonzini }
60880b4ecc8SPaolo Bonzini
60980b4ecc8SPaolo Bonzini if (s->msix && &s->msix->mmio == mr) {
61080b4ecc8SPaolo Bonzini if (adding) {
61180b4ecc8SPaolo Bonzini s->msix->mmio_base_addr = sec->offset_within_address_space;
61280b4ecc8SPaolo Bonzini rc = xen_pt_msix_update_remap(s, s->msix->bar_index);
61380b4ecc8SPaolo Bonzini }
61480b4ecc8SPaolo Bonzini return;
61580b4ecc8SPaolo Bonzini }
61680b4ecc8SPaolo Bonzini
61780b4ecc8SPaolo Bonzini args.type = d->io_regions[bar].type;
6182914fc61SPeter Xu pci_for_each_device_under_bus(pci_get_bus(d),
61980b4ecc8SPaolo Bonzini xen_pt_check_bar_overlap, &args);
62080b4ecc8SPaolo Bonzini if (args.rc) {
62101d152c0SXinhao Zhang XEN_PT_WARN(d, "Region: %d (addr: 0x%"FMT_PCIBUS
62201d152c0SXinhao Zhang ", len: 0x%"FMT_PCIBUS") is overlapped.\n",
623d18e173aSWei Liu bar, sec->offset_within_address_space,
624d18e173aSWei Liu int128_get64(sec->size));
62580b4ecc8SPaolo Bonzini }
62680b4ecc8SPaolo Bonzini
62780b4ecc8SPaolo Bonzini if (d->io_regions[bar].type & PCI_BASE_ADDRESS_SPACE_IO) {
62880b4ecc8SPaolo Bonzini uint32_t guest_port = sec->offset_within_address_space;
62980b4ecc8SPaolo Bonzini uint32_t machine_port = s->bases[bar].access.pio_base;
630052e87b0SPaolo Bonzini uint32_t size = int128_get64(sec->size);
63180b4ecc8SPaolo Bonzini rc = xc_domain_ioport_mapping(xen_xc, xen_domid,
63280b4ecc8SPaolo Bonzini guest_port, machine_port, size,
63380b4ecc8SPaolo Bonzini op);
63480b4ecc8SPaolo Bonzini if (rc) {
6353782f60dSJan Beulich XEN_PT_ERR(d, "%s ioport mapping failed! (err: %i)\n",
6363782f60dSJan Beulich adding ? "create new" : "remove old", errno);
63780b4ecc8SPaolo Bonzini }
63880b4ecc8SPaolo Bonzini } else {
63980b4ecc8SPaolo Bonzini pcibus_t guest_addr = sec->offset_within_address_space;
64080b4ecc8SPaolo Bonzini pcibus_t machine_addr = s->bases[bar].access.maddr
64180b4ecc8SPaolo Bonzini + sec->offset_within_region;
642052e87b0SPaolo Bonzini pcibus_t size = int128_get64(sec->size);
64380b4ecc8SPaolo Bonzini rc = xc_domain_memory_mapping(xen_xc, xen_domid,
64480b4ecc8SPaolo Bonzini XEN_PFN(guest_addr + XC_PAGE_SIZE - 1),
64580b4ecc8SPaolo Bonzini XEN_PFN(machine_addr + XC_PAGE_SIZE - 1),
64680b4ecc8SPaolo Bonzini XEN_PFN(size + XC_PAGE_SIZE - 1),
64780b4ecc8SPaolo Bonzini op);
64880b4ecc8SPaolo Bonzini if (rc) {
6493782f60dSJan Beulich XEN_PT_ERR(d, "%s mem mapping failed! (err: %i)\n",
6503782f60dSJan Beulich adding ? "create new" : "remove old", errno);
65180b4ecc8SPaolo Bonzini }
65280b4ecc8SPaolo Bonzini }
65380b4ecc8SPaolo Bonzini }
65480b4ecc8SPaolo Bonzini
xen_pt_region_add(MemoryListener * l,MemoryRegionSection * sec)65580b4ecc8SPaolo Bonzini static void xen_pt_region_add(MemoryListener *l, MemoryRegionSection *sec)
65680b4ecc8SPaolo Bonzini {
65780b4ecc8SPaolo Bonzini XenPCIPassthroughState *s = container_of(l, XenPCIPassthroughState,
65880b4ecc8SPaolo Bonzini memory_listener);
65980b4ecc8SPaolo Bonzini
660dfde4e6eSPaolo Bonzini memory_region_ref(sec->mr);
66180b4ecc8SPaolo Bonzini xen_pt_region_update(s, sec, true);
66280b4ecc8SPaolo Bonzini }
66380b4ecc8SPaolo Bonzini
xen_pt_region_del(MemoryListener * l,MemoryRegionSection * sec)66480b4ecc8SPaolo Bonzini static void xen_pt_region_del(MemoryListener *l, MemoryRegionSection *sec)
66580b4ecc8SPaolo Bonzini {
66680b4ecc8SPaolo Bonzini XenPCIPassthroughState *s = container_of(l, XenPCIPassthroughState,
66780b4ecc8SPaolo Bonzini memory_listener);
66880b4ecc8SPaolo Bonzini
66980b4ecc8SPaolo Bonzini xen_pt_region_update(s, sec, false);
670dfde4e6eSPaolo Bonzini memory_region_unref(sec->mr);
67180b4ecc8SPaolo Bonzini }
67280b4ecc8SPaolo Bonzini
xen_pt_io_region_add(MemoryListener * l,MemoryRegionSection * sec)67380b4ecc8SPaolo Bonzini static void xen_pt_io_region_add(MemoryListener *l, MemoryRegionSection *sec)
67480b4ecc8SPaolo Bonzini {
67580b4ecc8SPaolo Bonzini XenPCIPassthroughState *s = container_of(l, XenPCIPassthroughState,
67680b4ecc8SPaolo Bonzini io_listener);
67780b4ecc8SPaolo Bonzini
678dfde4e6eSPaolo Bonzini memory_region_ref(sec->mr);
67980b4ecc8SPaolo Bonzini xen_pt_region_update(s, sec, true);
68080b4ecc8SPaolo Bonzini }
68180b4ecc8SPaolo Bonzini
xen_pt_io_region_del(MemoryListener * l,MemoryRegionSection * sec)68280b4ecc8SPaolo Bonzini static void xen_pt_io_region_del(MemoryListener *l, MemoryRegionSection *sec)
68380b4ecc8SPaolo Bonzini {
68480b4ecc8SPaolo Bonzini XenPCIPassthroughState *s = container_of(l, XenPCIPassthroughState,
68580b4ecc8SPaolo Bonzini io_listener);
68680b4ecc8SPaolo Bonzini
68780b4ecc8SPaolo Bonzini xen_pt_region_update(s, sec, false);
688dfde4e6eSPaolo Bonzini memory_region_unref(sec->mr);
68980b4ecc8SPaolo Bonzini }
69080b4ecc8SPaolo Bonzini
69180b4ecc8SPaolo Bonzini static const MemoryListener xen_pt_memory_listener = {
692142518bdSPeter Xu .name = "xen-pt-mem",
69380b4ecc8SPaolo Bonzini .region_add = xen_pt_region_add,
69480b4ecc8SPaolo Bonzini .region_del = xen_pt_region_del,
6955369a36cSIsaku Yamahata .priority = MEMORY_LISTENER_PRIORITY_ACCEL,
69680b4ecc8SPaolo Bonzini };
69780b4ecc8SPaolo Bonzini
69880b4ecc8SPaolo Bonzini static const MemoryListener xen_pt_io_listener = {
699142518bdSPeter Xu .name = "xen-pt-io",
70080b4ecc8SPaolo Bonzini .region_add = xen_pt_io_region_add,
70180b4ecc8SPaolo Bonzini .region_del = xen_pt_io_region_del,
7025369a36cSIsaku Yamahata .priority = MEMORY_LISTENER_PRIORITY_ACCEL,
70380b4ecc8SPaolo Bonzini };
70480b4ecc8SPaolo Bonzini
705df6aa457SKonrad Rzeszutek Wilk /* destroy. */
xen_pt_destroy(PCIDevice * d)706df6aa457SKonrad Rzeszutek Wilk static void xen_pt_destroy(PCIDevice *d) {
707df6aa457SKonrad Rzeszutek Wilk
708df6aa457SKonrad Rzeszutek Wilk XenPCIPassthroughState *s = XEN_PT_DEVICE(d);
709df6aa457SKonrad Rzeszutek Wilk XenHostPCIDevice *host_dev = &s->real_device;
710df6aa457SKonrad Rzeszutek Wilk uint8_t machine_irq = s->machine_irq;
711df6aa457SKonrad Rzeszutek Wilk uint8_t intx;
712df6aa457SKonrad Rzeszutek Wilk int rc;
713df6aa457SKonrad Rzeszutek Wilk
714*ee1004bbSPhilippe Mathieu-Daudé if (machine_irq && !xen_host_pci_device_closed(host_dev)) {
715df6aa457SKonrad Rzeszutek Wilk intx = xen_pt_pci_intx(s);
716df6aa457SKonrad Rzeszutek Wilk rc = xc_domain_unbind_pt_irq(xen_xc, xen_domid, machine_irq,
717df6aa457SKonrad Rzeszutek Wilk PT_IRQ_TYPE_PCI,
718cdc57472SDavid Gibson pci_dev_bus_num(d),
719df6aa457SKonrad Rzeszutek Wilk PCI_SLOT(s->dev.devfn),
720df6aa457SKonrad Rzeszutek Wilk intx,
721df6aa457SKonrad Rzeszutek Wilk 0 /* isa_irq */);
722df6aa457SKonrad Rzeszutek Wilk if (rc < 0) {
723df6aa457SKonrad Rzeszutek Wilk XEN_PT_ERR(d, "unbinding of interrupt INT%c failed."
724df6aa457SKonrad Rzeszutek Wilk " (machine irq: %i, err: %d)"
725df6aa457SKonrad Rzeszutek Wilk " But bravely continuing on..\n",
726df6aa457SKonrad Rzeszutek Wilk 'a' + intx, machine_irq, errno);
727df6aa457SKonrad Rzeszutek Wilk }
728df6aa457SKonrad Rzeszutek Wilk }
729df6aa457SKonrad Rzeszutek Wilk
730df6aa457SKonrad Rzeszutek Wilk /* N.B. xen_pt_config_delete takes care of freeing them. */
731df6aa457SKonrad Rzeszutek Wilk if (s->msi) {
732df6aa457SKonrad Rzeszutek Wilk xen_pt_msi_disable(s);
733df6aa457SKonrad Rzeszutek Wilk }
734df6aa457SKonrad Rzeszutek Wilk if (s->msix) {
735df6aa457SKonrad Rzeszutek Wilk xen_pt_msix_disable(s);
736df6aa457SKonrad Rzeszutek Wilk }
737df6aa457SKonrad Rzeszutek Wilk
738df6aa457SKonrad Rzeszutek Wilk if (machine_irq) {
739df6aa457SKonrad Rzeszutek Wilk xen_pt_mapped_machine_irq[machine_irq]--;
740df6aa457SKonrad Rzeszutek Wilk
741df6aa457SKonrad Rzeszutek Wilk if (xen_pt_mapped_machine_irq[machine_irq] == 0) {
742df6aa457SKonrad Rzeszutek Wilk rc = xc_physdev_unmap_pirq(xen_xc, xen_domid, machine_irq);
743df6aa457SKonrad Rzeszutek Wilk
744df6aa457SKonrad Rzeszutek Wilk if (rc < 0) {
745df6aa457SKonrad Rzeszutek Wilk XEN_PT_ERR(d, "unmapping of interrupt %i failed. (err: %d)"
746df6aa457SKonrad Rzeszutek Wilk " But bravely continuing on..\n",
747df6aa457SKonrad Rzeszutek Wilk machine_irq, errno);
748df6aa457SKonrad Rzeszutek Wilk }
749df6aa457SKonrad Rzeszutek Wilk }
750df6aa457SKonrad Rzeszutek Wilk s->machine_irq = 0;
751df6aa457SKonrad Rzeszutek Wilk }
752df6aa457SKonrad Rzeszutek Wilk
753df6aa457SKonrad Rzeszutek Wilk /* delete all emulated config registers */
754df6aa457SKonrad Rzeszutek Wilk xen_pt_config_delete(s);
755df6aa457SKonrad Rzeszutek Wilk
756df6aa457SKonrad Rzeszutek Wilk xen_pt_unregister_vga_regions(host_dev);
757df6aa457SKonrad Rzeszutek Wilk
758df6aa457SKonrad Rzeszutek Wilk if (s->listener_set) {
759df6aa457SKonrad Rzeszutek Wilk memory_listener_unregister(&s->memory_listener);
760df6aa457SKonrad Rzeszutek Wilk memory_listener_unregister(&s->io_listener);
761df6aa457SKonrad Rzeszutek Wilk s->listener_set = false;
762df6aa457SKonrad Rzeszutek Wilk }
763*ee1004bbSPhilippe Mathieu-Daudé if (!xen_host_pci_device_closed(host_dev)) {
764*ee1004bbSPhilippe Mathieu-Daudé xen_host_pci_device_put(host_dev);
765df6aa457SKonrad Rzeszutek Wilk }
766df6aa457SKonrad Rzeszutek Wilk }
76780b4ecc8SPaolo Bonzini /* init */
76880b4ecc8SPaolo Bonzini
xen_pt_realize(PCIDevice * d,Error ** errp)7695a11d0f7SCao jin static void xen_pt_realize(PCIDevice *d, Error **errp)
77080b4ecc8SPaolo Bonzini {
7711de7096dSVladimir Sementsov-Ogievskiy ERRP_GUARD();
772f9b9d292SGonglei XenPCIPassthroughState *s = XEN_PT_DEVICE(d);
7735a11d0f7SCao jin int i, rc = 0;
7746aa07b14SKonrad Rzeszutek Wilk uint8_t machine_irq = 0, scratch;
77581b23ef8SJan Beulich uint16_t cmd = 0;
77680b4ecc8SPaolo Bonzini int pirq = XEN_PT_UNASSIGNED_PIRQ;
77780b4ecc8SPaolo Bonzini
77880b4ecc8SPaolo Bonzini /* register real device */
77980b4ecc8SPaolo Bonzini XEN_PT_LOG(d, "Assigning real physical device %02x:%02x.%d"
78001d152c0SXinhao Zhang " to devfn 0x%x\n",
78180b4ecc8SPaolo Bonzini s->hostaddr.bus, s->hostaddr.slot, s->hostaddr.function,
78280b4ecc8SPaolo Bonzini s->dev.devfn);
78380b4ecc8SPaolo Bonzini
78480b4ecc8SPaolo Bonzini s->is_virtfn = s->real_device.is_virtfn;
78580b4ecc8SPaolo Bonzini if (s->is_virtfn) {
78680b4ecc8SPaolo Bonzini XEN_PT_LOG(d, "%04x:%02x:%02x.%d is a SR-IOV Virtual Function\n",
78780b4ecc8SPaolo Bonzini s->real_device.domain, s->real_device.bus,
78880b4ecc8SPaolo Bonzini s->real_device.dev, s->real_device.func);
78980b4ecc8SPaolo Bonzini }
79080b4ecc8SPaolo Bonzini
79180b4ecc8SPaolo Bonzini /* Initialize virtualized PCI configuration (Extended 256 Bytes) */
792cae99f1dSKonrad Rzeszutek Wilk memset(d->config, 0, PCI_CONFIG_SPACE_SIZE);
79380b4ecc8SPaolo Bonzini
79480b4ecc8SPaolo Bonzini s->memory_listener = xen_pt_memory_listener;
79580b4ecc8SPaolo Bonzini s->io_listener = xen_pt_io_listener;
79680b4ecc8SPaolo Bonzini
797881213f1STiejun Chen /* Setup VGA bios for passthrough GFX */
7984f67543bSChuck Zmudzinski if ((s->real_device.domain == XEN_PCI_IGD_DOMAIN) &&
7994f67543bSChuck Zmudzinski (s->real_device.bus == XEN_PCI_IGD_BUS) &&
8004f67543bSChuck Zmudzinski (s->real_device.dev == XEN_PCI_IGD_DEV) &&
8014f67543bSChuck Zmudzinski (s->real_device.func == XEN_PCI_IGD_FN)) {
802f37d630aSTiejun Chen if (!is_igd_vga_passthrough(&s->real_device)) {
8035a11d0f7SCao jin error_setg(errp, "Need to enable igd-passthru if you're trying"
8045a11d0f7SCao jin " to passthrough IGD GFX");
805f37d630aSTiejun Chen xen_host_pci_device_put(&s->real_device);
8065a11d0f7SCao jin return;
807f37d630aSTiejun Chen }
808f37d630aSTiejun Chen
8091de7096dSVladimir Sementsov-Ogievskiy xen_pt_setup_vga(s, &s->real_device, errp);
8101de7096dSVladimir Sementsov-Ogievskiy if (*errp) {
8111de7096dSVladimir Sementsov-Ogievskiy error_append_hint(errp, "Setup VGA BIOS of passthrough"
8125226bb59SCao jin " GFX failed");
813881213f1STiejun Chen xen_host_pci_device_put(&s->real_device);
8145a11d0f7SCao jin return;
815881213f1STiejun Chen }
816f37d630aSTiejun Chen
817f37d630aSTiejun Chen /* Register ISA bridge for passthrough GFX. */
818f37d630aSTiejun Chen xen_igd_passthrough_isa_bridge_create(s, &s->real_device);
819881213f1STiejun Chen }
820881213f1STiejun Chen
82180b4ecc8SPaolo Bonzini /* Handle real device's MMIO/PIO BARs */
82281b23ef8SJan Beulich xen_pt_register_regions(s, &cmd);
82380b4ecc8SPaolo Bonzini
82480b4ecc8SPaolo Bonzini /* reinitialize each config register to be emulated */
8251de7096dSVladimir Sementsov-Ogievskiy xen_pt_config_init(s, errp);
8261de7096dSVladimir Sementsov-Ogievskiy if (*errp) {
8271de7096dSVladimir Sementsov-Ogievskiy error_append_hint(errp, "PCI Config space initialisation failed");
828d50a6e58SCao jin rc = -1;
8293d3697f2SKonrad Rzeszutek Wilk goto err_out;
83080b4ecc8SPaolo Bonzini }
83180b4ecc8SPaolo Bonzini
83280b4ecc8SPaolo Bonzini /* Bind interrupt */
8336aa07b14SKonrad Rzeszutek Wilk rc = xen_host_pci_get_byte(&s->real_device, PCI_INTERRUPT_PIN, &scratch);
8346aa07b14SKonrad Rzeszutek Wilk if (rc) {
8355a11d0f7SCao jin error_setg_errno(errp, errno, "Failed to read PCI_INTERRUPT_PIN");
8363d3697f2SKonrad Rzeszutek Wilk goto err_out;
8376aa07b14SKonrad Rzeszutek Wilk }
8386aa07b14SKonrad Rzeszutek Wilk if (!scratch) {
8390968c91cSBruce Rogers XEN_PT_LOG(d, "no pin interrupt\n");
84080b4ecc8SPaolo Bonzini goto out;
84180b4ecc8SPaolo Bonzini }
84280b4ecc8SPaolo Bonzini
84380b4ecc8SPaolo Bonzini machine_irq = s->real_device.irq;
84492dbfcc6SZhao Yan if (machine_irq == 0) {
84592dbfcc6SZhao Yan XEN_PT_LOG(d, "machine irq is 0\n");
84692dbfcc6SZhao Yan cmd |= PCI_COMMAND_INTX_DISABLE;
84792dbfcc6SZhao Yan goto out;
84892dbfcc6SZhao Yan }
84992dbfcc6SZhao Yan
85080b4ecc8SPaolo Bonzini rc = xc_physdev_map_pirq(xen_xc, xen_domid, machine_irq, &pirq);
85180b4ecc8SPaolo Bonzini if (rc < 0) {
852c61d1d9eSMarkus Armbruster XEN_PT_ERR(d, "Mapping machine irq %u to pirq %i failed, (err: %d)\n",
853c61d1d9eSMarkus Armbruster machine_irq, pirq, errno);
85480b4ecc8SPaolo Bonzini
85580b4ecc8SPaolo Bonzini /* Disable PCI intx assertion (turn on bit10 of devctl) */
856950fe0aaSJan Beulich cmd |= PCI_COMMAND_INTX_DISABLE;
85780b4ecc8SPaolo Bonzini machine_irq = 0;
85880b4ecc8SPaolo Bonzini s->machine_irq = 0;
85980b4ecc8SPaolo Bonzini } else {
86080b4ecc8SPaolo Bonzini machine_irq = pirq;
86180b4ecc8SPaolo Bonzini s->machine_irq = pirq;
86280b4ecc8SPaolo Bonzini xen_pt_mapped_machine_irq[machine_irq]++;
86380b4ecc8SPaolo Bonzini }
86480b4ecc8SPaolo Bonzini
86580b4ecc8SPaolo Bonzini /* bind machine_irq to device */
86680b4ecc8SPaolo Bonzini if (machine_irq != 0) {
86780b4ecc8SPaolo Bonzini uint8_t e_intx = xen_pt_pci_intx(s);
86880b4ecc8SPaolo Bonzini
86980b4ecc8SPaolo Bonzini rc = xc_domain_bind_pt_pci_irq(xen_xc, xen_domid, machine_irq,
870cdc57472SDavid Gibson pci_dev_bus_num(d),
87180b4ecc8SPaolo Bonzini PCI_SLOT(d->devfn),
87280b4ecc8SPaolo Bonzini e_intx);
87380b4ecc8SPaolo Bonzini if (rc < 0) {
874c61d1d9eSMarkus Armbruster XEN_PT_ERR(d, "Binding of interrupt %i failed! (err: %d)\n",
875c61d1d9eSMarkus Armbruster e_intx, errno);
87680b4ecc8SPaolo Bonzini
87780b4ecc8SPaolo Bonzini /* Disable PCI intx assertion (turn on bit10 of devctl) */
878950fe0aaSJan Beulich cmd |= PCI_COMMAND_INTX_DISABLE;
87980b4ecc8SPaolo Bonzini xen_pt_mapped_machine_irq[machine_irq]--;
88080b4ecc8SPaolo Bonzini
88180b4ecc8SPaolo Bonzini if (xen_pt_mapped_machine_irq[machine_irq] == 0) {
88280b4ecc8SPaolo Bonzini if (xc_physdev_unmap_pirq(xen_xc, xen_domid, machine_irq)) {
883c61d1d9eSMarkus Armbruster XEN_PT_ERR(d, "Unmapping of machine interrupt %i failed!"
884c61d1d9eSMarkus Armbruster " (err: %d)\n", machine_irq, errno);
88580b4ecc8SPaolo Bonzini }
88680b4ecc8SPaolo Bonzini }
88780b4ecc8SPaolo Bonzini s->machine_irq = 0;
88880b4ecc8SPaolo Bonzini }
88980b4ecc8SPaolo Bonzini }
89080b4ecc8SPaolo Bonzini
89180b4ecc8SPaolo Bonzini out:
89281b23ef8SJan Beulich if (cmd) {
8936aa07b14SKonrad Rzeszutek Wilk uint16_t val;
8946aa07b14SKonrad Rzeszutek Wilk
8956aa07b14SKonrad Rzeszutek Wilk rc = xen_host_pci_get_word(&s->real_device, PCI_COMMAND, &val);
8966aa07b14SKonrad Rzeszutek Wilk if (rc) {
8975a11d0f7SCao jin error_setg_errno(errp, errno, "Failed to read PCI_COMMAND");
8983d3697f2SKonrad Rzeszutek Wilk goto err_out;
8996aa07b14SKonrad Rzeszutek Wilk } else {
9006aa07b14SKonrad Rzeszutek Wilk val |= cmd;
9016aa07b14SKonrad Rzeszutek Wilk rc = xen_host_pci_set_word(&s->real_device, PCI_COMMAND, val);
9026aa07b14SKonrad Rzeszutek Wilk if (rc) {
9035a11d0f7SCao jin error_setg_errno(errp, errno, "Failed to write PCI_COMMAND"
9045a11d0f7SCao jin " val = 0x%x", val);
9053d3697f2SKonrad Rzeszutek Wilk goto err_out;
9066aa07b14SKonrad Rzeszutek Wilk }
9076aa07b14SKonrad Rzeszutek Wilk }
90881b23ef8SJan Beulich }
90981b23ef8SJan Beulich
91084201604SIgor Druzhinin memory_listener_register(&s->memory_listener, &address_space_memory);
91180b4ecc8SPaolo Bonzini memory_listener_register(&s->io_listener, &address_space_io);
912bce33948SKonrad Rzeszutek Wilk s->listener_set = true;
91352f35022SStefan Weil XEN_PT_LOG(d,
9145a11d0f7SCao jin "Real physical device %02x:%02x.%d registered successfully\n",
91580b4ecc8SPaolo Bonzini s->hostaddr.bus, s->hostaddr.slot, s->hostaddr.function);
91680b4ecc8SPaolo Bonzini
9175a11d0f7SCao jin return;
9183d3697f2SKonrad Rzeszutek Wilk
9193d3697f2SKonrad Rzeszutek Wilk err_out:
9205a11d0f7SCao jin for (i = 0; i < PCI_ROM_SLOT; i++) {
9215a11d0f7SCao jin object_unparent(OBJECT(&s->bar[i]));
9225a11d0f7SCao jin }
9235a11d0f7SCao jin object_unparent(OBJECT(&s->rom));
9245a11d0f7SCao jin
9253d3697f2SKonrad Rzeszutek Wilk xen_pt_destroy(d);
9263d3697f2SKonrad Rzeszutek Wilk assert(rc);
92780b4ecc8SPaolo Bonzini }
92880b4ecc8SPaolo Bonzini
xen_pt_unregister_device(PCIDevice * d)92980b4ecc8SPaolo Bonzini static void xen_pt_unregister_device(PCIDevice *d)
93080b4ecc8SPaolo Bonzini {
931df6aa457SKonrad Rzeszutek Wilk xen_pt_destroy(d);
932bce33948SKonrad Rzeszutek Wilk }
93380b4ecc8SPaolo Bonzini
93480b4ecc8SPaolo Bonzini static Property xen_pci_passthrough_properties[] = {
93580b4ecc8SPaolo Bonzini DEFINE_PROP_PCI_HOST_DEVADDR("hostaddr", XenPCIPassthroughState, hostaddr),
936c25bbf15SJan Beulich DEFINE_PROP_BOOL("permissive", XenPCIPassthroughState, permissive, false),
93780b4ecc8SPaolo Bonzini DEFINE_PROP_END_OF_LIST(),
93880b4ecc8SPaolo Bonzini };
93980b4ecc8SPaolo Bonzini
xen_pci_passthrough_instance_init(Object * obj)940d61a363dSYoni Bettan static void xen_pci_passthrough_instance_init(Object *obj)
941d61a363dSYoni Bettan {
942d61a363dSYoni Bettan /* QEMU_PCI_CAP_EXPRESS initialization does not depend on QEMU command
943d61a363dSYoni Bettan * line, therefore, no need to wait to realize like other devices */
944d61a363dSYoni Bettan PCI_DEVICE(obj)->cap_present |= QEMU_PCI_CAP_EXPRESS;
945d61a363dSYoni Bettan }
946d61a363dSYoni Bettan
xen_igd_reserve_slot(PCIBus * pci_bus)9474f67543bSChuck Zmudzinski void xen_igd_reserve_slot(PCIBus *pci_bus)
9484f67543bSChuck Zmudzinski {
9494f67543bSChuck Zmudzinski if (!xen_igd_gfx_pt_enabled()) {
9504f67543bSChuck Zmudzinski return;
9514f67543bSChuck Zmudzinski }
9524f67543bSChuck Zmudzinski
9534f67543bSChuck Zmudzinski XEN_PT_LOG(0, "Reserving PCI slot 2 for IGD\n");
954b93fe7f2SChuck Zmudzinski pci_bus_set_slot_reserved_mask(pci_bus, XEN_PCI_IGD_SLOT_MASK);
9554f67543bSChuck Zmudzinski }
9564f67543bSChuck Zmudzinski
xen_igd_clear_slot(DeviceState * qdev,Error ** errp)9574f67543bSChuck Zmudzinski static void xen_igd_clear_slot(DeviceState *qdev, Error **errp)
9584f67543bSChuck Zmudzinski {
9594f67543bSChuck Zmudzinski ERRP_GUARD();
9604f67543bSChuck Zmudzinski PCIDevice *pci_dev = (PCIDevice *)qdev;
9614f67543bSChuck Zmudzinski XenPCIPassthroughState *s = XEN_PT_DEVICE(pci_dev);
9624f67543bSChuck Zmudzinski XenPTDeviceClass *xpdc = XEN_PT_DEVICE_GET_CLASS(s);
9634f67543bSChuck Zmudzinski PCIBus *pci_bus = pci_get_bus(pci_dev);
9644f67543bSChuck Zmudzinski
9654f67543bSChuck Zmudzinski xen_host_pci_device_get(&s->real_device,
9664f67543bSChuck Zmudzinski s->hostaddr.domain, s->hostaddr.bus,
9674f67543bSChuck Zmudzinski s->hostaddr.slot, s->hostaddr.function,
9684f67543bSChuck Zmudzinski errp);
9694f67543bSChuck Zmudzinski if (*errp) {
9704f67543bSChuck Zmudzinski error_append_hint(errp, "Failed to \"open\" the real pci device");
9714f67543bSChuck Zmudzinski return;
9724f67543bSChuck Zmudzinski }
9734f67543bSChuck Zmudzinski
974b93fe7f2SChuck Zmudzinski if (!(pci_bus_get_slot_reserved_mask(pci_bus) & XEN_PCI_IGD_SLOT_MASK)) {
9754f67543bSChuck Zmudzinski xpdc->pci_qdev_realize(qdev, errp);
9764f67543bSChuck Zmudzinski return;
9774f67543bSChuck Zmudzinski }
9784f67543bSChuck Zmudzinski
9794f67543bSChuck Zmudzinski if (is_igd_vga_passthrough(&s->real_device) &&
9804f67543bSChuck Zmudzinski s->real_device.domain == XEN_PCI_IGD_DOMAIN &&
9814f67543bSChuck Zmudzinski s->real_device.bus == XEN_PCI_IGD_BUS &&
9824f67543bSChuck Zmudzinski s->real_device.dev == XEN_PCI_IGD_DEV &&
9834f67543bSChuck Zmudzinski s->real_device.func == XEN_PCI_IGD_FN &&
9844f67543bSChuck Zmudzinski s->real_device.vendor_id == PCI_VENDOR_ID_INTEL) {
985b93fe7f2SChuck Zmudzinski pci_bus_clear_slot_reserved_mask(pci_bus, XEN_PCI_IGD_SLOT_MASK);
9864f67543bSChuck Zmudzinski XEN_PT_LOG(pci_dev, "Intel IGD found, using slot 2\n");
9874f67543bSChuck Zmudzinski }
9884f67543bSChuck Zmudzinski xpdc->pci_qdev_realize(qdev, errp);
9894f67543bSChuck Zmudzinski }
9904f67543bSChuck Zmudzinski
xen_pci_passthrough_class_init(ObjectClass * klass,void * data)99180b4ecc8SPaolo Bonzini static void xen_pci_passthrough_class_init(ObjectClass *klass, void *data)
99280b4ecc8SPaolo Bonzini {
99380b4ecc8SPaolo Bonzini DeviceClass *dc = DEVICE_CLASS(klass);
99480b4ecc8SPaolo Bonzini PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
99580b4ecc8SPaolo Bonzini
9964f67543bSChuck Zmudzinski XenPTDeviceClass *xpdc = XEN_PT_DEVICE_CLASS(klass);
9974f67543bSChuck Zmudzinski xpdc->pci_qdev_realize = dc->realize;
9984f67543bSChuck Zmudzinski dc->realize = xen_igd_clear_slot;
9995a11d0f7SCao jin k->realize = xen_pt_realize;
100080b4ecc8SPaolo Bonzini k->exit = xen_pt_unregister_device;
100180b4ecc8SPaolo Bonzini k->config_read = xen_pt_pci_read_config;
100280b4ecc8SPaolo Bonzini k->config_write = xen_pt_pci_write_config;
1003125ee0edSMarcel Apfelbaum set_bit(DEVICE_CATEGORY_MISC, dc->categories);
100480b4ecc8SPaolo Bonzini dc->desc = "Assign an host PCI device with Xen";
10054f67d30bSMarc-André Lureau device_class_set_props(dc, xen_pci_passthrough_properties);
100680b4ecc8SPaolo Bonzini };
100780b4ecc8SPaolo Bonzini
xen_pci_passthrough_finalize(Object * obj)10084e494de6SLan Tianyu static void xen_pci_passthrough_finalize(Object *obj)
10094e494de6SLan Tianyu {
10104e494de6SLan Tianyu XenPCIPassthroughState *s = XEN_PT_DEVICE(obj);
10114e494de6SLan Tianyu
10124e494de6SLan Tianyu xen_pt_msix_delete(s);
10134e494de6SLan Tianyu }
10144e494de6SLan Tianyu
101580b4ecc8SPaolo Bonzini static const TypeInfo xen_pci_passthrough_info = {
1016f9b9d292SGonglei .name = TYPE_XEN_PT_DEVICE,
101780b4ecc8SPaolo Bonzini .parent = TYPE_PCI_DEVICE,
101880b4ecc8SPaolo Bonzini .instance_size = sizeof(XenPCIPassthroughState),
10194e494de6SLan Tianyu .instance_finalize = xen_pci_passthrough_finalize,
102080b4ecc8SPaolo Bonzini .class_init = xen_pci_passthrough_class_init,
10214f67543bSChuck Zmudzinski .class_size = sizeof(XenPTDeviceClass),
1022d61a363dSYoni Bettan .instance_init = xen_pci_passthrough_instance_init,
1023fd3b02c8SEduardo Habkost .interfaces = (InterfaceInfo[]) {
1024fd3b02c8SEduardo Habkost { INTERFACE_CONVENTIONAL_PCI_DEVICE },
10256d702376SEduardo Habkost { INTERFACE_PCIE_DEVICE },
1026fd3b02c8SEduardo Habkost { },
1027fd3b02c8SEduardo Habkost },
102880b4ecc8SPaolo Bonzini };
102980b4ecc8SPaolo Bonzini
xen_pci_passthrough_register_types(void)103080b4ecc8SPaolo Bonzini static void xen_pci_passthrough_register_types(void)
103180b4ecc8SPaolo Bonzini {
103280b4ecc8SPaolo Bonzini type_register_static(&xen_pci_passthrough_info);
103380b4ecc8SPaolo Bonzini }
103480b4ecc8SPaolo Bonzini
103580b4ecc8SPaolo Bonzini type_init(xen_pci_passthrough_register_types)
1036