mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	If dma_direct_alloc() alloc memory in size of 64MB, the inner function dma_common_contiguous_remap() will allocate 128KB memory by invoking the function kmalloc_array(). and the kmalloc_array seems to fail to try to allocate 128KB mem. Call trace: [14977.928623] qcrosvm: page allocation failure: order:5, mode:0x40cc0 [14977.928638] dump_backtrace.cfi_jt+0x0/0x8 [14977.928647] dump_stack_lvl+0x80/0xb8 [14977.928652] warn_alloc+0x164/0x200 [14977.928657] __alloc_pages_slowpath+0x9f0/0xb4c [14977.928660] __alloc_pages+0x21c/0x39c [14977.928662] kmalloc_order+0x48/0x108 [14977.928666] kmalloc_order_trace+0x34/0x154 [14977.928668] __kmalloc+0x548/0x7e4 [14977.928673] dma_direct_alloc+0x11c/0x4f8 [14977.928678] dma_alloc_attrs+0xf4/0x138 [14977.928680] gh_vm_ioctl_set_fw_name+0x3c4/0x610 [gunyah] [14977.928698] gh_vm_ioctl+0x90/0x14c [gunyah] [14977.928705] __arm64_sys_ioctl+0x184/0x210 work around by doing kvmalloc_array instead. Signed-off-by: Gao Xu <gaoxu2@hihonor.com> Reviewed-by: Suren Baghdasaryan <surenb@google.com> Signed-off-by: Christoph Hellwig <hch@lst.de>
		
			
				
	
	
		
			70 lines
		
	
	
	
		
			1.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			70 lines
		
	
	
	
		
			1.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
// SPDX-License-Identifier: GPL-2.0
 | 
						|
/*
 | 
						|
 * Copyright (c) 2014 The Linux Foundation
 | 
						|
 */
 | 
						|
#include <linux/dma-map-ops.h>
 | 
						|
#include <linux/slab.h>
 | 
						|
#include <linux/vmalloc.h>
 | 
						|
 | 
						|
struct page **dma_common_find_pages(void *cpu_addr)
 | 
						|
{
 | 
						|
	struct vm_struct *area = find_vm_area(cpu_addr);
 | 
						|
 | 
						|
	if (!area || area->flags != VM_DMA_COHERENT)
 | 
						|
		return NULL;
 | 
						|
	return area->pages;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Remaps an array of PAGE_SIZE pages into another vm_area.
 | 
						|
 * Cannot be used in non-sleeping contexts
 | 
						|
 */
 | 
						|
void *dma_common_pages_remap(struct page **pages, size_t size,
 | 
						|
			 pgprot_t prot, const void *caller)
 | 
						|
{
 | 
						|
	void *vaddr;
 | 
						|
 | 
						|
	vaddr = vmap(pages, PAGE_ALIGN(size) >> PAGE_SHIFT,
 | 
						|
		     VM_DMA_COHERENT, prot);
 | 
						|
	if (vaddr)
 | 
						|
		find_vm_area(vaddr)->pages = pages;
 | 
						|
	return vaddr;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Remaps an allocated contiguous region into another vm_area.
 | 
						|
 * Cannot be used in non-sleeping contexts
 | 
						|
 */
 | 
						|
void *dma_common_contiguous_remap(struct page *page, size_t size,
 | 
						|
			pgprot_t prot, const void *caller)
 | 
						|
{
 | 
						|
	int count = PAGE_ALIGN(size) >> PAGE_SHIFT;
 | 
						|
	struct page **pages;
 | 
						|
	void *vaddr;
 | 
						|
	int i;
 | 
						|
 | 
						|
	pages = kvmalloc_array(count, sizeof(struct page *), GFP_KERNEL);
 | 
						|
	if (!pages)
 | 
						|
		return NULL;
 | 
						|
	for (i = 0; i < count; i++)
 | 
						|
		pages[i] = nth_page(page, i);
 | 
						|
	vaddr = vmap(pages, count, VM_DMA_COHERENT, prot);
 | 
						|
	kvfree(pages);
 | 
						|
 | 
						|
	return vaddr;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Unmaps a range previously mapped by dma_common_*_remap
 | 
						|
 */
 | 
						|
void dma_common_free_remap(void *cpu_addr, size_t size)
 | 
						|
{
 | 
						|
	struct vm_struct *area = find_vm_area(cpu_addr);
 | 
						|
 | 
						|
	if (!area || area->flags != VM_DMA_COHERENT) {
 | 
						|
		WARN(1, "trying to free invalid coherent area: %p\n", cpu_addr);
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	vunmap(cpu_addr);
 | 
						|
}
 |