Bart
Bart

Reputation: 1

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

I'm using Orange Pi3 LTS with Allwinner H6 ARM CPU. I'm writing now UART driver with DMA for Rx and Tx. I allocated physical RAM memory using kmalloc() call and I got physical and logical address for my allocated memory. So, I know physical address in processor and corresponding logical address in Linux Kernel Driver space. I have a problem with updating physical memory after update logical. I mean, for example in my linux kernel driver I have callback init() when I'm attaching my driver to kernel and exit() when I'm disconnecting driver from kernel. In this call init() I'm allocating physical memory using kmalloc() call. In the same call I'm filling this memory with some data, but using logical address (because from kernel I can't access physical memory). In the same call (after fill memory) I'm triggering one of DMA channel to do job (I'm putting data to CPU registers). So, DMA should take descriptor (as pointer) from physical RAM memory and do some job for transmit data over UART. But it seems that physical memory is not updated in this "init()" call. Only logical RAM memory is updated, because in CPU registers I have wrong data. But when I put filling in RAM only descriptor data and for example in another kernel callback (exit) I'm triggering DMA then it is working -> in physical RAM memory is correct data and data is sending over UART as expected. I don't understand this situation. Why in single linux kernel driver callback (i.e. "init") physical memory is not updated, but it is updated only in logical memory space. Why linux kernel driver is not updating physical memory (over MMU) directly after write to logical memory, but after this call (after leave init() callbcak)?

As I wrote in problem description.

Upvotes: 0

Views: 360

Answers (1)

Bart
Bart

Reputation: 1

I studied documentation about DMA API Linux. Finally I found solution.

As was wrote in comment here was a problem with cache coherency. Instead of use kmalloc() call to allocate RAM memory for DMA should be use dma_alloc_coherent() which returns pointer to logical address for kernel and also in argument it returns physical address without cache (non-cached).

Here is my example/test code which is working for me and now physical memory is updated immediately with logical inside kernel memory space. Allocation of 1024 bytes in RAM.

static struct device *dev;
static dma_addr_t physical_address;
static unsigned int *logical_address;

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");
    
    logical_address = (unsigned int *)dma_alloc_coherent(dev,  1024,  &physical_address, GFP_KERNEL);
    
    if (logical_address != NULL)
        printk("allocation OK \n");
    else
        printk("allocation NOT OK\n");
    
    printk("logical address:  %x\n", logical_address);
    printk("physical address: %x\n", physical_address);
}

Upvotes: 0

Related Questions