Re: v5.4.289 failed to boot with error megasas_build_io_fusion 3219 sge_count (-12) is out of range

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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@xxxxxxxx>
> 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@xxxxxxxx>
> ---
> 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
> 

[Index of Archives]     [Linux Kernel]     [Kernel Development Newbies]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite Hiking]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux