From patchwork Mon Oct 17 09:28:13 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jan Kiszka X-Patchwork-Id: 120154 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [140.186.70.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 23711B6F98 for ; Mon, 17 Oct 2011 21:49:05 +1100 (EST) Received: from localhost ([::1]:54885 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RFjX1-0001Cy-P9 for incoming@patchwork.ozlabs.org; Mon, 17 Oct 2011 05:30:51 -0400 Received: from eggs.gnu.org ([140.186.70.92]:33205) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RFjUz-0005fp-HG for qemu-devel@nongnu.org; Mon, 17 Oct 2011 05:28:53 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1RFjUm-0004N0-UY for qemu-devel@nongnu.org; Mon, 17 Oct 2011 05:28:44 -0400 Received: from david.siemens.de ([192.35.17.14]:19130) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RFjUm-0004MA-IV for qemu-devel@nongnu.org; Mon, 17 Oct 2011 05:28:32 -0400 Received: from mail1.siemens.de (localhost [127.0.0.1]) by david.siemens.de (8.13.6/8.13.6) with ESMTP id p9H9SVsQ023743; Mon, 17 Oct 2011 11:28:31 +0200 Received: from mchn199C.mchp.siemens.de ([139.25.109.49]) by mail1.siemens.de (8.13.6/8.13.6) with ESMTP id p9H9SKVt023511; Mon, 17 Oct 2011 11:28:31 +0200 From: Jan Kiszka To: Avi Kivity , Marcelo Tosatti Date: Mon, 17 Oct 2011 11:28:13 +0200 Message-Id: X-Mailer: git-send-email 1.7.3.4 In-Reply-To: References: In-Reply-To: References: X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6, seldom 2.4 (older, 4) X-Received-From: 192.35.17.14 Cc: Alex Williamson , qemu-devel@nongnu.org, kvm@vger.kernel.org, "Michael S. Tsirkin" Subject: [Qemu-devel] [RFC][PATCH 39/45] pci-assign: Use generic MSI support X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Implement MSI support of a assigned devices via the generic MSI layer of QEMU. Use config notifiers to update the vector route or switch back to INTx when MSI gets disabled again. Using the generic layer not only saves a bit code, it also fixes reset while legacy MSI is in use and adds 64 bit support. Signed-off-by: Jan Kiszka --- hw/device-assignment.c | 77 +++++++++++++++++++---------------------------- 1 files changed, 31 insertions(+), 46 deletions(-) diff --git a/hw/device-assignment.c b/hw/device-assignment.c index 2484afd..10b30a3 100644 --- a/hw/device-assignment.c +++ b/hw/device-assignment.c @@ -699,10 +699,6 @@ static void free_assigned_device(AssignedDevice *dev) close(dev->real_device.config_fd); } - if (dev->dev.msi_cache) { - kvm_msi_cache_invalidate(&dev->dev.msi_cache[0]); - g_free(dev->dev.msi_cache); - } invalidate_msix_vectors(dev); g_free(dev->dev.msix_cache); } @@ -847,7 +843,7 @@ static int assign_intx(AssignedDevice *dev) irq_type = KVM_DEV_IRQ_GUEST_INTX; if (dev->features & ASSIGNED_DEVICE_PREFER_MSI_MASK && - dev->cap.available & ASSIGNED_DEVICE_CAP_MSI) { + msi_present(&dev->dev)) { irq_type |= KVM_DEV_IRQ_HOST_MSI; } else { irq_type |= KVM_DEV_IRQ_HOST_INTX; @@ -920,31 +916,33 @@ void assigned_dev_update_irqs(void) } } -static void assigned_dev_update_msi(PCIDevice *pci_dev) +static void assigned_dev_update_msi(PCIDevice *pci_dev, bool enabled) { AssignedDevice *dev = DO_UPCAST(AssignedDevice, dev, pci_dev); - uint8_t ctrl_byte = pci_get_byte(pci_dev->config + pci_dev->msi_cap + - PCI_MSI_FLAGS); - - if (ctrl_byte & PCI_MSI_FLAGS_ENABLE) { - uint8_t *pos = pci_dev->config + pci_dev->msi_cap; - MSIMessage msg; - deassign_irq(dev); + if (!enabled) { + assign_intx(dev); + } +} - msg.address = pci_get_long(pos + PCI_MSI_ADDRESS_LO); - msg.data = pci_get_word(pos + PCI_MSI_DATA_32); +static int assigned_dev_update_msi_vector(PCIDevice *pci_dev, + unsigned int vector, + MSIMessage *msg, bool masked) +{ + AssignedDevice *dev = DO_UPCAST(AssignedDevice, dev, pci_dev); + int ret; - if (kvm_device_msi_assign(kvm_state, calc_assigned_dev_id(dev), &msg, - &dev->dev.msi_cache[0]) < 0) { - perror("assigned_dev_update_msi: assign msi"); - return; + if (!masked) { + deassign_irq(dev); + ret = kvm_device_msi_assign(kvm_state, calc_assigned_dev_id(dev), msg, + &dev->dev.msi_cache[0]); + if (ret < 0) { + perror("assigned_dev_update_msi_vector: assign msi"); + return ret; } dev->irq_requested_type = KVM_DEV_IRQ_HOST_MSI | KVM_DEV_IRQ_GUEST_MSI; - } else { - kvm_msi_cache_invalidate(&dev->dev.msi_cache[0]); - assign_intx(dev); } + return 0; } static int assigned_dev_set_msix_vectors(PCIDevice *pci_dev) @@ -1085,12 +1083,6 @@ static void assigned_dev_pci_write_config(PCIDevice *pci_dev, uint32_t address, pci_default_write_config(pci_dev, address, val, len); - if (assigned_dev->cap.available & ASSIGNED_DEVICE_CAP_MSI) { - if (range_covers_byte(address, len, - pci_dev->msi_cap + PCI_MSI_FLAGS)) { - assigned_dev_update_msi(pci_dev); - } - } if (assigned_dev->cap.available & ASSIGNED_DEVICE_CAP_MSIX) { if (range_covers_byte(address, len, pci_dev->msix_cap + PCI_MSIX_FLAGS + 1)) { @@ -1136,26 +1128,19 @@ static int assigned_device_pci_cap_init(PCIDevice *pci_dev) * MSI capability is the 1st capability in capability config */ pos = pci_find_cap_offset(pci_dev, PCI_CAP_ID_MSI, 0); if (pos != 0 && kvm_check_extension(kvm_state, KVM_CAP_ASSIGN_DEV_IRQ)) { - dev->cap.available |= ASSIGNED_DEVICE_CAP_MSI; - /* Only 32-bit/no-mask currently supported */ - if ((ret = pci_add_capability(pci_dev, PCI_CAP_ID_MSI, pos, 10)) < 0) { + uint16_t flags = pci_get_word(pci_dev->config + pos + PCI_MSI_FLAGS); + + /* Note: KVM does not support multiple messages */ + ret = msi_init(pci_dev, pos, 1, flags & PCI_MSI_FLAGS_64BIT, + flags & PCI_MSI_FLAGS_MASKBIT); + if (ret < 0) { + return ret; + } + ret = msi_set_config_notifiers(pci_dev, assigned_dev_update_msi, + assigned_dev_update_msi_vector); + if (ret < 0) { return ret; } - pci_dev->msi_cap = pos; - - pci_set_word(pci_dev->config + pos + PCI_MSI_FLAGS, - pci_get_word(pci_dev->config + pos + PCI_MSI_FLAGS) & - PCI_MSI_FLAGS_QMASK); - pci_set_long(pci_dev->config + pos + PCI_MSI_ADDRESS_LO, 0); - pci_set_word(pci_dev->config + pos + PCI_MSI_DATA_32, 0); - - /* Set writable fields */ - pci_set_word(pci_dev->wmask + pos + PCI_MSI_FLAGS, - PCI_MSI_FLAGS_QSIZE | PCI_MSI_FLAGS_ENABLE); - pci_set_long(pci_dev->wmask + pos + PCI_MSI_ADDRESS_LO, 0xfffffffc); - pci_set_word(pci_dev->wmask + pos + PCI_MSI_DATA_32, 0xffff); - - dev->dev.msi_cache = g_malloc0(sizeof(MSIRoutingCache)); } /* Expose MSI-X capability */ pos = pci_find_cap_offset(pci_dev, PCI_CAP_ID_MSIX, 0);