繁体   English   中英

Linux 内核驱动程序 - 物理 CPU 内存未更新。 DMA问题

[英]Linux Kernel Driver - physical CPU memory not updated. DMA problem

我正在使用带有 Allwinner H6 ARM CPU 的 Orange Pi3 LTS。 我现在正在为 Rx 和 Tx 编写带有 DMA 的 UART 驱动程序。 我使用 kmalloc() 调用分配了物理 RAM 内存,并获得了分配内存的物理和逻辑地址。 所以,我知道处理器中的物理地址和 Linux 内核驱动程序空间中相应的逻辑地址。 我在更新逻辑后更新物理内存时遇到问题。 我的意思是,例如在我的 linux 内核驱动程序中,当我将我的驱动程序附加到内核时,我有回调 init() ,当我从内核断开驱动程序时,我有 exit() 。 在此调用 init() 中,我使用 kmalloc() 调用分配物理内存。 在同一个调用中,我用一些数据填充了这个内存,但使用的是逻辑地址(因为从内核我无法访问物理内存)。 在同一个调用中(填充内存后),我触发了一个 DMA 通道来完成工作(我将数据放入 CPU 寄存器)。 因此,DMA 应该从物理 RAM 内存中获取描述符(作为指针)并通过 UART 传输数据。 但似乎在这个“init()”调用中物理内存没有更新。 只更新逻辑 RAM 内存,因为在 CPU 寄存器中我有错误的数据。 但是当我只填充 RAM 描述符数据时,例如在另一个内核回调(退出)中,我触发了 DMA 然后它正在工作 -> 在物理 RAM 内存中是正确的数据并且数据按预期通过 UART 发送。 我不明白这种情况。 为什么在单个 linux 内核驱动回调(即“init”)中物理内存不更新,而只在逻辑内存空间中更新。 为什么 linux 内核驱动程序在写入逻辑内存之后不直接更新物理内存(通过 MMU),而是在这个调用之后(在 leave init() callbcak 之后)?

正如我在问题描述中所写。

我研究了有关 DMA API Linux 的文档。 最后我找到了解决方案。 正如这里的评论所写,缓存一致性存在问题。 而不是使用 kmalloc() 调用为 DMA 分配 RAM 内存应该使用 dma_alloc_coherent() 返回指向内核虚拟地址的指针,并且在参数中它返回没有缓存的物理地址(非缓存)。

这是我的示例/测试代码,它对我有用,现在物理内存会立即更新为内核内存空间中的虚拟内存。 在 RAM 中分配 1024 字节。

static struct device *dev;
static dma_addr_t dma_handle;
static unsigned int *dma_descriptor_tx_ptr;

static void ptr_init(void)
{
    unsigned long long dma_mask = DMA_BIT_MASK(32);
    dev->dma_mask = &dma_mask;
    
    if(dma_set_mask_and_coherent(dev, dma_mask)  != 0)
    {
        printk("Mask not OK\n");
    }
    else
    {
        printk("Mask OK\n");
    }
    
    dma_descriptor_tx_ptr = (unsigned int *)dma_alloc_coherent(dev,  1024,  &dma_handle, GFP_KERNEL);
    
    if(dma_descriptor_tx_ptr != NULL)
    {
        printk("OK \n");
    }
    else
    {
        printk("NOT OK\n");
    }
    
    printk("virt address:  %x\n", dma_descriptor_tx_ptr);
    printk("phys addres: %x\n", dma_handle);
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM