Received: by 2002:a05:6902:102b:0:0:0:0 with SMTP id x11csp262570ybt; Mon, 6 Jul 2020 08:44:31 -0700 (PDT) X-Google-Smtp-Source: ABdhPJxHts0v1C2snC915kC8tKzlhSPErQf7naIn+luP009XyitQfGvb2PX8jy5P4jynR9NNGlfr X-Received: by 2002:a17:906:199b:: with SMTP id g27mr42190811ejd.297.1594050271033; Mon, 06 Jul 2020 08:44:31 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1594050271; cv=none; d=google.com; s=arc-20160816; b=DedpuuIjyKG/XHJOXJQelrmtIp5dsdRtgOcgHNxx2ScnkvpbaCu9aw2f39q5iw5NME KIeH3x0CARoAt2UMARZXeSAkkCV3qmwiT+FE+9cJ7vqWM+yPlW3drB2n3ZbnUs/GzMTE EIrRKWqGzp+rrlgUf34N7Yeb9xe5DNQV4xNhkEyWBnxT3uVM/YSPBriQxa2WCUnR+IW5 wn47Ewt7LLTQ2kzgMPL9Zk//sM9qFfW+r7xzWrufHRtt+n0lKPJqBmq5PITcmtvHeRoL fNS9CGuandmDRRL2+M0sEvau8XUQ51/FGlWuNj+yP01Qm/SnrNU6bcaAbe0DZNRFqnNC EPuQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from; bh=wDV9ib2NgUFgCskRgBlLrj/Zf1JWLwvKLdnD0Rek4Hg=; b=O6LFABO1N8gSrzEKUGeB5U39XMbox7Athxi1c2EUmhCI0LyOFeb96eZrtwYWm3pzAa ylEnFxZzOKOnE1dFkB2jLLeyeXG2zvImdHsx9KIlCkZoWBwtdJYVMjwKp75nGCXve8/y R8/WTc4Cf2kPywZGjPagUE5Yi4Wn9gEALfOmf7TuJam56j6aA/LC54r4BxO6c4s8r7c0 1HqV93gwliJkxTl0+bT55sZUGIIdvNQvJodcaE7p7URhOEtN/ymeRZyV8zm4B/+AsUPH IC5jaUk6Vban5E8GUIOsbtcuX/EHpBaCM0JhP20A63hNhpYFZ7bG6kdCSW7FJDwnAUGu 7xew== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=nxp.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id f15si12584581edt.552.2020.07.06.08.44.08; Mon, 06 Jul 2020 08:44:31 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=nxp.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729667AbgGFPmy (ORCPT + 99 others); Mon, 6 Jul 2020 11:42:54 -0400 Received: from inva021.nxp.com ([92.121.34.21]:36286 "EHLO inva021.nxp.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729474AbgGFPmS (ORCPT ); Mon, 6 Jul 2020 11:42:18 -0400 Received: from inva021.nxp.com (localhost [127.0.0.1]) by inva021.eu-rdc02.nxp.com (Postfix) with ESMTP id 4CF932006DF; Mon, 6 Jul 2020 17:42:15 +0200 (CEST) Received: from inva024.eu-rdc02.nxp.com (inva024.eu-rdc02.nxp.com [134.27.226.22]) by inva021.eu-rdc02.nxp.com (Postfix) with ESMTP id 4A2D8200512; Mon, 6 Jul 2020 17:42:15 +0200 (CEST) Received: from fsr-ub1864-111.ea.freescale.net (fsr-ub1864-111.ea.freescale.net [10.171.82.141]) by inva024.eu-rdc02.nxp.com (Postfix) with ESMTP id F186B203C3; Mon, 6 Jul 2020 17:42:14 +0200 (CEST) From: Diana Craciun To: alex.williamson@redhat.com, kvm@vger.kernel.org Cc: bharatb.linux@gmail.com, linux-kernel@vger.kernel.org, laurentiu.tudor@nxp.com, Diana Craciun , Bharat Bhushan Subject: [PATCH v3 8/9] vfio/fsl-mc: trigger an interrupt via eventfd Date: Mon, 6 Jul 2020 18:41:52 +0300 Message-Id: <20200706154153.11477-9-diana.craciun@oss.nxp.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200706154153.11477-1-diana.craciun@oss.nxp.com> References: <20200706154153.11477-1-diana.craciun@oss.nxp.com> X-Virus-Scanned: ClamAV using ClamSMTP Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org This patch allows to set an eventfd for fsl-mc device interrupts and also to trigger the interrupt eventfd from userspace for testing. All fsl-mc device interrupts are MSIs. The MSIs are allocated from the MSI domain only once per DPRC and used by all the DPAA2 objects. The interrupts are managed by the DPRC in a pool of interrupts. Each device requests interrupts from this pool. The pool is allocated when the first virtual device is setting the interrupts. The pool of interrupts is protected by a lock. The DPRC has an interrupt of its own which indicates if the DPRC contents have changed. However, currently, the contents of a DPRC assigned to the guest cannot be changed at runtime, so this interrupt is not configured. Signed-off-by: Bharat Bhushan Signed-off-by: Diana Craciun --- drivers/vfio/fsl-mc/vfio_fsl_mc.c | 18 ++- drivers/vfio/fsl-mc/vfio_fsl_mc_intr.c | 160 +++++++++++++++++++++- drivers/vfio/fsl-mc/vfio_fsl_mc_private.h | 11 +- 3 files changed, 186 insertions(+), 3 deletions(-) diff --git a/drivers/vfio/fsl-mc/vfio_fsl_mc.c b/drivers/vfio/fsl-mc/vfio_fsl_mc.c index 2ce17d297145..0c2d4f11dc43 100644 --- a/drivers/vfio/fsl-mc/vfio_fsl_mc.c +++ b/drivers/vfio/fsl-mc/vfio_fsl_mc.c @@ -146,12 +146,28 @@ static int vfio_fsl_mc_open(void *device_data) static void vfio_fsl_mc_release(void *device_data) { struct vfio_fsl_mc_device *vdev = device_data; + int ret; mutex_lock(&vdev->reflck->lock); - if (!(--vdev->refcnt)) + if (!(--vdev->refcnt)) { + struct fsl_mc_device *mc_dev = vdev->mc_dev; + struct device *cont_dev = fsl_mc_cont_dev(&mc_dev->dev); + struct fsl_mc_device *mc_cont = to_fsl_mc_device(cont_dev); + vfio_fsl_mc_regions_cleanup(vdev); + /* reset the device before cleaning up the interrupts */ + ret = dprc_reset_container(mc_cont->mc_io, 0, + mc_cont->mc_handle, + mc_cont->obj_desc.id, + DPRC_RESET_OPTION_NON_RECURSIVE); + + vfio_fsl_mc_irqs_cleanup(vdev); + + fsl_mc_cleanup_irq_pool(mc_cont); + } + mutex_unlock(&vdev->reflck->lock); module_put(THIS_MODULE); diff --git a/drivers/vfio/fsl-mc/vfio_fsl_mc_intr.c b/drivers/vfio/fsl-mc/vfio_fsl_mc_intr.c index 058aa97aa54a..409f3507fcf3 100644 --- a/drivers/vfio/fsl-mc/vfio_fsl_mc_intr.c +++ b/drivers/vfio/fsl-mc/vfio_fsl_mc_intr.c @@ -29,12 +29,149 @@ static int vfio_fsl_mc_irq_unmask(struct vfio_fsl_mc_device *vdev, return -EINVAL; } +int vfio_fsl_mc_irqs_allocate(struct vfio_fsl_mc_device *vdev) +{ + struct fsl_mc_device *mc_dev = vdev->mc_dev; + struct vfio_fsl_mc_irq *mc_irq; + int irq_count; + int ret, i; + + /* Device does not support any interrupt */ + if (mc_dev->obj_desc.irq_count == 0) + return 0; + + /* interrupts were already allocated for this device */ + if (vdev->mc_irqs) + return 0; + + irq_count = mc_dev->obj_desc.irq_count; + + mc_irq = kcalloc(irq_count, sizeof(*mc_irq), GFP_KERNEL); + if (!mc_irq) + return -ENOMEM; + + /* Allocate IRQs */ + ret = fsl_mc_allocate_irqs(mc_dev); + if (ret) { + kfree(mc_irq); + return ret; + } + + for (i = 0; i < irq_count; i++) { + mc_irq[i].count = 1; + mc_irq[i].flags = VFIO_IRQ_INFO_EVENTFD; + } + + vdev->mc_irqs = mc_irq; + + return 0; +} + +static irqreturn_t vfio_fsl_mc_irq_handler(int irq_num, void *arg) +{ + struct vfio_fsl_mc_irq *mc_irq = (struct vfio_fsl_mc_irq *)arg; + + eventfd_signal(mc_irq->trigger, 1); + return IRQ_HANDLED; +} + +static int vfio_set_trigger(struct vfio_fsl_mc_device *vdev, + int index, int fd) +{ + struct vfio_fsl_mc_irq *irq = &vdev->mc_irqs[index]; + struct eventfd_ctx *trigger; + int hwirq; + int ret; + + hwirq = vdev->mc_dev->irqs[index]->msi_desc->irq; + if (irq->trigger) { + free_irq(hwirq, irq); + kfree(irq->name); + eventfd_ctx_put(irq->trigger); + irq->trigger = NULL; + } + + if (fd < 0) /* Disable only */ + return 0; + + irq->name = kasprintf(GFP_KERNEL, "vfio-irq[%d](%s)", + hwirq, dev_name(&vdev->mc_dev->dev)); + if (!irq->name) + return -ENOMEM; + + trigger = eventfd_ctx_fdget(fd); + if (IS_ERR(trigger)) { + kfree(irq->name); + return PTR_ERR(trigger); + } + + irq->trigger = trigger; + + ret = request_irq(hwirq, vfio_fsl_mc_irq_handler, 0, + irq->name, irq); + if (ret) { + kfree(irq->name); + eventfd_ctx_put(trigger); + irq->trigger = NULL; + return ret; + } + + return 0; +} + static int vfio_fsl_mc_set_irq_trigger(struct vfio_fsl_mc_device *vdev, unsigned int index, unsigned int start, unsigned int count, u32 flags, void *data) { - return -EINVAL; + struct fsl_mc_device *mc_dev = vdev->mc_dev; + int ret, hwirq; + struct vfio_fsl_mc_irq *irq; + struct device *cont_dev = fsl_mc_cont_dev(&mc_dev->dev); + struct fsl_mc_device *mc_cont = to_fsl_mc_device(cont_dev); + + if (start != 0 || count != 1) + return -EINVAL; + + mutex_lock(&vdev->reflck->lock); + ret = fsl_mc_populate_irq_pool(mc_cont, + FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS); + if (ret) + goto unlock; + + ret = vfio_fsl_mc_irqs_allocate(vdev); + if (ret) + goto unlock; + mutex_unlock(&vdev->reflck->lock); + + if (!count && (flags & VFIO_IRQ_SET_DATA_NONE)) + return vfio_set_trigger(vdev, index, -1); + + if (flags & VFIO_IRQ_SET_DATA_EVENTFD) { + s32 fd = *(s32 *)data; + + return vfio_set_trigger(vdev, index, fd); + } + + hwirq = vdev->mc_dev->irqs[index]->msi_desc->irq; + + irq = &vdev->mc_irqs[index]; + + if (flags & VFIO_IRQ_SET_DATA_NONE) { + vfio_fsl_mc_irq_handler(hwirq, irq); + + } else if (flags & VFIO_IRQ_SET_DATA_BOOL) { + u8 trigger = *(u8 *)data; + + if (trigger) + vfio_fsl_mc_irq_handler(hwirq, irq); + } + + return 0; + +unlock: + mutex_unlock(&vdev->reflck->lock); + return ret; } int vfio_fsl_mc_set_irqs_ioctl(struct vfio_fsl_mc_device *vdev, @@ -61,3 +198,24 @@ int vfio_fsl_mc_set_irqs_ioctl(struct vfio_fsl_mc_device *vdev, return ret; } + +/* Free All IRQs for the given MC object */ +void vfio_fsl_mc_irqs_cleanup(struct vfio_fsl_mc_device *vdev) +{ + struct fsl_mc_device *mc_dev = vdev->mc_dev; + int irq_count = mc_dev->obj_desc.irq_count; + int i; + + /* Device does not support any interrupt or the interrupts + * were not configured + */ + if (mc_dev->obj_desc.irq_count == 0 || !vdev->mc_irqs) + return; + + for (i = 0; i < irq_count; i++) + vfio_set_trigger(vdev, i, -1); + + fsl_mc_free_irqs(mc_dev); + kfree(vdev->mc_irqs); + vdev->mc_irqs = NULL; +} diff --git a/drivers/vfio/fsl-mc/vfio_fsl_mc_private.h b/drivers/vfio/fsl-mc/vfio_fsl_mc_private.h index dd94be84a3d0..1f9b518c520d 100644 --- a/drivers/vfio/fsl-mc/vfio_fsl_mc_private.h +++ b/drivers/vfio/fsl-mc/vfio_fsl_mc_private.h @@ -15,6 +15,13 @@ #define VFIO_FSL_MC_INDEX_TO_OFFSET(index) \ ((u64)(index) << VFIO_FSL_MC_OFFSET_SHIFT) +struct vfio_fsl_mc_irq { + u32 flags; + u32 count; + struct eventfd_ctx *trigger; + char *name; +}; + struct vfio_fsl_mc_reflck { struct kref kref; struct mutex lock; @@ -34,7 +41,7 @@ struct vfio_fsl_mc_device { u32 num_regions; struct vfio_fsl_mc_region *regions; struct vfio_fsl_mc_reflck *reflck; - + struct vfio_fsl_mc_irq *mc_irqs; }; extern int vfio_fsl_mc_set_irqs_ioctl(struct vfio_fsl_mc_device *vdev, @@ -42,4 +49,6 @@ extern int vfio_fsl_mc_set_irqs_ioctl(struct vfio_fsl_mc_device *vdev, unsigned int start, unsigned int count, void *data); +void vfio_fsl_mc_irqs_cleanup(struct vfio_fsl_mc_device *vdev); + #endif /* VFIO_FSL_MC_PRIVATE_H */ -- 2.17.1