[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <alpine.DEB.2.22.394.2501301226330.11632@ubuntu-linux-20-04-desktop>
Date: Thu, 30 Jan 2025 12:28:00 -0800 (PST)
From: Stefano Stabellini <sstabellini@...nel.org>
To: Jürgen Groß <jgross@...e.com>
cc: Harshvardhan Jha <harshvardhan.j.jha@...cle.com>,
Greg KH <gregkh@...uxfoundation.org>, Konrad Wilk <konrad.wilk@...cle.com>,
Boris Ostrovsky <boris.ostrovsky@...cle.com>,
"sstabellini@...nel.org" <sstabellini@...nel.org>,
"xen-devel@...ts.xenproject.org" <xen-devel@...ts.xenproject.org>,
"linux-kernel@...r.kernel.org" <linux-kernel@...r.kernel.org>,
Harshit Mogalapalli <harshit.m.mogalapalli@...cle.com>,
stable@...r.kernel.org
Subject: Re: v5.4.289 failed to boot with error megasas_build_io_fusion 3219
sge_count (-12) is out of range
On Thu, 30 Jan 2025, Jürgen Groß wrote:
> Can you try the attached patch, please? I don't have a system at hand
> showing the problem.
>
> From cff43e997f79a95dc44e02debaeafe5f127f40bb Mon Sep 17 00:00:00 2001
> From: Juergen Gross <jgross@...e.com>
> Date: Thu, 30 Jan 2025 09:56:57 +0100
> Subject: [PATCH] x86/xen: allow larger contiguous memory regions in PV guests
>
> Today a PV guest (including dom0) can create 2MB contiguous memory
> regions for DMA buffers at max. This has led to problems at least
> with the megaraid_sas driver, which wants to allocate a 2.3MB DMA
> buffer.
>
> The limiting factor is the frame array used to do the hypercall for
> making the memory contiguous, which has 512 entries and is just a
> static array in mmu_pv.c.
>
> In case a contiguous memory area larger than the initially supported
> 2MB is requested, allocate a larger buffer for the frame list. Note
> that such an allocation is tried only after memory management has been
> initialized properly, which is tested via the early_boot_irqs_disabled
> flag.
>
> Fixes: 9f40ec84a797 ("xen/swiotlb: add alignment check for dma buffers")
> Signed-off-by: Juergen Gross <jgross@...e.com>
> ---
> Note that the "Fixes:" tag is not really correct, as that patch didn't
> introduce the problem, but rather made it visible. OTOH it is the best
> indicator we have to identify kernel versions this patch should be
> backported to.
> ---
> arch/x86/xen/mmu_pv.c | 44 ++++++++++++++++++++++++++++++++++++-------
> 1 file changed, 37 insertions(+), 7 deletions(-)
>
> diff --git a/arch/x86/xen/mmu_pv.c b/arch/x86/xen/mmu_pv.c
> index 55a4996d0c04..62aec29b8174 100644
> --- a/arch/x86/xen/mmu_pv.c
> +++ b/arch/x86/xen/mmu_pv.c
> @@ -2200,8 +2200,10 @@ void __init xen_init_mmu_ops(void)
> }
>
> /* Protected by xen_reservation_lock. */
> -#define MAX_CONTIG_ORDER 9 /* 2MB */
> -static unsigned long discontig_frames[1<<MAX_CONTIG_ORDER];
> +#define MIN_CONTIG_ORDER 9 /* 2MB */
> +static unsigned int discontig_frames_order = MIN_CONTIG_ORDER;
> +static unsigned long discontig_frames_early[1UL << MIN_CONTIG_ORDER];
> +static unsigned long *discontig_frames = discontig_frames_early;
>
> #define VOID_PTE (mfn_pte(0, __pgprot(0)))
> static void xen_zap_pfn_range(unsigned long vaddr, unsigned int order,
> @@ -2319,18 +2321,44 @@ int xen_create_contiguous_region(phys_addr_t pstart, unsigned int order,
> unsigned int address_bits,
> dma_addr_t *dma_handle)
> {
> - unsigned long *in_frames = discontig_frames, out_frame;
> + unsigned long *in_frames, out_frame;
> + unsigned long *new_array, *old_array;
> unsigned long flags;
> int success;
> unsigned long vstart = (unsigned long)phys_to_virt(pstart);
>
> - if (unlikely(order > MAX_CONTIG_ORDER))
> - return -ENOMEM;
> + if (unlikely(order > discontig_frames_order)) {
> + if (early_boot_irqs_disabled)
> + return -ENOMEM;
> +
> + new_array = vmalloc(sizeof(unsigned long) * (1UL << order));
> +
> + if (!new_array)
> + return -ENOMEM;
> +
> + spin_lock_irqsave(&xen_reservation_lock, flags);
> +
> + if (order > discontig_frames_order) {
This second if check should not be needed because it is the same as the
outer if check.
> + if (discontig_frames == discontig_frames_early)
> + old_array = NULL;
> + else
> + old_array = discontig_frames;
> + discontig_frames = new_array;
> + discontig_frames_order = order;
> + } else
> + old_array = new_array;
> +
> + spin_unlock_irqrestore(&xen_reservation_lock, flags);
> +
> + vfree(old_array);
> + }
>
> memset((void *) vstart, 0, PAGE_SIZE << order);
>
> spin_lock_irqsave(&xen_reservation_lock, flags);
>
> + in_frames = discontig_frames;
> +
> /* 1. Zap current PTEs, remembering MFNs. */
> xen_zap_pfn_range(vstart, order, in_frames, NULL);
>
> @@ -2354,12 +2382,12 @@ int xen_create_contiguous_region(phys_addr_t pstart, unsigned int order,
>
> void xen_destroy_contiguous_region(phys_addr_t pstart, unsigned int order)
> {
> - unsigned long *out_frames = discontig_frames, in_frame;
> + unsigned long *out_frames, in_frame;
> unsigned long flags;
> int success;
> unsigned long vstart;
>
> - if (unlikely(order > MAX_CONTIG_ORDER))
> + if (unlikely(order > discontig_frames_order))
> return;
>
> vstart = (unsigned long)phys_to_virt(pstart);
> @@ -2367,6 +2395,8 @@ void xen_destroy_contiguous_region(phys_addr_t pstart, unsigned int order)
>
> spin_lock_irqsave(&xen_reservation_lock, flags);
>
> + out_frames = discontig_frames;
> +
> /* 1. Find start MFN of contiguous extent. */
> in_frame = virt_to_mfn((void *)vstart);
>
> --
> 2.43.0
>
Powered by blists - more mailing lists