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

xen/privcmd: Add new syscall to get gsi from dev

On PVH dom0, when passthrough a device to domU, QEMU and xl tools
want to use gsi number to do pirq mapping, see QEMU code
xen_pt_realize->xc_physdev_map_pirq, and xl code
pci_add_dm_done->xc_physdev_map_pirq, but in current codes, the gsi
number is got from file /sys/bus/pci/devices/<sbdf>/irq, that is
wrong, because irq is not equal with gsi, they are in different
spaces, so pirq mapping fails.
And in current linux codes, there is no method to get gsi
for userspace.

For above purpose, record gsi of pcistub devices when init
pcistub and add a new syscall into privcmd to let userspace
can get gsi when they have a need.

Signed-off-by: Jiqian Chen <Jiqian.Chen@amd.com>
Signed-off-by: Huang Rui <ray.huang@amd.com>
Signed-off-by: Jiqian Chen <Jiqian.Chen@amd.com>
Reviewed-by: Stefano Stabellini <sstabellini@kernel.org>
Message-ID: <20240924061437.2636766-4-Jiqian.Chen@amd.com>
Signed-off-by: Juergen Gross <jgross@suse.com>

authored by

Jiqian Chen and committed by
Juergen Gross
2fae6bb7 b166b8ab

+84 -3
+1
drivers/xen/Kconfig
··· 261 261 config XEN_PRIVCMD 262 262 tristate "Xen hypercall passthrough driver" 263 263 depends on XEN 264 + imply CONFIG_XEN_PCIDEV_BACKEND 264 265 default m 265 266 help 266 267 The hypercall passthrough driver allows privileged user programs to
+32
drivers/xen/privcmd.c
··· 46 46 #include <xen/page.h> 47 47 #include <xen/xen-ops.h> 48 48 #include <xen/balloon.h> 49 + #ifdef CONFIG_XEN_ACPI 50 + #include <xen/acpi.h> 51 + #endif 49 52 50 53 #include "privcmd.h" 51 54 ··· 847 844 return rc; 848 845 } 849 846 847 + static long privcmd_ioctl_pcidev_get_gsi(struct file *file, void __user *udata) 848 + { 849 + #if defined(CONFIG_XEN_ACPI) 850 + int rc = -EINVAL; 851 + struct privcmd_pcidev_get_gsi kdata; 852 + 853 + if (copy_from_user(&kdata, udata, sizeof(kdata))) 854 + return -EFAULT; 855 + 856 + if (IS_REACHABLE(CONFIG_XEN_PCIDEV_BACKEND)) 857 + rc = pcistub_get_gsi_from_sbdf(kdata.sbdf); 858 + 859 + if (rc < 0) 860 + return rc; 861 + 862 + kdata.gsi = rc; 863 + if (copy_to_user(udata, &kdata, sizeof(kdata))) 864 + return -EFAULT; 865 + 866 + return 0; 867 + #else 868 + return -EINVAL; 869 + #endif 870 + } 871 + 850 872 #ifdef CONFIG_XEN_PRIVCMD_EVENTFD 851 873 /* Irqfd support */ 852 874 static struct workqueue_struct *irqfd_cleanup_wq; ··· 1569 1541 1570 1542 case IOCTL_PRIVCMD_IOEVENTFD: 1571 1543 ret = privcmd_ioctl_ioeventfd(file, udata); 1544 + break; 1545 + 1546 + case IOCTL_PRIVCMD_PCIDEV_GET_GSI: 1547 + ret = privcmd_ioctl_pcidev_get_gsi(file, udata); 1572 1548 break; 1573 1549 1574 1550 default:
+35 -3
drivers/xen/xen-pciback/pci_stub.c
··· 56 56 57 57 struct pci_dev *dev; 58 58 struct xen_pcibk_device *pdev;/* non-NULL if struct pci_dev is in use */ 59 + #ifdef CONFIG_XEN_ACPI 60 + int gsi; 61 + #endif 59 62 }; 60 63 61 64 /* Access to pcistub_devices & seized_devices lists and the initialize_devices ··· 91 88 92 89 kref_init(&psdev->kref); 93 90 spin_lock_init(&psdev->lock); 91 + #ifdef CONFIG_XEN_ACPI 92 + psdev->gsi = -1; 93 + #endif 94 94 95 95 return psdev; 96 96 } ··· 225 219 226 220 return pci_dev; 227 221 } 222 + 223 + #ifdef CONFIG_XEN_ACPI 224 + int pcistub_get_gsi_from_sbdf(unsigned int sbdf) 225 + { 226 + struct pcistub_device *psdev; 227 + int domain = (sbdf >> 16) & 0xffff; 228 + int bus = PCI_BUS_NUM(sbdf); 229 + int slot = PCI_SLOT(sbdf); 230 + int func = PCI_FUNC(sbdf); 231 + 232 + psdev = pcistub_device_find(domain, bus, slot, func); 233 + 234 + if (!psdev) 235 + return -ENODEV; 236 + 237 + return psdev->gsi; 238 + } 239 + EXPORT_SYMBOL_GPL(pcistub_get_gsi_from_sbdf); 240 + #endif 228 241 229 242 struct pci_dev *pcistub_get_pci_dev_by_slot(struct xen_pcibk_device *pdev, 230 243 int domain, int bus, ··· 392 367 return found; 393 368 } 394 369 395 - static int pcistub_init_device(struct pci_dev *dev) 370 + static int pcistub_init_device(struct pcistub_device *psdev) 396 371 { 397 372 struct xen_pcibk_dev_data *dev_data; 373 + struct pci_dev *dev; 398 374 #ifdef CONFIG_XEN_ACPI 399 375 int gsi, trigger, polarity; 400 376 #endif 401 377 int err = 0; 378 + 379 + if (!psdev) 380 + return -EINVAL; 381 + 382 + dev = psdev->dev; 402 383 403 384 dev_dbg(&dev->dev, "initializing...\n"); 404 385 ··· 483 452 err = xen_pvh_setup_gsi(gsi, trigger, polarity); 484 453 if (err) 485 454 goto config_release; 455 + psdev->gsi = gsi; 486 456 } 487 457 #endif 488 458 ··· 526 494 527 495 spin_unlock_irqrestore(&pcistub_devices_lock, flags); 528 496 529 - err = pcistub_init_device(psdev->dev); 497 + err = pcistub_init_device(psdev); 530 498 if (err) { 531 499 dev_err(&psdev->dev->dev, 532 500 "error %d initializing device\n", err); ··· 596 564 spin_unlock_irqrestore(&pcistub_devices_lock, flags); 597 565 598 566 /* don't want irqs disabled when calling pcistub_init_device */ 599 - err = pcistub_init_device(psdev->dev); 567 + err = pcistub_init_device(psdev); 600 568 601 569 spin_lock_irqsave(&pcistub_devices_lock, flags); 602 570
+7
include/uapi/xen/privcmd.h
··· 126 126 __u8 pad[2]; 127 127 }; 128 128 129 + struct privcmd_pcidev_get_gsi { 130 + __u32 sbdf; 131 + __u32 gsi; 132 + }; 133 + 129 134 /* 130 135 * @cmd: IOCTL_PRIVCMD_HYPERCALL 131 136 * @arg: &privcmd_hypercall_t ··· 162 157 _IOW('P', 8, struct privcmd_irqfd) 163 158 #define IOCTL_PRIVCMD_IOEVENTFD \ 164 159 _IOW('P', 9, struct privcmd_ioeventfd) 160 + #define IOCTL_PRIVCMD_PCIDEV_GET_GSI \ 161 + _IOC(_IOC_NONE, 'P', 10, sizeof(struct privcmd_pcidev_get_gsi)) 165 162 166 163 #endif /* __LINUX_PUBLIC_PRIVCMD_H__ */
+9
include/xen/acpi.h
··· 91 91 } 92 92 #endif 93 93 94 + #ifdef CONFIG_XEN_PCI_STUB 95 + int pcistub_get_gsi_from_sbdf(unsigned int sbdf); 96 + #else 97 + static inline int pcistub_get_gsi_from_sbdf(unsigned int sbdf) 98 + { 99 + return -1; 100 + } 101 + #endif 102 + 94 103 #endif /* _XEN_ACPI_H */