From patchwork Fri Jul 24 09:03:10 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: PranavkumarSawargaonkar X-Patchwork-Id: 6858531 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id C1032C05AC for ; Fri, 24 Jul 2015 09:10:50 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id BC3CD20603 for ; Fri, 24 Jul 2015 09:10:49 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id CBAC1205BD for ; Fri, 24 Jul 2015 09:10:44 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1ZIYy5-000200-MA; Fri, 24 Jul 2015 09:08:37 +0000 Received: from mail-pd0-f176.google.com ([209.85.192.176]) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1ZIYtc-0004PW-Rz for linux-arm-kernel@lists.infradead.org; Fri, 24 Jul 2015 09:04:12 +0000 Received: by pdrg1 with SMTP id g1so10825364pdr.2 for ; Fri, 24 Jul 2015 02:03:37 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=J2ysj2wzyFd8jLaJ+x0WaR0v7SLk5C3ZrnH5UdcuM7o=; b=cbkukzt452XI8LFHJ68EiiHLZuLNIXFna3g3wLf59lQOGFMNcD5UxDhrzew0eVcUVy VYhxyhcO3USG0yaCvopYzq9GAmwZDC+P1cj6W+kndj8l3qSkM2f4Dzug3y7Cp4bXJ9tK di/zmAjsM7xczfBia0eDXycqqZuk2hSKtkI3Lc+y1o/AtWNrvdd4xC7jNnaxIrEreiF1 b5iYMPUd7XFon9NJ/x8S9dpMSh2OD4FV2M56FuSu/mT2bIbwdEht3M2u2FLM93UPBecM A4FeM5mUL2m3fyrfaQ+9ugytSa+uXRxyz4qV0jMex3Xg08Bd6onA7h4JJx++CQJayPHO oV/A== X-Gm-Message-State: ALoCoQmSi3y20DHh2d7xHJU6WunF/VDqQo+TLYM8Q0xgPtH8UX1jZ9sgsIETcrYZiRItvTPZ/3Sc X-Received: by 10.70.136.129 with SMTP id qa1mr28477321pdb.81.1437728617615; Fri, 24 Jul 2015 02:03:37 -0700 (PDT) Received: from pnqlab006.amcc.com ([182.73.239.130]) by smtp.gmail.com with ESMTPSA id wp5sm13346655pab.22.2015.07.24.02.03.32 (version=TLSv1.1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Fri, 24 Jul 2015 02:03:36 -0700 (PDT) From: Pranavkumar Sawargaonkar To: kvm@vger.kernel.org, kvmarm@lists.cs.columbia.edu Subject: [RFC 2/2] drivers: vfio: pci: Add virtual MSI doorbell support. Date: Fri, 24 Jul 2015 14:33:10 +0530 Message-Id: <1437728590-23126-3-git-send-email-pranavkumar@linaro.org> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1437728590-23126-1-git-send-email-pranavkumar@linaro.org> References: <1437728590-23126-1-git-send-email-pranavkumar@linaro.org> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20150724_020401_543098_AD011E42 X-CRM114-Status: GOOD ( 17.79 ) X-Spam-Score: -2.6 (--) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: rob.herring@linaro.org, arnd@arndb.de, eric.auger@linaro.org, marc.zyngier@arm.com, patches@apm.com, will.deacon@arm.com, linux-kernel@vger.kernel.org, alex.williamson@redhat.com, linux-arm-kernel@lists.infradead.org, bhelgaas@google.com, Ankit Jindal , christoffer.dall@linaro.org, Pranavkumar Sawargaonkar MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-5.4 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP In ARM/ARM64 MSI transactions goes through iommu/smmu. This means there has to be an iommu mapping created for MSI addresses. This patch adds a new ioctl "VFIO_DEVICE_PCI_MSI_VIRT_DOORBELL". Userspace can call this ioctl to do following things: 1. Create a virtual doorbell mapping between MSI IOVA term as a "virtual msi doorbell" (known by the userspace) and MSI PA (known by the kernel). 2. Set MSI/MSI-X vetcor with a virtual doorbell address instead of PA. Signed-off-by: Ankit Jindal Signed-off-by: Pranavkumar Sawargaonkar Cc: Alex Williamson Cc: Marc Zyngier Cc: Will Deacon Cc: Christoffer Dall --- drivers/vfio/pci/vfio_pci.c | 32 ++++++++++++++++++ drivers/vfio/pci/vfio_pci_intrs.c | 64 +++++++++++++++++++++++++++++++++++ drivers/vfio/pci/vfio_pci_private.h | 3 ++ include/uapi/linux/vfio.h | 19 +++++++++++ 4 files changed, 118 insertions(+) diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c index 964ad57..9c92707 100644 --- a/drivers/vfio/pci/vfio_pci.c +++ b/drivers/vfio/pci/vfio_pci.c @@ -784,6 +784,38 @@ hot_reset_release: kfree(groups); return ret; + } else if (cmd == VFIO_DEVICE_PCI_MSI_VIRT_DOORBELL) { + struct vfio_pci_msi_virt_doorbell hdr; + u64 *data = NULL; + int ret = 0; + size_t size = sizeof(uint64_t); + + minsz = offsetofend(struct vfio_pci_msi_virt_doorbell, count); + + if (copy_from_user(&hdr, (void __user *)arg, minsz)) + return -EFAULT; + + if (hdr.argsz < minsz) + return -EINVAL; + + if (hdr.argsz - minsz < hdr.count * size) + return -EINVAL; + + data = memdup_user((void __user *)(arg + minsz), + hdr.count * size); + if (IS_ERR(data)) + return PTR_ERR(data); + + mutex_lock(&vdev->igate); + + ret = vfio_pci_msi_virt_doorbell(vdev, hdr.flags, + hdr.start, hdr.count, data); + + mutex_unlock(&vdev->igate); + + kfree(data); + + return ret; } return -ENOTTY; diff --git a/drivers/vfio/pci/vfio_pci_intrs.c b/drivers/vfio/pci/vfio_pci_intrs.c index 1f577b4..22a25b8 100644 --- a/drivers/vfio/pci/vfio_pci_intrs.c +++ b/drivers/vfio/pci/vfio_pci_intrs.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -352,8 +353,10 @@ static int vfio_msi_set_vector_signal(struct vfio_pci_device *vdev, pci_write_msi_msg(irq, &msg); } + ret = request_irq(irq, vfio_msihandler, 0, vdev->ctx[vector].name, trigger); + if (ret) { kfree(vdev->ctx[vector].name); eventfd_ctx_put(trigger); @@ -673,3 +676,64 @@ int vfio_pci_set_irqs_ioctl(struct vfio_pci_device *vdev, uint32_t flags, return func(vdev, index, start, count, flags, data); } + +int vfio_pci_msi_virt_doorbell(struct vfio_pci_device *vdev, uint32_t flags, + unsigned start, unsigned count, + void *data) +{ + struct pci_dev *pdev = vdev->pdev; + int irq; + bool msix = flags & VFIO_PCI_IS_MSIX; + struct msi_msg msg; + struct irq_data *d; + unsigned long msi_paddr, msi_iova; + struct vfio_device *device; + int ret; + int i, j; + + for (i = 0, j = start; i < count && !ret; i++, j++) { + + device = vfio_device_get_from_dev(&pdev->dev); + irq = msix ? vdev->msix[j].vector : + pdev->irq + j; + + if (flags & VFIO_PCI_MSI_SET_DOORBELL) { + /* Get the MSI message to extract Physical Address */ + d = irq_get_irq_data(irq); + irq_chip_compose_msi_msg(d, &msg); + msi_paddr = (msg.address_hi << 31) | msg.address_lo; + } else { + /* + * Restore the cached value of the message prior + * to the virtual doorbell setting. + */ + get_cached_msi_msg(irq, &msg); + } + + /* MSI IPA/GPA i.e. virtual doorbell address */ + msi_iova = (unsigned long) ((unsigned long *) data)[i]; + + if (flags & VFIO_PCI_MSI_SET_DOORBELL) { + ret = vfio_device_iommu_map(device, + (msi_iova & PAGE_MASK), + (msi_paddr & PAGE_MASK), + PAGE_SIZE, + IOMMU_READ | IOMMU_WRITE | + IOMMU_CACHE); + + /* Fill MSI GPA/IPA as a new MSI doorbell address. */ + msg.address_hi = msi_iova << 31; + msg.address_lo = msi_iova & 0xFFFFFFFF; + } else if (flags & VFIO_PCI_MSI_CLEAR_DOORBELL) { + vfio_device_iommu_unmap(device, (msi_iova & PAGE_MASK), + PAGE_SIZE); + } else { + return -EINVAL; + } + + pci_write_msi_msg(irq, &msg); + } + + return 0; +} + diff --git a/drivers/vfio/pci/vfio_pci_private.h b/drivers/vfio/pci/vfio_pci_private.h index ae0e1b4..ec76e45 100644 --- a/drivers/vfio/pci/vfio_pci_private.h +++ b/drivers/vfio/pci/vfio_pci_private.h @@ -73,6 +73,9 @@ extern void vfio_pci_intx_unmask(struct vfio_pci_device *vdev); extern int vfio_pci_set_irqs_ioctl(struct vfio_pci_device *vdev, uint32_t flags, unsigned index, unsigned start, unsigned count, void *data); +extern int vfio_pci_msi_virt_doorbell(struct vfio_pci_device *vdev, + uint32_t flags, unsigned start, + unsigned count, void *data); extern ssize_t vfio_pci_config_rw(struct vfio_pci_device *vdev, char __user *buf, size_t count, diff --git a/include/uapi/linux/vfio.h b/include/uapi/linux/vfio.h index 9fd7b5d..12384f5 100644 --- a/include/uapi/linux/vfio.h +++ b/include/uapi/linux/vfio.h @@ -379,6 +379,25 @@ struct vfio_pci_hot_reset { #define VFIO_DEVICE_PCI_HOT_RESET _IO(VFIO_TYPE, VFIO_BASE + 13) +/** + * VFIO_DEVICE_PCI_MSI_VIRT_DOORBELL - _IOW(VFIO_TYPE, VFIO_BASE + 14, + * struct vfio_pci_msi_virt_doorbell) + * + * Return: 0 on success, -errno on failure. + */ +struct vfio_pci_msi_virt_doorbell { + __u32 argsz; + __u32 flags; +#define VFIO_PCI_MSI_CLEAR_DOORBELL (1 << 0) /* Remove virtual doorbell */ +#define VFIO_PCI_MSI_SET_DOORBELL (1 << 1) /* Set virtual doorbell */ +#define VFIO_PCI_IS_MSIX (1 << 2) /* Is MSI-X ? */ + __u32 start; + __u32 count; + __u64 data[]; +}; + +#define VFIO_DEVICE_PCI_MSI_VIRT_DOORBELL _IO(VFIO_TYPE, VFIO_BASE + 14) + /* -------- API for Type1 VFIO IOMMU -------- */ /**