linux - I/O 内存访问可以在 Linux (ARM) 下的 ISR 中使用吗?

标签 linux io arm driver isr

我正在为 Linux 下的 FPGA 通信创建驱动程序。 FPGA通过GPMC接口(interface)连接。当我从驱动程序上下文测试读/写时 - 一切正常。但问题是我需要在中断时读取一些地址。所以我创建了中断处理程序,将其注册并将 iomemory 读取放入其中(readw 函数)。但是当中断被触发时 - 只读取零。我从上到下测试了驱动程序的每个部分,看起来问题出在 ISR 中的内存访问中。当我用常量值替换 io 访问时 - 它成功传递给用户级应用程序。

ARM 版本:armv7a (Cortex ARM-A8 (DM3730))

编译器:CodeSourcery 2014.05

这是来自驱动程序的一些代码,表示已执行的操作:

// Request physical memory region for FPGA address IO
void* uni_PhysMem_request(const unsigned long addr, const unsigned long size) {
    // Handle to be returned
    void* handle = NULL;
    // Check if memory region successfully requested (mapped to module)
    if (!request_mem_region(addr, size, moduleName)) {
        printk(KERN_ERR "\t\t\t\t%s() failed to request_mem_region(0x%p, %lu)\n", __func__, (void*)addr, size);
    }
    // Remap physical memory
    if (!(handle = ioremap(addr, size))) {
        printk(KERN_ERR "\t\t\t\t%s() failed to ioremap(0x%p, %lu)\n", __func__, (void*)addr, size);
    }
    // Return virtual address;
    return handle;
}

// ...

// ISR
static irqreturn_t uni_IRQ_handler(int irq, void *dev_id) {
    size_t readed = 0;
    if (irq == irqNumber) {
        printk(KERN_DEBUG "\t\t\t\tIRQ handling...\n");
        printk(KERN_DEBUG "\t\t\t\tGPIO %d pin is %s\n", irqGPIOPin, ((gpio_get_value(irqGPIOPin) == 0) ? "LOW" : "HIGH"));
        // gUniAddr is a struct which holds GPMC remapped virtual address (from uni_PhysMem_request), offset and read size
        if ((readed = uni_ReadBuffer_IRQ(gUniAddr.gpmc.addr, gUniAddr.gpmc.offset, gUniAddr.size)) < 0) {
            printk(KERN_ERR "\t\t\t\tunable to read data\n");
        }
        else {
            printk(KERN_INFO "\t\t\t\tdata readed success (%zu bytes)\n", readed);
        }
    }
    return IRQ_HANDLED;
}

// ...

// Read buffer by IRQ
ssize_t uni_ReadBuffer_IRQ(void* physAddr, unsigned long physOffset, size_t buffSize) {
    size_t size = 0;
    size_t i;
    for (i = 0; i < buffSize; i += 2) {
        size += uni_RB_write(readw(physAddr + physOffset)); // Here readed value sent to ring buffer. When "readw" replaced with any constant - everything OK
    }
    return size;
}

最佳答案

看起来问题出在代码优化上。我更改了 uni_RB_write 函数以传递物理地址和数据大小,现在还通过 ioread16_rep 函数读取。所以现在一切正常。

关于linux - I/O 内存访问可以在 Linux (ARM) 下的 ISR 中使用吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51267564/

相关文章:

c - C中的函数指针和内存地址

java - 扫描仪在使用 next() 或 nextFoo() 后跳过 nextLine()?

haskell - 如何在 Haskell 中将 IO [[Int]] 转换为 [[Int]]?

c - C 编程中的 Hex 文件读取?

c - ARM 程序集 - bl 分支到错误的地址

c++ - 核心转储消息未在 STDERR 中捕获

java - 将 NetBeans 项目从 Windows 转移到 Linux VM 时 Ant 构建出错

assembly - ARM 汇编分支到寄存器或内存内部的地址

c++ - 在 Linux C++ 中获取虚拟内存最大映射计数

assembly - 如何运行 linaro 汇编程序以获取 thumb2 (T32) 指令