From patchwork Wed Sep 23 20:23:58 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alex Williamson X-Patchwork-Id: 521848 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id ACC551401AF for ; Thu, 24 Sep 2015 06:29:44 +1000 (AEST) Received: from localhost ([::1]:50563 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Zeqfe-0001lU-Eu for incoming@patchwork.ozlabs.org; Wed, 23 Sep 2015 16:29:42 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:42911) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ZeqaC-0001Zy-ST for qemu-devel@nongnu.org; Wed, 23 Sep 2015 16:24:07 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Zeqa7-0003Hy-SL for qemu-devel@nongnu.org; Wed, 23 Sep 2015 16:24:04 -0400 Received: from mx1.redhat.com ([209.132.183.28]:41680) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Zeqa7-0003Hj-8i for qemu-devel@nongnu.org; Wed, 23 Sep 2015 16:23:59 -0400 Received: from int-mx14.intmail.prod.int.phx2.redhat.com (int-mx14.intmail.prod.int.phx2.redhat.com [10.5.11.27]) by mx1.redhat.com (Postfix) with ESMTPS id E7D6B8E6E3 for ; Wed, 23 Sep 2015 20:23:58 +0000 (UTC) Received: from gimli.home (ovpn-113-42.phx2.redhat.com [10.3.113.42]) by int-mx14.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id t8NKNwub013397; Wed, 23 Sep 2015 16:23:58 -0400 From: Alex Williamson To: qemu-devel@nongnu.org Date: Wed, 23 Sep 2015 14:23:58 -0600 Message-ID: <20150923202358.6569.29219.stgit@gimli.home> In-Reply-To: <20150923202200.6569.64538.stgit@gimli.home> References: <20150923202200.6569.64538.stgit@gimli.home> User-Agent: StGit/0.17.1-dirty MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.68 on 10.5.11.27 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PULL 10/19] vfio/pci: Foundation for new quirk structure 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 VFIOQuirk hosts a single memory region and a fixed set of data fields that try to handle all the quirk cases, but end up making those that don't exactly match really confusing. This patch introduces a struct intended to provide more flexibility and simpler code. VFIOQuirk is stripped to its basics, an opaque data pointer for quirk specific data and a pointer to an array of MemoryRegions with a counter. This still allows us to have common teardown routines, but adds much greater flexibility to support multiple memory regions and quirk specific data structures that are easier to maintain. The existing VFIOQuirk is transformed into VFIOLegacyQuirk, which further patches will eliminate entirely. Signed-off-by: Alex Williamson --- hw/vfio/pci-quirks.c | 249 ++++++++++++++++++++++++++++++-------------------- hw/vfio/pci.h | 12 ++ 2 files changed, 157 insertions(+), 104 deletions(-) diff --git a/hw/vfio/pci-quirks.c b/hw/vfio/pci-quirks.c index 17e300a..429fdad 100644 --- a/hw/vfio/pci-quirks.c +++ b/hw/vfio/pci-quirks.c @@ -80,7 +80,7 @@ static bool vfio_flags_enabled(uint8_t flags, uint8_t mask) static uint64_t vfio_generic_window_quirk_read(void *opaque, hwaddr addr, unsigned size) { - VFIOQuirk *quirk = opaque; + VFIOLegacyQuirk *quirk = opaque; VFIOPCIDevice *vdev = quirk->vdev; uint64_t data; @@ -92,13 +92,13 @@ static uint64_t vfio_generic_window_quirk_read(void *opaque, if (!vfio_range_contained(addr, size, quirk->data.data_offset, quirk->data.data_size)) { hw_error("%s: window data read not fully contained: %s", - __func__, memory_region_name(&quirk->mem)); + __func__, memory_region_name(quirk->mem)); } data = vfio_pci_read_config(&vdev->pdev, quirk->data.address_val + offset, size); - trace_vfio_generic_window_quirk_read(memory_region_name(&quirk->mem), + trace_vfio_generic_window_quirk_read(memory_region_name(quirk->mem), vdev->vbasedev.name, quirk->data.bar, addr, size, data); @@ -113,7 +113,7 @@ static uint64_t vfio_generic_window_quirk_read(void *opaque, static void vfio_generic_window_quirk_write(void *opaque, hwaddr addr, uint64_t data, unsigned size) { - VFIOQuirk *quirk = opaque; + VFIOLegacyQuirk *quirk = opaque; VFIOPCIDevice *vdev = quirk->vdev; if (ranges_overlap(addr, size, @@ -121,7 +121,7 @@ static void vfio_generic_window_quirk_write(void *opaque, hwaddr addr, if (addr != quirk->data.address_offset) { hw_error("%s: offset write into address window: %s", - __func__, memory_region_name(&quirk->mem)); + __func__, memory_region_name(quirk->mem)); } if ((data & ~quirk->data.address_mask) == quirk->data.address_match) { @@ -142,12 +142,12 @@ static void vfio_generic_window_quirk_write(void *opaque, hwaddr addr, if (!vfio_range_contained(addr, size, quirk->data.data_offset, quirk->data.data_size)) { hw_error("%s: window data write not fully contained: %s", - __func__, memory_region_name(&quirk->mem)); + __func__, memory_region_name(quirk->mem)); } vfio_pci_write_config(&vdev->pdev, quirk->data.address_val + offset, data, size); - trace_vfio_generic_window_quirk_write(memory_region_name(&quirk->mem), + trace_vfio_generic_window_quirk_write(memory_region_name(quirk->mem), vdev->vbasedev.name, quirk->data.bar, addr, data, size); @@ -167,7 +167,7 @@ static const MemoryRegionOps vfio_generic_window_quirk = { static uint64_t vfio_generic_quirk_read(void *opaque, hwaddr addr, unsigned size) { - VFIOQuirk *quirk = opaque; + VFIOLegacyQuirk *quirk = opaque; VFIOPCIDevice *vdev = quirk->vdev; hwaddr base = quirk->data.address_match & TARGET_PAGE_MASK; hwaddr offset = quirk->data.address_match & ~TARGET_PAGE_MASK; @@ -178,12 +178,12 @@ static uint64_t vfio_generic_quirk_read(void *opaque, if (!vfio_range_contained(addr, size, offset, quirk->data.address_mask + 1)) { hw_error("%s: read not fully contained: %s", - __func__, memory_region_name(&quirk->mem)); + __func__, memory_region_name(quirk->mem)); } data = vfio_pci_read_config(&vdev->pdev, addr - offset, size); - trace_vfio_generic_quirk_read(memory_region_name(&quirk->mem), + trace_vfio_generic_quirk_read(memory_region_name(quirk->mem), vdev->vbasedev.name, quirk->data.bar, addr + base, size, data); } else { @@ -197,7 +197,7 @@ static uint64_t vfio_generic_quirk_read(void *opaque, static void vfio_generic_quirk_write(void *opaque, hwaddr addr, uint64_t data, unsigned size) { - VFIOQuirk *quirk = opaque; + VFIOLegacyQuirk *quirk = opaque; VFIOPCIDevice *vdev = quirk->vdev; hwaddr base = quirk->data.address_match & TARGET_PAGE_MASK; hwaddr offset = quirk->data.address_match & ~TARGET_PAGE_MASK; @@ -207,12 +207,12 @@ static void vfio_generic_quirk_write(void *opaque, hwaddr addr, if (!vfio_range_contained(addr, size, offset, quirk->data.address_mask + 1)) { hw_error("%s: write not fully contained: %s", - __func__, memory_region_name(&quirk->mem)); + __func__, memory_region_name(quirk->mem)); } vfio_pci_write_config(&vdev->pdev, addr - offset, data, size); - trace_vfio_generic_quirk_write(memory_region_name(&quirk->mem), + trace_vfio_generic_quirk_write(memory_region_name(quirk->mem), vdev->vbasedev.name, quirk->data.bar, addr + base, data, size); } else { @@ -242,7 +242,7 @@ static const MemoryRegionOps vfio_generic_quirk = { static uint64_t vfio_ati_3c3_quirk_read(void *opaque, hwaddr addr, unsigned size) { - VFIOQuirk *quirk = opaque; + VFIOLegacyQuirk *quirk = opaque; VFIOPCIDevice *vdev = quirk->vdev; uint64_t data = vfio_pci_read_config(&vdev->pdev, PCI_BASE_ADDRESS_0 + (4 * 4) + 1, @@ -261,6 +261,7 @@ static void vfio_vga_probe_ati_3c3_quirk(VFIOPCIDevice *vdev) { PCIDevice *pdev = &vdev->pdev; VFIOQuirk *quirk; + VFIOLegacyQuirk *legacy; if (pci_get_word(pdev->config + PCI_VENDOR_ID) != PCI_VENDOR_ID_ATI) { return; @@ -275,12 +276,15 @@ static void vfio_vga_probe_ati_3c3_quirk(VFIOPCIDevice *vdev) } quirk = g_malloc0(sizeof(*quirk)); - quirk->vdev = vdev; + legacy = quirk->data = g_malloc0(sizeof(*legacy)); + quirk->mem = legacy->mem = g_malloc0_n(sizeof(MemoryRegion), 1); + quirk->nr_mem = 1; + legacy->vdev = vdev; - memory_region_init_io(&quirk->mem, OBJECT(vdev), &vfio_ati_3c3_quirk, quirk, + memory_region_init_io(quirk->mem, OBJECT(vdev), &vfio_ati_3c3_quirk, legacy, "vfio-ati-3c3-quirk", 1); memory_region_add_subregion(&vdev->vga.region[QEMU_PCI_VGA_IO_HI].mem, - 3 /* offset 3 bytes from 0x3c0 */, &quirk->mem); + 3 /* offset 3 bytes from 0x3c0 */, quirk->mem); QLIST_INSERT_HEAD(&vdev->vga.region[QEMU_PCI_VGA_IO_HI].quirks, quirk, next); @@ -302,6 +306,7 @@ static void vfio_probe_ati_bar4_window_quirk(VFIOPCIDevice *vdev, int nr) { PCIDevice *pdev = &vdev->pdev; VFIOQuirk *quirk; + VFIOLegacyQuirk *legacy; if (!vdev->has_vga || nr != 4 || pci_get_word(pdev->config + PCI_VENDOR_ID) != PCI_VENDOR_ID_ATI) { @@ -309,20 +314,23 @@ static void vfio_probe_ati_bar4_window_quirk(VFIOPCIDevice *vdev, int nr) } quirk = g_malloc0(sizeof(*quirk)); - quirk->vdev = vdev; - quirk->data.address_size = 4; - quirk->data.data_offset = 4; - quirk->data.data_size = 4; - quirk->data.address_match = 0x4000; - quirk->data.address_mask = PCIE_CONFIG_SPACE_SIZE - 1; - quirk->data.bar = nr; - quirk->data.read_flags = quirk->data.write_flags = 1; - - memory_region_init_io(&quirk->mem, OBJECT(vdev), - &vfio_generic_window_quirk, quirk, + quirk->data = legacy = g_malloc0(sizeof(*legacy)); + quirk->mem = legacy->mem = g_malloc0_n(sizeof(MemoryRegion), 1); + quirk->nr_mem = 1; + legacy->vdev = vdev; + legacy->data.address_size = 4; + legacy->data.data_offset = 4; + legacy->data.data_size = 4; + legacy->data.address_match = 0x4000; + legacy->data.address_mask = PCIE_CONFIG_SPACE_SIZE - 1; + legacy->data.bar = nr; + legacy->data.read_flags = legacy->data.write_flags = 1; + + memory_region_init_io(quirk->mem, OBJECT(vdev), + &vfio_generic_window_quirk, legacy, "vfio-ati-bar4-window-quirk", 8); memory_region_add_subregion_overlap(&vdev->bars[nr].region.mem, - quirk->data.base_offset, &quirk->mem, 1); + legacy->data.base_offset, quirk->mem, 1); QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next); @@ -336,6 +344,7 @@ static void vfio_probe_ati_bar2_4000_quirk(VFIOPCIDevice *vdev, int nr) { PCIDevice *pdev = &vdev->pdev; VFIOQuirk *quirk; + VFIOLegacyQuirk *legacy; /* Only enable on newer devices where BAR2 is 64bit */ if (!vdev->has_vga || nr != 2 || !vdev->bars[2].mem64 || @@ -344,18 +353,21 @@ static void vfio_probe_ati_bar2_4000_quirk(VFIOPCIDevice *vdev, int nr) } quirk = g_malloc0(sizeof(*quirk)); - quirk->vdev = vdev; - quirk->data.flags = quirk->data.read_flags = quirk->data.write_flags = 1; - quirk->data.address_match = 0x4000; - quirk->data.address_mask = PCIE_CONFIG_SPACE_SIZE - 1; - quirk->data.bar = nr; - - memory_region_init_io(&quirk->mem, OBJECT(vdev), &vfio_generic_quirk, quirk, + quirk->data = legacy = g_malloc0(sizeof(*legacy)); + quirk->mem = legacy->mem = g_malloc0_n(sizeof(MemoryRegion), 1); + quirk->nr_mem = 1; + legacy->vdev = vdev; + legacy->data.flags = legacy->data.read_flags = legacy->data.write_flags = 1; + legacy->data.address_match = 0x4000; + legacy->data.address_mask = PCIE_CONFIG_SPACE_SIZE - 1; + legacy->data.bar = nr; + + memory_region_init_io(quirk->mem, OBJECT(vdev), &vfio_generic_quirk, legacy, "vfio-ati-bar2-4000-quirk", - TARGET_PAGE_ALIGN(quirk->data.address_mask + 1)); + TARGET_PAGE_ALIGN(legacy->data.address_mask + 1)); memory_region_add_subregion_overlap(&vdev->bars[nr].region.mem, - quirk->data.address_match & TARGET_PAGE_MASK, - &quirk->mem, 1); + legacy->data.address_match & TARGET_PAGE_MASK, + quirk->mem, 1); QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next); @@ -397,7 +409,7 @@ enum { static uint64_t vfio_nvidia_3d0_quirk_read(void *opaque, hwaddr addr, unsigned size) { - VFIOQuirk *quirk = opaque; + VFIOLegacyQuirk *quirk = opaque; VFIOPCIDevice *vdev = quirk->vdev; PCIDevice *pdev = &vdev->pdev; uint64_t data = vfio_vga_read(&vdev->vga.region[QEMU_PCI_VGA_IO_HI], @@ -416,7 +428,7 @@ static uint64_t vfio_nvidia_3d0_quirk_read(void *opaque, static void vfio_nvidia_3d0_quirk_write(void *opaque, hwaddr addr, uint64_t data, unsigned size) { - VFIOQuirk *quirk = opaque; + VFIOLegacyQuirk *quirk = opaque; VFIOPCIDevice *vdev = quirk->vdev; PCIDevice *pdev = &vdev->pdev; @@ -468,6 +480,7 @@ static void vfio_vga_probe_nvidia_3d0_quirk(VFIOPCIDevice *vdev) { PCIDevice *pdev = &vdev->pdev; VFIOQuirk *quirk; + VFIOLegacyQuirk *legacy; if (pci_get_word(pdev->config + PCI_VENDOR_ID) != PCI_VENDOR_ID_NVIDIA || !vdev->bars[1].region.size) { @@ -475,19 +488,22 @@ static void vfio_vga_probe_nvidia_3d0_quirk(VFIOPCIDevice *vdev) } quirk = g_malloc0(sizeof(*quirk)); - quirk->vdev = vdev; - quirk->data.base_offset = 0x10; - quirk->data.address_offset = 4; - quirk->data.address_size = 2; - quirk->data.address_match = 0x1800; - quirk->data.address_mask = PCI_CONFIG_SPACE_SIZE - 1; - quirk->data.data_offset = 0; - quirk->data.data_size = 4; - - memory_region_init_io(&quirk->mem, OBJECT(vdev), &vfio_nvidia_3d0_quirk, - quirk, "vfio-nvidia-3d0-quirk", 6); + quirk->data = legacy = g_malloc0(sizeof(*legacy)); + quirk->mem = legacy->mem = g_malloc0_n(sizeof(MemoryRegion), 1); + quirk->nr_mem = 1; + legacy->vdev = vdev; + legacy->data.base_offset = 0x10; + legacy->data.address_offset = 4; + legacy->data.address_size = 2; + legacy->data.address_match = 0x1800; + legacy->data.address_mask = PCI_CONFIG_SPACE_SIZE - 1; + legacy->data.data_offset = 0; + legacy->data.data_size = 4; + + memory_region_init_io(quirk->mem, OBJECT(vdev), &vfio_nvidia_3d0_quirk, + legacy, "vfio-nvidia-3d0-quirk", 6); memory_region_add_subregion(&vdev->vga.region[QEMU_PCI_VGA_IO_HI].mem, - quirk->data.base_offset, &quirk->mem); + legacy->data.base_offset, quirk->mem); QLIST_INSERT_HEAD(&vdev->vga.region[QEMU_PCI_VGA_IO_HI].quirks, quirk, next); @@ -512,7 +528,7 @@ enum { static void vfio_nvidia_bar5_window_quirk_write(void *opaque, hwaddr addr, uint64_t data, unsigned size) { - VFIOQuirk *quirk = opaque; + VFIOLegacyQuirk *quirk = opaque; switch (addr) { case 0x0: @@ -558,6 +574,7 @@ static void vfio_probe_nvidia_bar5_window_quirk(VFIOPCIDevice *vdev, int nr) { PCIDevice *pdev = &vdev->pdev; VFIOQuirk *quirk; + VFIOLegacyQuirk *legacy; if (!vdev->has_vga || nr != 5 || pci_get_word(pdev->config + PCI_VENDOR_ID) != PCI_VENDOR_ID_NVIDIA) { @@ -565,19 +582,22 @@ static void vfio_probe_nvidia_bar5_window_quirk(VFIOPCIDevice *vdev, int nr) } quirk = g_malloc0(sizeof(*quirk)); - quirk->vdev = vdev; - quirk->data.read_flags = quirk->data.write_flags = NV_BAR5_VALID; - quirk->data.address_offset = 0x8; - quirk->data.address_size = 0; /* actually 4, but avoids generic code */ - quirk->data.data_offset = 0xc; - quirk->data.data_size = 4; - quirk->data.bar = nr; - - memory_region_init_io(&quirk->mem, OBJECT(vdev), - &vfio_nvidia_bar5_window_quirk, quirk, + quirk->data = legacy = g_malloc0(sizeof(*legacy)); + quirk->mem = legacy->mem = g_malloc0_n(sizeof(MemoryRegion), 1); + quirk->nr_mem = 1; + legacy->vdev = vdev; + legacy->data.read_flags = legacy->data.write_flags = NV_BAR5_VALID; + legacy->data.address_offset = 0x8; + legacy->data.address_size = 0; /* actually 4, but avoids generic code */ + legacy->data.data_offset = 0xc; + legacy->data.data_size = 4; + legacy->data.bar = nr; + + memory_region_init_io(quirk->mem, OBJECT(vdev), + &vfio_nvidia_bar5_window_quirk, legacy, "vfio-nvidia-bar5-window-quirk", 16); memory_region_add_subregion_overlap(&vdev->bars[nr].region.mem, - 0, &quirk->mem, 1); + 0, quirk->mem, 1); QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next); @@ -587,7 +607,7 @@ static void vfio_probe_nvidia_bar5_window_quirk(VFIOPCIDevice *vdev, int nr) static void vfio_nvidia_88000_quirk_write(void *opaque, hwaddr addr, uint64_t data, unsigned size) { - VFIOQuirk *quirk = opaque; + VFIOLegacyQuirk *quirk = opaque; VFIOPCIDevice *vdev = quirk->vdev; PCIDevice *pdev = &vdev->pdev; hwaddr base = quirk->data.address_match & TARGET_PAGE_MASK; @@ -626,6 +646,7 @@ static void vfio_probe_nvidia_bar0_88000_quirk(VFIOPCIDevice *vdev, int nr) { PCIDevice *pdev = &vdev->pdev; VFIOQuirk *quirk; + VFIOLegacyQuirk *legacy; uint16_t vendor, class; vendor = pci_get_word(pdev->config + PCI_VENDOR_ID); @@ -637,18 +658,21 @@ static void vfio_probe_nvidia_bar0_88000_quirk(VFIOPCIDevice *vdev, int nr) } quirk = g_malloc0(sizeof(*quirk)); - quirk->vdev = vdev; - quirk->data.flags = quirk->data.read_flags = quirk->data.write_flags = 1; - quirk->data.address_match = 0x88000; - quirk->data.address_mask = PCIE_CONFIG_SPACE_SIZE - 1; - quirk->data.bar = nr; - - memory_region_init_io(&quirk->mem, OBJECT(vdev), &vfio_nvidia_88000_quirk, - quirk, "vfio-nvidia-bar0-88000-quirk", - TARGET_PAGE_ALIGN(quirk->data.address_mask + 1)); + quirk->data = legacy = g_malloc0(sizeof(*legacy)); + quirk->mem = legacy->mem = g_malloc0_n(sizeof(MemoryRegion), 1); + quirk->nr_mem = 1; + legacy->vdev = vdev; + legacy->data.flags = legacy->data.read_flags = legacy->data.write_flags = 1; + legacy->data.address_match = 0x88000; + legacy->data.address_mask = PCIE_CONFIG_SPACE_SIZE - 1; + legacy->data.bar = nr; + + memory_region_init_io(quirk->mem, OBJECT(vdev), &vfio_nvidia_88000_quirk, + legacy, "vfio-nvidia-bar0-88000-quirk", + TARGET_PAGE_ALIGN(legacy->data.address_mask + 1)); memory_region_add_subregion_overlap(&vdev->bars[nr].region.mem, - quirk->data.address_match & TARGET_PAGE_MASK, - &quirk->mem, 1); + legacy->data.address_match & TARGET_PAGE_MASK, + quirk->mem, 1); QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next); @@ -662,6 +686,7 @@ static void vfio_probe_nvidia_bar0_1800_quirk(VFIOPCIDevice *vdev, int nr) { PCIDevice *pdev = &vdev->pdev; VFIOQuirk *quirk; + VFIOLegacyQuirk *legacy; if (!vdev->has_vga || nr != 0 || pci_get_word(pdev->config + PCI_VENDOR_ID) != PCI_VENDOR_ID_NVIDIA) { @@ -674,18 +699,21 @@ static void vfio_probe_nvidia_bar0_1800_quirk(VFIOPCIDevice *vdev, int nr) & 0xff); quirk = g_malloc0(sizeof(*quirk)); - quirk->vdev = vdev; - quirk->data.flags = quirk->data.read_flags = quirk->data.write_flags = 1; - quirk->data.address_match = 0x1800; - quirk->data.address_mask = PCI_CONFIG_SPACE_SIZE - 1; - quirk->data.bar = nr; - - memory_region_init_io(&quirk->mem, OBJECT(vdev), &vfio_generic_quirk, quirk, + quirk->data = legacy = g_malloc0(sizeof(*legacy)); + quirk->mem = legacy->mem = g_malloc0_n(sizeof(MemoryRegion), 1); + quirk->nr_mem = 1; + legacy->vdev = vdev; + legacy->data.flags = legacy->data.read_flags = legacy->data.write_flags = 1; + legacy->data.address_match = 0x1800; + legacy->data.address_mask = PCI_CONFIG_SPACE_SIZE - 1; + legacy->data.bar = nr; + + memory_region_init_io(quirk->mem, OBJECT(vdev), &vfio_generic_quirk, legacy, "vfio-nvidia-bar0-1800-quirk", - TARGET_PAGE_ALIGN(quirk->data.address_mask + 1)); + TARGET_PAGE_ALIGN(legacy->data.address_mask + 1)); memory_region_add_subregion_overlap(&vdev->bars[nr].region.mem, - quirk->data.address_match & TARGET_PAGE_MASK, - &quirk->mem, 1); + legacy->data.address_match & TARGET_PAGE_MASK, + quirk->mem, 1); QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next); @@ -725,7 +753,7 @@ static void vfio_probe_nvidia_bar0_1800_quirk(VFIOPCIDevice *vdev, int nr) static uint64_t vfio_rtl8168_window_quirk_read(void *opaque, hwaddr addr, unsigned size) { - VFIOQuirk *quirk = opaque; + VFIOLegacyQuirk *quirk = opaque; VFIOPCIDevice *vdev = quirk->vdev; uint64_t val = 0; @@ -755,7 +783,7 @@ static uint64_t vfio_rtl8168_window_quirk_read(void *opaque, static void vfio_rtl8168_window_quirk_write(void *opaque, hwaddr addr, uint64_t data, unsigned size) { - VFIOQuirk *quirk = opaque; + VFIOLegacyQuirk *quirk = opaque; VFIOPCIDevice *vdev = quirk->vdev; switch (addr) { @@ -809,6 +837,7 @@ static void vfio_probe_rtl8168_bar2_window_quirk(VFIOPCIDevice *vdev, int nr) { PCIDevice *pdev = &vdev->pdev; VFIOQuirk *quirk; + VFIOLegacyQuirk *legacy; if (pci_get_word(pdev->config + PCI_VENDOR_ID) != PCI_VENDOR_ID_REALTEK || pci_get_word(pdev->config + PCI_DEVICE_ID) != 0x8168 || nr != 2) { @@ -816,13 +845,16 @@ static void vfio_probe_rtl8168_bar2_window_quirk(VFIOPCIDevice *vdev, int nr) } quirk = g_malloc0(sizeof(*quirk)); - quirk->vdev = vdev; - quirk->data.bar = nr; - - memory_region_init_io(&quirk->mem, OBJECT(vdev), &vfio_rtl8168_window_quirk, - quirk, "vfio-rtl8168-window-quirk", 8); + quirk->data = legacy = g_malloc0(sizeof(*legacy)); + quirk->mem = legacy->mem = g_malloc0_n(sizeof(MemoryRegion), 1); + quirk->nr_mem = 1; + legacy->vdev = vdev; + legacy->data.bar = nr; + + memory_region_init_io(quirk->mem, OBJECT(vdev), &vfio_rtl8168_window_quirk, + legacy, "vfio-rtl8168-window-quirk", 8); memory_region_add_subregion_overlap(&vdev->bars[nr].region.mem, - 0x70, &quirk->mem, 1); + 0x70, quirk->mem, 1); QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next); @@ -841,24 +873,31 @@ void vfio_vga_quirk_setup(VFIOPCIDevice *vdev) void vfio_vga_quirk_teardown(VFIOPCIDevice *vdev) { VFIOQuirk *quirk; - int i; + int i, j; for (i = 0; i < ARRAY_SIZE(vdev->vga.region); i++) { QLIST_FOREACH(quirk, &vdev->vga.region[i].quirks, next) { - memory_region_del_subregion(&vdev->vga.region[i].mem, &quirk->mem); + for (j = 0; j < quirk->nr_mem; j++) { + memory_region_del_subregion(&vdev->vga.region[i].mem, + &quirk->mem[j]); + } } } } void vfio_vga_quirk_free(VFIOPCIDevice *vdev) { - int i; + int i, j; for (i = 0; i < ARRAY_SIZE(vdev->vga.region); i++) { while (!QLIST_EMPTY(&vdev->vga.region[i].quirks)) { VFIOQuirk *quirk = QLIST_FIRST(&vdev->vga.region[i].quirks); - object_unparent(OBJECT(&quirk->mem)); QLIST_REMOVE(quirk, next); + for (j = 0; j < quirk->nr_mem; j++) { + object_unparent(OBJECT(&quirk->mem[j])); + } + g_free(quirk->mem); + g_free(quirk->data); g_free(quirk); } } @@ -878,20 +917,28 @@ void vfio_bar_quirk_teardown(VFIOPCIDevice *vdev, int nr) { VFIOBAR *bar = &vdev->bars[nr]; VFIOQuirk *quirk; + int i; QLIST_FOREACH(quirk, &bar->quirks, next) { - memory_region_del_subregion(&bar->region.mem, &quirk->mem); + for (i = 0; i < quirk->nr_mem; i++) { + memory_region_del_subregion(&bar->region.mem, &quirk->mem[i]); + } } } void vfio_bar_quirk_free(VFIOPCIDevice *vdev, int nr) { VFIOBAR *bar = &vdev->bars[nr]; + int i; while (!QLIST_EMPTY(&bar->quirks)) { VFIOQuirk *quirk = QLIST_FIRST(&bar->quirks); - object_unparent(OBJECT(&quirk->mem)); QLIST_REMOVE(quirk, next); + for (i = 0; i < quirk->nr_mem; i++) { + object_unparent(OBJECT(&quirk->mem[i])); + } + g_free(quirk->mem); + g_free(quirk->data); g_free(quirk); } } diff --git a/hw/vfio/pci.h b/hw/vfio/pci.h index f6dbe7f..8696976 100644 --- a/hw/vfio/pci.h +++ b/hw/vfio/pci.h @@ -22,10 +22,9 @@ struct VFIOPCIDevice; -typedef struct VFIOQuirk { - MemoryRegion mem; +typedef struct VFIOLegacyQuirk { struct VFIOPCIDevice *vdev; - QLIST_ENTRY(VFIOQuirk) next; + MemoryRegion *mem; struct { uint32_t base_offset:TARGET_PAGE_BITS; uint32_t address_offset:TARGET_PAGE_BITS; @@ -43,6 +42,13 @@ typedef struct VFIOQuirk { uint8_t read_flags; uint8_t write_flags; } data; +} VFIOLegacyQuirk; + +typedef struct VFIOQuirk { + QLIST_ENTRY(VFIOQuirk) next; + void *data; + int nr_mem; + MemoryRegion *mem; } VFIOQuirk; typedef struct VFIOBAR {