#include <xen/page.h>
 #include <xen/xen-ops.h>
 #include <xen/balloon.h>
+#ifdef CONFIG_XEN_ACPI
+#include <xen/acpi.h>
+#endif
 
 #include "privcmd.h"
 
        return rc;
 }
 
+static long privcmd_ioctl_pcidev_get_gsi(struct file *file, void __user *udata)
+{
+#if defined(CONFIG_XEN_ACPI)
+       int rc = -EINVAL;
+       struct privcmd_pcidev_get_gsi kdata;
+
+       if (copy_from_user(&kdata, udata, sizeof(kdata)))
+               return -EFAULT;
+
+       if (IS_REACHABLE(CONFIG_XEN_PCIDEV_BACKEND))
+               rc = pcistub_get_gsi_from_sbdf(kdata.sbdf);
+
+       if (rc < 0)
+               return rc;
+
+       kdata.gsi = rc;
+       if (copy_to_user(udata, &kdata, sizeof(kdata)))
+               return -EFAULT;
+
+       return 0;
+#else
+       return -EINVAL;
+#endif
+}
+
 #ifdef CONFIG_XEN_PRIVCMD_EVENTFD
 /* Irqfd support */
 static struct workqueue_struct *irqfd_cleanup_wq;
                ret = privcmd_ioctl_ioeventfd(file, udata);
                break;
 
+       case IOCTL_PRIVCMD_PCIDEV_GET_GSI:
+               ret = privcmd_ioctl_pcidev_get_gsi(file, udata);
+               break;
+
        default:
                break;
        }
 
 
        struct pci_dev *dev;
        struct xen_pcibk_device *pdev;/* non-NULL if struct pci_dev is in use */
+#ifdef CONFIG_XEN_ACPI
+       int gsi;
+#endif
 };
 
 /* Access to pcistub_devices & seized_devices lists and the initialize_devices
 
        kref_init(&psdev->kref);
        spin_lock_init(&psdev->lock);
+#ifdef CONFIG_XEN_ACPI
+       psdev->gsi = -1;
+#endif
 
        return psdev;
 }
        return pci_dev;
 }
 
+#ifdef CONFIG_XEN_ACPI
+int pcistub_get_gsi_from_sbdf(unsigned int sbdf)
+{
+       struct pcistub_device *psdev;
+       int domain = (sbdf >> 16) & 0xffff;
+       int bus = PCI_BUS_NUM(sbdf);
+       int slot = PCI_SLOT(sbdf);
+       int func = PCI_FUNC(sbdf);
+
+       psdev = pcistub_device_find(domain, bus, slot, func);
+
+       if (!psdev)
+               return -ENODEV;
+
+       return psdev->gsi;
+}
+EXPORT_SYMBOL_GPL(pcistub_get_gsi_from_sbdf);
+#endif
+
 struct pci_dev *pcistub_get_pci_dev_by_slot(struct xen_pcibk_device *pdev,
                                            int domain, int bus,
                                            int slot, int func)
        return found;
 }
 
-static int pcistub_init_device(struct pci_dev *dev)
+static int pcistub_init_device(struct pcistub_device *psdev)
 {
        struct xen_pcibk_dev_data *dev_data;
+       struct pci_dev *dev;
 #ifdef CONFIG_XEN_ACPI
        int gsi, trigger, polarity;
 #endif
        int err = 0;
 
+       if (!psdev)
+               return -EINVAL;
+
+       dev = psdev->dev;
+
        dev_dbg(&dev->dev, "initializing...\n");
 
        /* The PCI backend is not intended to be a module (or to work with
                err = xen_pvh_setup_gsi(gsi, trigger, polarity);
                if (err)
                        goto config_release;
+               psdev->gsi = gsi;
        }
 #endif
 
 
                spin_unlock_irqrestore(&pcistub_devices_lock, flags);
 
-               err = pcistub_init_device(psdev->dev);
+               err = pcistub_init_device(psdev);
                if (err) {
                        dev_err(&psdev->dev->dev,
                                "error %d initializing device\n", err);
                spin_unlock_irqrestore(&pcistub_devices_lock, flags);
 
                /* don't want irqs disabled when calling pcistub_init_device */
-               err = pcistub_init_device(psdev->dev);
+               err = pcistub_init_device(psdev);
 
                spin_lock_irqsave(&pcistub_devices_lock, flags);
 
 
        __u8 pad[2];
 };
 
+struct privcmd_pcidev_get_gsi {
+       __u32 sbdf;
+       __u32 gsi;
+};
+
 /*
  * @cmd: IOCTL_PRIVCMD_HYPERCALL
  * @arg: &privcmd_hypercall_t
        _IOW('P', 8, struct privcmd_irqfd)
 #define IOCTL_PRIVCMD_IOEVENTFD                                        \
        _IOW('P', 9, struct privcmd_ioeventfd)
+#define IOCTL_PRIVCMD_PCIDEV_GET_GSI                           \
+       _IOC(_IOC_NONE, 'P', 10, sizeof(struct privcmd_pcidev_get_gsi))
 
 #endif /* __LINUX_PUBLIC_PRIVCMD_H__ */