From 875553e317b28e66824fec73ad4459372576ec68 Mon Sep 17 00:00:00 2001 From: Oleksandr Tyshchenko Date: Sat, 8 Oct 2022 18:10:12 +0300 Subject: xen/virtio: Handle cases when page offset > PAGE_SIZE properly Passed to xen_grant_dma_map_page() offset in the page can be > PAGE_SIZE even if the guest uses the same page granularity as Xen (4KB). Before current patch, if such case happened we ended up providing grants for the whole region in xen_grant_dma_map_page() which was really unnecessary. The more, we ended up not releasing all grants which represented that region in xen_grant_dma_unmap_page(). Current patch updates the code to be able to deal with such cases. Signed-off-by: Oleksandr Tyshchenko Reviewed-by: Stefano Stabellini Reviewed-by: Xenia Ragiadakou Link: https://lore.kernel.org/r/20221008151013.2537826-2-olekstysh@gmail.com Signed-off-by: Juergen Gross --- drivers/xen/grant-dma-ops.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers/xen') diff --git a/drivers/xen/grant-dma-ops.c b/drivers/xen/grant-dma-ops.c index 860f37c93af4..3089940436be 100644 --- a/drivers/xen/grant-dma-ops.c +++ b/drivers/xen/grant-dma-ops.c @@ -168,7 +168,9 @@ static dma_addr_t xen_grant_dma_map_page(struct device *dev, struct page *page, unsigned long attrs) { struct xen_grant_dma_data *data; - unsigned int i, n_pages = PFN_UP(offset + size); + unsigned long dma_offset = offset_in_page(offset), + pfn_offset = PFN_DOWN(offset); + unsigned int i, n_pages = PFN_UP(dma_offset + size); grant_ref_t grant; dma_addr_t dma_handle; @@ -187,10 +189,11 @@ static dma_addr_t xen_grant_dma_map_page(struct device *dev, struct page *page, for (i = 0; i < n_pages; i++) { gnttab_grant_foreign_access_ref(grant + i, data->backend_domid, - xen_page_to_gfn(page) + i, dir == DMA_TO_DEVICE); + pfn_to_gfn(page_to_xen_pfn(page) + i + pfn_offset), + dir == DMA_TO_DEVICE); } - dma_handle = grant_to_dma(grant) + offset; + dma_handle = grant_to_dma(grant) + dma_offset; return dma_handle; } -- cgit v1.2.3 From a383dcb1cca8305497877119fba0a320f41fe853 Mon Sep 17 00:00:00 2001 From: Oleksandr Tyshchenko Date: Sat, 8 Oct 2022 18:10:13 +0300 Subject: xen/virtio: Convert PAGE_SIZE/PAGE_SHIFT/PFN_UP to Xen counterparts Currently, a grant ref is always based on the Xen page granularity (4KB), and guest commonly uses the same page granularity. But the guest may use a different page granularity (i.e 64KB). So adopt the code to be able to deal with it. Signed-off-by: Oleksandr Tyshchenko Acked-by: Stefano Stabellini Reviewed-by: Xenia Ragiadakou Link: https://lore.kernel.org/r/20221008151013.2537826-3-olekstysh@gmail.com Signed-off-by: Juergen Gross --- drivers/xen/grant-dma-ops.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers/xen') diff --git a/drivers/xen/grant-dma-ops.c b/drivers/xen/grant-dma-ops.c index 3089940436be..daa525df7bdc 100644 --- a/drivers/xen/grant-dma-ops.c +++ b/drivers/xen/grant-dma-ops.c @@ -31,12 +31,12 @@ static DEFINE_XARRAY_FLAGS(xen_grant_dma_devices, XA_FLAGS_LOCK_IRQ); static inline dma_addr_t grant_to_dma(grant_ref_t grant) { - return XEN_GRANT_DMA_ADDR_OFF | ((dma_addr_t)grant << PAGE_SHIFT); + return XEN_GRANT_DMA_ADDR_OFF | ((dma_addr_t)grant << XEN_PAGE_SHIFT); } static inline grant_ref_t dma_to_grant(dma_addr_t dma) { - return (grant_ref_t)((dma & ~XEN_GRANT_DMA_ADDR_OFF) >> PAGE_SHIFT); + return (grant_ref_t)((dma & ~XEN_GRANT_DMA_ADDR_OFF) >> XEN_PAGE_SHIFT); } static struct xen_grant_dma_data *find_xen_grant_dma_data(struct device *dev) @@ -79,7 +79,7 @@ static void *xen_grant_dma_alloc(struct device *dev, size_t size, unsigned long attrs) { struct xen_grant_dma_data *data; - unsigned int i, n_pages = PFN_UP(size); + unsigned int i, n_pages = XEN_PFN_UP(size); unsigned long pfn; grant_ref_t grant; void *ret; @@ -91,14 +91,14 @@ static void *xen_grant_dma_alloc(struct device *dev, size_t size, if (unlikely(data->broken)) return NULL; - ret = alloc_pages_exact(n_pages * PAGE_SIZE, gfp); + ret = alloc_pages_exact(n_pages * XEN_PAGE_SIZE, gfp); if (!ret) return NULL; pfn = virt_to_pfn(ret); if (gnttab_alloc_grant_reference_seq(n_pages, &grant)) { - free_pages_exact(ret, n_pages * PAGE_SIZE); + free_pages_exact(ret, n_pages * XEN_PAGE_SIZE); return NULL; } @@ -116,7 +116,7 @@ static void xen_grant_dma_free(struct device *dev, size_t size, void *vaddr, dma_addr_t dma_handle, unsigned long attrs) { struct xen_grant_dma_data *data; - unsigned int i, n_pages = PFN_UP(size); + unsigned int i, n_pages = XEN_PFN_UP(size); grant_ref_t grant; data = find_xen_grant_dma_data(dev); @@ -138,7 +138,7 @@ static void xen_grant_dma_free(struct device *dev, size_t size, void *vaddr, gnttab_free_grant_reference_seq(grant, n_pages); - free_pages_exact(vaddr, n_pages * PAGE_SIZE); + free_pages_exact(vaddr, n_pages * XEN_PAGE_SIZE); } static struct page *xen_grant_dma_alloc_pages(struct device *dev, size_t size, @@ -168,9 +168,9 @@ static dma_addr_t xen_grant_dma_map_page(struct device *dev, struct page *page, unsigned long attrs) { struct xen_grant_dma_data *data; - unsigned long dma_offset = offset_in_page(offset), - pfn_offset = PFN_DOWN(offset); - unsigned int i, n_pages = PFN_UP(dma_offset + size); + unsigned long dma_offset = xen_offset_in_page(offset), + pfn_offset = XEN_PFN_DOWN(offset); + unsigned int i, n_pages = XEN_PFN_UP(dma_offset + size); grant_ref_t grant; dma_addr_t dma_handle; @@ -203,8 +203,8 @@ static void xen_grant_dma_unmap_page(struct device *dev, dma_addr_t dma_handle, unsigned long attrs) { struct xen_grant_dma_data *data; - unsigned long offset = dma_handle & (PAGE_SIZE - 1); - unsigned int i, n_pages = PFN_UP(offset + size); + unsigned long dma_offset = xen_offset_in_page(dma_handle); + unsigned int i, n_pages = XEN_PFN_UP(dma_offset + size); grant_ref_t grant; if (WARN_ON(dir == DMA_NONE)) -- cgit v1.2.3 From da36a2a76b01b210ffaa55cdc2c99bc8783697c5 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Thu, 10 Nov 2022 23:24:41 +0800 Subject: xen/pcpu: fix possible memory leak in register_pcpu() In device_add(), dev_set_name() is called to allocate name, if it returns error, the name need be freed. As comment of device_register() says, it should use put_device() to give up the reference in the error path. So fix this by calling put_device(), then the name can be freed in kobject_cleanup(). Fixes: f65c9bb3fb72 ("xen/pcpu: Xen physical cpus online/offline sys interface") Signed-off-by: Yang Yingliang Reviewed-by: Juergen Gross Link: https://lore.kernel.org/r/20221110152441.401630-1-yangyingliang@huawei.com Signed-off-by: Juergen Gross --- drivers/xen/pcpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/xen') diff --git a/drivers/xen/pcpu.c b/drivers/xen/pcpu.c index 47aa3a1ccaf5..fd3a644b0855 100644 --- a/drivers/xen/pcpu.c +++ b/drivers/xen/pcpu.c @@ -228,7 +228,7 @@ static int register_pcpu(struct pcpu *pcpu) err = device_register(dev); if (err) { - pcpu_release(dev); + put_device(dev); return err; } -- cgit v1.2.3 From 5e29500eba2aa19e1323df46f64dafcd4a327092 Mon Sep 17 00:00:00 2001 From: Marek Marczykowski-Górecki Date: Mon, 14 Nov 2022 11:31:08 +0100 Subject: xen-pciback: Allow setting PCI_MSIX_FLAGS_MASKALL too MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When Xen domain configures MSI-X, the usual approach is to enable MSI-X together with masking all of them via the config space, then fill the table and only then clear PCI_MSIX_FLAGS_MASKALL. Allow doing this via QEMU running in a stub domain. Previously, when changing PCI_MSIX_FLAGS_MASKALL was not allowed, the whole write was aborted, preventing change to the PCI_MSIX_FLAGS_ENABLE bit too. Note the Xen hypervisor intercepts this write anyway, and may keep the PCI_MSIX_FLAGS_MASKALL bit set if it wishes to. It will store the guest-requested state and will apply it eventually. Signed-off-by: Marek Marczykowski-Górecki Reviewed-by: Jan Beulich Link: https://lore.kernel.org/r/20221114103110.1519413-1-marmarek@invisiblethingslab.com Signed-off-by: Juergen Gross --- drivers/xen/xen-pciback/conf_space_capability.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers/xen') diff --git a/drivers/xen/xen-pciback/conf_space_capability.c b/drivers/xen/xen-pciback/conf_space_capability.c index 5e53b4817f16..097316a74126 100644 --- a/drivers/xen/xen-pciback/conf_space_capability.c +++ b/drivers/xen/xen-pciback/conf_space_capability.c @@ -190,13 +190,16 @@ static const struct config_field caplist_pm[] = { }; static struct msi_msix_field_config { - u16 enable_bit; /* bit for enabling MSI/MSI-X */ - unsigned int int_type; /* interrupt type for exclusiveness check */ + u16 enable_bit; /* bit for enabling MSI/MSI-X */ + u16 allowed_bits; /* bits allowed to be changed */ + unsigned int int_type; /* interrupt type for exclusiveness check */ } msi_field_config = { .enable_bit = PCI_MSI_FLAGS_ENABLE, + .allowed_bits = PCI_MSI_FLAGS_ENABLE, .int_type = INTERRUPT_TYPE_MSI, }, msix_field_config = { .enable_bit = PCI_MSIX_FLAGS_ENABLE, + .allowed_bits = PCI_MSIX_FLAGS_ENABLE | PCI_MSIX_FLAGS_MASKALL, .int_type = INTERRUPT_TYPE_MSIX, }; @@ -229,7 +232,7 @@ static int msi_msix_flags_write(struct pci_dev *dev, int offset, u16 new_value, return 0; if (!dev_data->allow_interrupt_control || - (new_value ^ old_value) & ~field_config->enable_bit) + (new_value ^ old_value) & ~field_config->allowed_bits) return PCIBIOS_SET_FAILED; if (new_value & field_config->enable_bit) { -- cgit v1.2.3 From c53717e1e3f0d0f9129b2e0dbc6dcc5e0a8132e9 Mon Sep 17 00:00:00 2001 From: ruanjinjie Date: Mon, 14 Nov 2022 19:21:24 +0800 Subject: xen/platform-pci: add missing free_irq() in error path free_irq() is missing in case of error in platform_pci_probe(), fix that. Signed-off-by: ruanjinjie Reviewed-by: Oleksandr Tyshchenko Link: https://lore.kernel.org/r/20221114112124.1965611-1-ruanjinjie@huawei.com Signed-off-by: Juergen Gross --- drivers/xen/platform-pci.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers/xen') diff --git a/drivers/xen/platform-pci.c b/drivers/xen/platform-pci.c index 18f0ed8b1f93..6ebd819338ec 100644 --- a/drivers/xen/platform-pci.c +++ b/drivers/xen/platform-pci.c @@ -144,7 +144,7 @@ static int platform_pci_probe(struct pci_dev *pdev, if (ret) { dev_warn(&pdev->dev, "Unable to set the evtchn callback " "err=%d\n", ret); - goto out; + goto irq_out; } } @@ -152,13 +152,16 @@ static int platform_pci_probe(struct pci_dev *pdev, grant_frames = alloc_xen_mmio(PAGE_SIZE * max_nr_gframes); ret = gnttab_setup_auto_xlat_frames(grant_frames); if (ret) - goto out; + goto irq_out; ret = gnttab_init(); if (ret) goto grant_out; return 0; grant_out: gnttab_free_auto_xlat_frames(); +irq_out: + if (!xen_have_vector_callback) + free_irq(pdev->irq, pdev); out: pci_release_region(pdev, 0); mem_out: -- cgit v1.2.3 From 4abb77fc5531381484477cac95913336c97176b7 Mon Sep 17 00:00:00 2001 From: Juergen Gross Date: Mon, 14 Nov 2022 14:29:37 +0100 Subject: xen/platform-pci: use define instead of literal number Instead of "0x01" use the HVM_PARAM_CALLBACK_TYPE_PCI_INTX define from the interface header in get_callback_via(). Signed-off-by: Juergen Gross Acked-by: Stefano Stabellini Signed-off-by: Juergen Gross --- drivers/xen/platform-pci.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/xen') diff --git a/drivers/xen/platform-pci.c b/drivers/xen/platform-pci.c index 6ebd819338ec..cd07e3fed0fa 100644 --- a/drivers/xen/platform-pci.c +++ b/drivers/xen/platform-pci.c @@ -54,7 +54,8 @@ static uint64_t get_callback_via(struct pci_dev *pdev) pin = pdev->pin; /* We don't know the GSI. Specify the PCI INTx line instead. */ - return ((uint64_t)0x01 << HVM_CALLBACK_VIA_TYPE_SHIFT) | /* PCI INTx identifier */ + return ((uint64_t)HVM_PARAM_CALLBACK_TYPE_PCI_INTX << + HVM_CALLBACK_VIA_TYPE_SHIFT) | ((uint64_t)pci_domain_nr(pdev->bus) << 32) | ((uint64_t)pdev->bus->number << 16) | ((uint64_t)(pdev->devfn & 0xff) << 8) | -- cgit v1.2.3