【发布时间】:2021-03-03 20:46:33
【问题描述】:
我有一个 Xilinx SoC,并通过 verilog 在可编程逻辑上创建了一个简单的乘法器。乘法器接受两个 16 位输入,将它们相乘并返回一个 32 位输出。数字设计已通过 AXI-Lite 接口封装并链接到 SoC 内的处理器系统。 Xilinx 工具已为此数字设计自动生成设备树实体,以便可以创建自定义 linux 设备驱动程序以与数字设计交互(即 PS 会将其视为连接到 ARM 处理器的外部硬件设备) .
生成的设备树如下所示:
/ {
amba_pl: amba_pl@0 {
#address-cells = <2>;
#size-cells = <2>;
compatible = "simple-bus";
ranges ;
multi2_0: multi2@a0000000 {
clock-names = "s00_axi_aclk";
clocks = <&zynqmp_clk 71>;
compatible = "xlnx,multi2-1.0";
reg = <0x0 0xa0000000 0x0 0x10000>;
xlnx,s00-axi-addr-width = <0x4>;
xlnx,s00-axi-data-width = <0x20>;
};
};
};
所以从设备树中我们可以看到乘法器(“multi2-1.0”)的物理内存地址为0xa0000000,地址宽度为0x4,数据宽度为32位。
因此,从设备驱动程序的角度来看,特别是在 write 回调函数中,我正在将一个 32 位数字写入从“ioremap(.)”函数检索的虚拟内存地址中。
已进行完整性检查以查看虚拟内存映射到物理地址,并且似乎正确完成且没有错误(驱动程序中的一些与内存相关的代码 sn-ps 如下所示):
struct simpmod_local {
int irq;
unsigned long mem_start;
unsigned long mem_end;
void __iomem *base_addr;
};
struct simpmod_local *lp = NULL;
......
static int simpmod_probe(struct platform_device *pdev)
{ .....
lp->base_addr = ioremap(lp->mem_start, lp->mem_end - lp->mem_start + 1);
...
dev_info(dev,"simpmod at 0x%08x mapped to 0x%08x, irq=%d\n",
(unsigned int __force)lp->mem_start,
(unsigned int __force)lp->base_addr,
lp->irq);
....
}
写回调函数(截至目前)只是获取一个 32 位数字并将其放入内存中。但是,即使我从 base_address+0x20_offset 读取,读取回调函数也只是读取完全相同的数字。我尝试更改偏移值,但无论如何,它一直读取相同的数字。
我的直觉告诉我,如果从不同的内存地址读取该值应该是垃圾值或零,但它不太可能读取写入基地址的相同值。关于为什么写入的数据会在整个分配的内存空间中复制的任何想法?
即使执行 devmem 命令
write-callback 函数如下所示:
static ssize_t dev_write(struct file *fil, const char *buf, size_t len, loff_t *off){
sscanf (buf,"%d,%d",&operand_1,&operand_2);
ker_buf[len] = 0 ;
iowrite32((unsigned int) operand_1, lp->base_addr);
return len;
}
完整的项目代码(稍作改动)可以在https://forums.xilinx.com/t5/Embedded-Linux/Memory-Replications-during-write-call-back-function-in-Linux/m-p/1212405找到
【问题讨论】:
-
所以读取回调是您实际观察到令人惊讶的结果的地方?你有没有考虑到错误可能存在?
-
你为什么使用
sscanf[inside a driver] 来获取端口地址?sscanf是 slow 并且永远不会以您使用它的方式在驱动程序中使用。operand_2[你不用于任何事情]是什么?添加printk以显示所有相关值[写之前]。许多需要用户空间写入端口的驱动程序可能不会将其映射到设备write回调,但会创建一个[自定义]ioctl和您设计的struct。拥有一个全球性的lp是坏事。lp应该来自platform_device中的每设备私有指针 -
@JohnBollinger 你好约翰,读取回调(截至目前)基本上只是一个 ioread32((unsigned int __force)lp->base_addr+0x20);我已经测试了一段时间,所以现在有点乱。但基本上,我的问题是,无论偏移量是多少(当前为 0x20),读取值都是相同的。从命令行运行 devmem 时会发生类似的问题。
-
您好@CraigEstey,感谢您的指点。你认为这就是问题所在吗(请记住 devmem 会导致同样的奇怪问题)。
-
我会尝试为他们提供的标准设备找到 Xilinx 提供的设备驱动程序,以用作 DTB/DTC 条目的参考设计以及如何使用它。 [此处] 缺少扫描 DTB 并提取数据的代码。我会添加一些诊断代码[从
probe或open调用] 来验证简单的操作:2*2 == 4、17 * 37 == 629等带有硬连线调用 [vs.等待来自用户空间的数据]。您甚至可以让它转储周围的记忆词以寻找 [已知] 结果。乘数是标准宏 [由 Xilinx 提供] 还是您自己的定制设计?
标签: c linux linux-kernel driver xilinx