C Linux内核:AXI互连,在哪里以及如何处理?
我正在为我的公司编写一个Linux驱动程序,以便将我们的硬件移植到GNU/Linux桌面。我根本不是一个硬件爱好者,我正在努力理解内核和硬件之间的通信是如何进行的 我们基本上有一个AXI互连,其中一些IP是有线连接的(我们使用的是运行Linux的Xilinx板) 我已经能够向硬件发送请求,它工作得很好,但我觉得我遗漏了一些东西。 在内核中,由于C Linux内核:AXI互连,在哪里以及如何处理?,c,linux,linux-kernel,linux-device-driver,hardware,C,Linux,Linux Kernel,Linux Device Driver,Hardware,我正在为我的公司编写一个Linux驱动程序,以便将我们的硬件移植到GNU/Linux桌面。我根本不是一个硬件爱好者,我正在努力理解内核和硬件之间的通信是如何进行的 我们基本上有一个AXI互连,其中一些IP是有线连接的(我们使用的是运行Linux的Xilinx板) 我已经能够向硬件发送请求,它工作得很好,但我觉得我遗漏了一些东西。 在内核中,由于ioremap(),我将物理地址映射到虚拟地址,并且我自己实现了读/写操作,如下所示: static void\uu iomem*邮箱; 静态ssize\
ioremap()
,我将物理地址映射到虚拟地址,并且我自己实现了读/写操作,如下所示:
static void\uu iomem*邮箱;
静态ssize\u t邮箱读取(结构文件*filp,字符*user*buf,大小\u t计数,loff\u t*f\u pos)
{
ssize_t retval=0;
uint32_t mlb_数据=0;
if(向下可中断(&sem))
返回-ERESTARTSYS;
//*f_pos必须是4的倍数
//*f_位置必须在边界内
//计数必须为4(邮箱一次仅支持读取4个字节)
如果(*f|u pos%4 |*f|pos>=邮箱大小|计数!=大小(mlb|u数据)){
retval=-EINVAL;
出去;
}
mlb_data=readl(邮箱+*f_位置);
if(复制到用户(buf和mlb数据,计数)){
retval=-EFAULT;
出去;
}
*f_pos+=计数;
retval=计数;
输出:
up&sem;
返回返回;
}
int邮箱初始化(开发设备)
{
邮箱=ioremap\u nocache(MLB\u基本地址,邮箱大小);
如果(!邮箱){
printk(KERN_ERR DRIVER_NAME):无法映射邮箱,ioremap失败。\n“;
返回错误;
}
返回0;
}
在用户端,我尝试这样读/写:
int dev_fd=open(“/dev/”驱动程序名,O_RDWR);
如果(dev_fd<0)返回任何值;
int数据;
pread(dev_fd和data,sizeof data,0);
关闭(dev_fd);
它工作得很好,但我不明白它怎么会这么简单,所有的AXI东西都在哪里处理?我认为这是我必须要做的事情,但我惊讶地发现一切都已经很好了
我发现一切都是透明的,这真的很好,但问题是我想实现一些错误处理,而我不知道如何去做
例如,如果我试图使用(内部使用)从不受支持的地址读取,我会得到一个总线错误:
root@petalinux:~#devmem 0xCAFEBABE
总线错误
但是如果我尝试通过我自己的角色设备做同样的事情,它就会挂起。似乎没有收到任何SIGBUS
我不确定我是否说得很清楚,所以这里是我的两个问题:
- Linux内核中的AXI在哪里处理?它可能是Xilinx驱动程序“覆盖”了我的吗
- 如何通过向userland应用程序发送SIGBUS来处理像
这样的硬件故障/dev/mem
mailbox
)会导致readl()
、writel()
、memcpy\u fromio()
等正确处理访问
如何在硬件级别执行此操作的详细信息取决于硬件体系结构。例如,mach-ipx4xx使用宏来确定(通过inl()
)还是/应该使用
loff\u t
是有符号的,当偏移量无效时,返回-EFAULT而不是-EINVAL可能更有意义:
//*f_位置必须在范围内
如果(*f|pos<0 | |*f|pos>=邮箱大小){
retval=-EFAULT;
出去;
}
//*f_pos必须是4的倍数,并且
//计数必须为4(邮箱一次仅支持读取4个字节)
if((*f_位置&3)|计数!=mlb_数据的大小){
retval=-EINVAL;
出去;
}
ioread32()
只调用readl()
,因此这不是一个功能更改;这更多的是通过保持当前推荐的内部内核接口,更易于长期维护
(关于“[某些]体系结构不能使用此通用接口”的评论是针对体系结构维护人员的,他们不能仅仅依赖于通用接口,而是需要在特定于arch的文件中为其硬件体系结构实现宏。驱动程序开发人员可以依赖这些宏的可用性和正常工作。)
struct内核\u siginfo;
清除_siginfo(&info);//重要!这样就不会泄露到用户空间。
info.si_signo=SIGBUS;
info.si_code=BUS_ADRALN;//原因,请参见include/uapi/asm generic/siginfo.h
info.si_errno=0;
info.si_addr=addr;//错误地址
info.si_addr_lsb=lsb;//地址的最低有效位
强制信号信息(&info);
我希望这会有所帮助,并且即使只有少数用户,您也会将GPL驱动程序推到上游。Greg KH过去尤其在这方面提供了帮助。我想,就Linux而言,“AXI东西”只包括读取/写入邮箱寄存器,其余的都是在硬件逻辑中完成的。非常感谢你令人惊讶的回答,我没想到会有这么好的回答!如果你愿意,我还有几个问题要问你:在ARM64上,这是[]数组中的第16个条目。发生时,调用do_sea()函数;那个叫。如果导致故障的代码在用户空间中运行,则该进程将被终止;但是如果代码在内核中,您将得到一个oops。由于arm64上的数组是静态常量,我们无法修改它。您的用户空间