From patchwork Sat Oct 30 16:59:48 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alex Williamson X-Patchwork-Id: 292222 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id o9UH1FHl031711 for ; Sat, 30 Oct 2010 17:01:15 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756423Ab0J3RAI (ORCPT ); Sat, 30 Oct 2010 13:00:08 -0400 Received: from mx1.redhat.com ([209.132.183.28]:43756 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1756027Ab0J3Q7u (ORCPT ); Sat, 30 Oct 2010 12:59:50 -0400 Received: from int-mx01.intmail.prod.int.phx2.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) by mx1.redhat.com (8.13.8/8.13.8) with ESMTP id o9UGxn0j022752 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Sat, 30 Oct 2010 12:59:50 -0400 Received: from s20.home (ovpn01.gateway.prod.ext.phx2.redhat.com [10.5.9.1]) by int-mx01.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id o9UGxmat023176; Sat, 30 Oct 2010 12:59:49 -0400 From: Alex Williamson Subject: [PATCH 4/5] vfio: Add support for non-PCI 2.3 compliant devices To: pugs@cisco.com Cc: linux-kernel@vger.kernel.org, linux-pci@vger.kernel.org, kvm@vger.kernel.org, avi@redhat.com, chrisw@redhat.com, mst@redhat.com, alex.williamson@redhat.com Date: Sat, 30 Oct 2010 10:59:48 -0600 Message-ID: <20101030165944.885.7174.stgit@s20.home> In-Reply-To: <20101030164626.885.89216.stgit@s20.home> References: <20101030164626.885.89216.stgit@s20.home> User-Agent: StGIT/0.14.3 MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.67 on 10.5.11.11 Sender: linux-pci-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pci@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter1.kernel.org [140.211.167.41]); Sat, 30 Oct 2010 17:01:15 +0000 (UTC) diff --git a/drivers/vfio/vfio_intrs.c b/drivers/vfio/vfio_intrs.c index a57d5aa..4d5a7f8 100644 --- a/drivers/vfio/vfio_intrs.c +++ b/drivers/vfio/vfio_intrs.c @@ -52,32 +52,44 @@ irqreturn_t vfio_interrupt(int irq, void *dev_id) u16 origcmd, newcmd, status; spin_lock_irq(&vdev->irqlock); - pci_block_user_cfg_access(pdev); - - /* Read both command and status registers in a single 32-bit operation. - * Note: we could cache the value for command and move the status read - * out of the lock if there was a way to get notified of user changes - * to command register through sysfs. Should be good for shared irqs. */ - pci_read_config_dword(pdev, PCI_COMMAND, &cmd_status_dword); - origcmd = cmd_status_dword; - status = cmd_status_dword >> 16; - - /* Check interrupt status register to see whether our device - * triggered the interrupt. */ - if (!(status & PCI_STATUS_INTERRUPT)) - goto done; - - /* We triggered the interrupt, disable it. */ - newcmd = origcmd | PCI_COMMAND_INTX_DISABLE; - if (newcmd != origcmd) - pci_write_config_word(pdev, PCI_COMMAND, newcmd); - - ret = IRQ_HANDLED; + + if (vdev->pci_2_3) { + pci_block_user_cfg_access(pdev); + + /* Read both command and status registers in a single 32-bit + * operation. Note: we could cache the value for command and + * move the status read out of the lock if there was a way to + * get notified of user changes to command register through + * sysfs. Should be good for shared irqs. */ + pci_read_config_dword(pdev, PCI_COMMAND, &cmd_status_dword); + origcmd = cmd_status_dword; + status = cmd_status_dword >> 16; + + /* Check interrupt status register to see whether our device + * triggered the interrupt. */ + if (!(status & PCI_STATUS_INTERRUPT)) + goto done; + + /* We triggered the interrupt, disable it. */ + newcmd = origcmd | PCI_COMMAND_INTX_DISABLE; + if (newcmd != origcmd) + pci_write_config_word(pdev, PCI_COMMAND, newcmd); + + ret = IRQ_HANDLED; done: - pci_unblock_user_cfg_access(pdev); + pci_unblock_user_cfg_access(pdev); + } else { + disable_irq_nosync(pdev->irq); + ret = IRQ_HANDLED; + } + + vdev->irq_disabled = (ret == IRQ_HANDLED); + spin_unlock_irq(&vdev->irqlock); + if (ret != IRQ_HANDLED) return ret; + if (vdev->ev_irq) eventfd_signal(vdev->ev_irq, 1); return ret; @@ -86,16 +98,25 @@ done: int vfio_irq_eoi(struct vfio_dev *vdev) { struct pci_dev *pdev = vdev->pdev; - u16 cmd; spin_lock_irq(&vdev->irqlock); - pci_block_user_cfg_access(pdev); - pci_read_config_word(pdev, PCI_COMMAND, &cmd); - cmd &= ~PCI_COMMAND_INTX_DISABLE; - pci_write_config_word(pdev, PCI_COMMAND, cmd); + if (vdev->irq_disabled) { + if (vdev->pci_2_3) { + u16 cmd; + pci_block_user_cfg_access(pdev); + + pci_read_config_word(pdev, PCI_COMMAND, &cmd); + cmd &= ~PCI_COMMAND_INTX_DISABLE; + pci_write_config_word(pdev, PCI_COMMAND, cmd); + + pci_unblock_user_cfg_access(pdev); + } else + enable_irq(pdev->irq); + + vdev->irq_disabled = false; + } - pci_unblock_user_cfg_access(pdev); spin_unlock_irq(&vdev->irqlock); return 0; } diff --git a/drivers/vfio/vfio_main.c b/drivers/vfio/vfio_main.c index 72db79c..cf2e671 100644 --- a/drivers/vfio/vfio_main.c +++ b/drivers/vfio/vfio_main.c @@ -401,7 +401,8 @@ static long vfio_unl_ioctl(struct file *filep, if (vdev->ev_irq) ret = request_irq(pdev->irq, vfio_interrupt, - IRQF_SHARED, vdev->name, vdev); + vdev->pci_2_3 ? IRQF_SHARED : 0, + vdev->name, vdev); else ret = -EINVAL; } @@ -567,8 +568,8 @@ static int verify_pci_2_3(struct pci_dev *pdev) return -EBUSY; } if (!((new ^ orig) & PCI_COMMAND_INTX_DISABLE)) { - dev_warn(&pdev->dev, "Device does not support " - "disabling interrupts: unable to bind.\n"); + dev_warn(&pdev->dev, "Device does not support disabling " + "interrupts, exclusive interrupt required.\n"); return -ENODEV; } /* Now restore the original value. */ @@ -589,15 +590,13 @@ static int vfio_probe(struct pci_dev *pdev, const struct pci_device_id *id) if ((type & 0x7F) != PCI_HEADER_TYPE_NORMAL) return -EINVAL; - err = verify_pci_2_3(pdev); - if (err) - return err; - vdev = kzalloc(sizeof(struct vfio_dev), GFP_KERNEL); if (!vdev) return -ENOMEM; vdev->pdev = pdev; + vdev->pci_2_3 = (verify_pci_2_3(pdev) == 0); + mutex_init(&vdev->lgate); mutex_init(&vdev->dgate); mutex_init(&vdev->igate); diff --git a/include/linux/vfio.h b/include/linux/vfio.h index 73d7e84..f7e51ff 100644 --- a/include/linux/vfio.h +++ b/include/linux/vfio.h @@ -77,6 +77,8 @@ struct vfio_dev { u8 msi_qmax; u8 bardirty; struct perm_bits *msi_perm; + bool pci_2_3; + bool irq_disabled; }; struct vfio_listener {