Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

xen-pciback: notify hypervisor about devices intended to be assigned to guests

For MSI-X capable devices the hypervisor wants to write protect the
MSI-X table and PBA, yet it can't assume that resources have been
assigned to their final values at device enumeration time. Thus have
pciback do that notification, as having the device controlled by it is
a prerequisite to assigning the device to guests anyway.

This is the kernel part of hypervisor side commit 4245d33 ("x86/MSI:
add mechanism to fully protect MSI-X table from PV guest accesses") on
the master branch of git://xenbits.xen.org/xen.git.

CC: stable@vger.kernel.org
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>

authored by

Jan Beulich and committed by
Konrad Rzeszutek Wilk
909b3fdb 949dd8c1

+54 -18
+2 -2
arch/x86/include/asm/xen/hypercall.h
··· 382 382 return _hypercall3(int, console_io, cmd, count, str); 383 383 } 384 384 385 - extern int __must_check HYPERVISOR_physdev_op_compat(int, void *); 385 + extern int __must_check xen_physdev_op_compat(int, void *); 386 386 387 387 static inline int 388 388 HYPERVISOR_physdev_op(int cmd, void *arg) 389 389 { 390 390 int rc = _hypercall2(int, physdev_op, cmd, arg); 391 391 if (unlikely(rc == -ENOSYS)) 392 - rc = HYPERVISOR_physdev_op_compat(cmd, arg); 392 + rc = xen_physdev_op_compat(cmd, arg); 393 393 return rc; 394 394 } 395 395
+2 -1
drivers/xen/fallback.c
··· 44 44 } 45 45 EXPORT_SYMBOL_GPL(xen_event_channel_op_compat); 46 46 47 - int HYPERVISOR_physdev_op_compat(int cmd, void *arg) 47 + int xen_physdev_op_compat(int cmd, void *arg) 48 48 { 49 49 struct physdev_op op; 50 50 int rc; ··· 78 78 79 79 return rc; 80 80 } 81 + EXPORT_SYMBOL_GPL(xen_physdev_op_compat);
+44 -15
drivers/xen/xen-pciback/pci_stub.c
··· 17 17 #include <xen/events.h> 18 18 #include <asm/xen/pci.h> 19 19 #include <asm/xen/hypervisor.h> 20 + #include <xen/interface/physdev.h> 20 21 #include "pciback.h" 21 22 #include "conf_space.h" 22 23 #include "conf_space_quirks.h" ··· 86 85 static void pcistub_device_release(struct kref *kref) 87 86 { 88 87 struct pcistub_device *psdev; 88 + struct pci_dev *dev; 89 89 struct xen_pcibk_dev_data *dev_data; 90 90 91 91 psdev = container_of(kref, struct pcistub_device, kref); 92 - dev_data = pci_get_drvdata(psdev->dev); 92 + dev = psdev->dev; 93 + dev_data = pci_get_drvdata(dev); 93 94 94 - dev_dbg(&psdev->dev->dev, "pcistub_device_release\n"); 95 + dev_dbg(&dev->dev, "pcistub_device_release\n"); 95 96 96 - xen_unregister_device_domain_owner(psdev->dev); 97 + xen_unregister_device_domain_owner(dev); 97 98 98 99 /* Call the reset function which does not take lock as this 99 100 * is called from "unbind" which takes a device_lock mutex. 100 101 */ 101 - __pci_reset_function_locked(psdev->dev); 102 - if (pci_load_and_free_saved_state(psdev->dev, 103 - &dev_data->pci_saved_state)) { 104 - dev_dbg(&psdev->dev->dev, "Could not reload PCI state\n"); 105 - } else 106 - pci_restore_state(psdev->dev); 102 + __pci_reset_function_locked(dev); 103 + if (pci_load_and_free_saved_state(dev, &dev_data->pci_saved_state)) 104 + dev_dbg(&dev->dev, "Could not reload PCI state\n"); 105 + else 106 + pci_restore_state(dev); 107 + 108 + if (pci_find_capability(dev, PCI_CAP_ID_MSIX)) { 109 + struct physdev_pci_device ppdev = { 110 + .seg = pci_domain_nr(dev->bus), 111 + .bus = dev->bus->number, 112 + .devfn = dev->devfn 113 + }; 114 + int err = HYPERVISOR_physdev_op(PHYSDEVOP_release_msix, 115 + &ppdev); 116 + 117 + if (err) 118 + dev_warn(&dev->dev, "MSI-X release failed (%d)\n", 119 + err); 120 + } 107 121 108 122 /* Disable the device */ 109 - xen_pcibk_reset_device(psdev->dev); 123 + xen_pcibk_reset_device(dev); 110 124 111 125 kfree(dev_data); 112 - pci_set_drvdata(psdev->dev, NULL); 126 + pci_set_drvdata(dev, NULL); 113 127 114 128 /* Clean-up the device */ 115 - xen_pcibk_config_free_dyn_fields(psdev->dev); 116 - xen_pcibk_config_free_dev(psdev->dev); 129 + xen_pcibk_config_free_dyn_fields(dev); 130 + xen_pcibk_config_free_dev(dev); 117 131 118 - psdev->dev->dev_flags &= ~PCI_DEV_FLAGS_ASSIGNED; 119 - pci_dev_put(psdev->dev); 132 + dev->dev_flags &= ~PCI_DEV_FLAGS_ASSIGNED; 133 + pci_dev_put(dev); 120 134 121 135 kfree(psdev); 122 136 } ··· 370 354 err = pci_enable_device(dev); 371 355 if (err) 372 356 goto config_release; 357 + 358 + if (pci_find_capability(dev, PCI_CAP_ID_MSIX)) { 359 + struct physdev_pci_device ppdev = { 360 + .seg = pci_domain_nr(dev->bus), 361 + .bus = dev->bus->number, 362 + .devfn = dev->devfn 363 + }; 364 + 365 + err = HYPERVISOR_physdev_op(PHYSDEVOP_prepare_msix, &ppdev); 366 + if (err) 367 + dev_err(&dev->dev, "MSI-X preparation failed (%d)\n", 368 + err); 369 + } 373 370 374 371 /* We need the device active to save the state. */ 375 372 dev_dbg(&dev->dev, "save state of device\n");
+6
include/xen/interface/physdev.h
··· 251 251 252 252 #define PHYSDEVOP_pci_device_remove 26 253 253 #define PHYSDEVOP_restore_msi_ext 27 254 + /* 255 + * Dom0 should use these two to announce MMIO resources assigned to 256 + * MSI-X capable devices won't (prepare) or may (release) change. 257 + */ 258 + #define PHYSDEVOP_prepare_msix 30 259 + #define PHYSDEVOP_release_msix 31 254 260 struct physdev_pci_device { 255 261 /* IN */ 256 262 uint16_t seg;