linux3.10.65 DMA缓冲区分配失败

时间:2021-04-19 03:56:07

       今天调试tp固件升级的时候,DMA缓冲区按照以前android4.2(内核版本不记得了),DMA缓冲区的申请方式,发现老是申请失败。原来的申请方式如下:

static u8 *I2CDMABuf_va = NULL;
dma_addr_t I2CDMABuf_pa =NULL;

I2CDMABuf_va = (u8 *)dma_alloc_coherent(NULL, FTS_DMA_BUF_SIZE, (dma_addr_t *)&I2CDMABuf_pa, GFP_KERNEL);
	if(!I2CDMABuf_va)
	{
		dev_dbg(&client->dev,"%s Allocate DMA I2C Buffer failed!\n",__func__);
		snprintf(dma_alloc_buf, 100,
					"Allocate DMA I2C Buffer failed!\n");
		return -EIO;
	}
分析dma_alloc_coherent源码发现如下:

static inline void *dma_alloc_coherent(struct device *dev, size_t size,
				       dma_addr_t *dma_handle, gfp_t flags)
{
	struct dma_map_ops *ops = get_dma_ops(dev);//得到dma映射操作集
	void *vaddr;

	if (dma_alloc_from_coherent(dev, size, dma_handle, &vaddr))
		return vaddr;

	vaddr = ops->alloc(dev, size, dma_handle, flags, NULL);
	debug_dma_alloc_coherent(dev, size, *dma_handle, vaddr);
	return vaddr;
}
get_dma_ops源码如下:

static inline struct dma_map_ops *get_dma_ops(struct device *dev)
{
	if (unlikely(!dev) || !dev->archdata.dma_ops)//dev为NULL,
		return dma_ops;
	else
		return dev->archdata.dma_ops;
}
因为传递进来的参数dev为NULL,所以这里返回dma_ops。再来看dma_alloc_from_coherent这个方法,一致性DMA映射:

int dma_alloc_from_coherent(struct device *dev, ssize_t size,
				       dma_addr_t *dma_handle, void **ret)
{
	struct dma_coherent_mem *mem;
	int order = get_order(size);
	int pageno;

	if (!dev)//dev为NULL
		return 0;

	mem = dev->dma_mem;
	if (!mem)
		return 0;

	*ret = NULL;

	if (unlikely(size > (mem->size << PAGE_SHIFT)))
		goto err;

	pageno = bitmap_find_free_region(mem->bitmap, mem->size, order);
	if (unlikely(pageno < 0))
		goto err;

	/*
	 * Memory was found in the per-device area.
	 */
	*dma_handle = mem->device_base + (pageno << PAGE_SHIFT);
	*ret = mem->virt_base + (pageno << PAGE_SHIFT);
	memset(*ret, 0, size);

	return 1;

err:
	/*
	 * In the case where the allocation can not be satisfied from the
	 * per-device area, try to fall back to generic memory if the
	 * constraints allow it.
	 */
	return mem->flags & DMA_MEMORY_EXCLUSIVE;
}
因为dev为NULL,所以这里返回0。所以直接返回了一个未初始化的vaddr的指针。所以,新的内核版本中dma_alloc_coherent的第一个device参数不能为NULL,否则,DMA缓冲区会分配失败。如下:

I2CDMABuf_va = (u8 *)dma_alloc_coherent(&client->dev, FTS_DMA_BUF_SIZE, (dma_addr_t *)&I2CDMABuf_pa, GFP_KERNEL);
	if(!I2CDMABuf_va)
	{
		dev_dbg(&client->dev,"%s Allocate DMA I2C Buffer failed!\n",__func__);
		snprintf(dma_alloc_buf, 100,
					"Allocate DMA I2C Buffer failed!\n");
		return -EIO;
	}