如何解决Linux 内核驱动程序:轮询硬件寄存器
我正在编写一个 Linux 驱动程序,旨在将一些工作委托给硬件加速器。我的驱动程序写了一些寄存器和内存来告诉硬件完成它的工作。硬件完成后,它将通过将状态寄存器设置为 1 来指示。我确实意识到这不是应该这样做的方式,而是应该使用 IRQ,我正计划这样做。但就目前而言,我愿意对该寄存器进行一些投票。我在这里,请教聪明的人,这样做的最佳方法是什么。
我的硬件寄存器使用 ioremap()
映射到内核空间,这是我正在努力处理的代码:
int mailbox_request(const uint32_t *request,size_t request_size,struct mailbox_reply *reply)
{
size_t i;
int retval = 0;
if(down_interruptible(&sem))
return -ERESTARTSYS;
for(i = 0; i < request_size; i++)
iowrite32(mailbox + FIFO_OFFSET,request[i]);
iowrite32(mailbox + CONTROL_OFFSET,1);
// WHAT SHOULD I DO HERE TO WAIT FOR THE RESULT ?
// while(ioread32(mailbox + STATUS_OFFSET) != 1); // better not do that...
reply->data = ioread32(mailbox + RESULT_OFFSET);
out:
up(&sem);
return retval;
}
我的第一个想法是使用工作队列和等待队列,如下所示:
static DECLARE_WORK(workqueue,mailbox_polling_result);
static DECLARE_WAIT_QUEUE_HEAD(wq);
static void mailbox_polling_result(struct work_struct *work)
{
while(ioread32(mailbox + STATUS_OFFSET) != 1)
msleep_interruptible(100);
wake_up_interruptible(&wq);
}
int mailbox_request(const uint32_t *request,struct mailbox_reply *reply)
{
[...]
schedule_work(&workqueue);
wait_event_interruptible(wq,ioread32(mailbox + STATUS_OFFSET) == 1);
[...]
}
我不确定这是否相关,但以防万一:mailbox_request
函数不一定会从进程上下文中调用。它很可能由内核本身调用。我在某处读到工作队列是在进程上下文中执行的,这就是为什么我要告诉您这一点,以确保这不是问题。
然后我想知道 {work,wait} 队列的做法对于我想要实现的目标是否有点矫枉过正?我在某处读到了关于 schedule()
函数的信息,我不得不承认这对我来说有点晦涩。你认为这可以吗:
int mailbox_request(const uint32_t *request,struct mailbox_reply *reply)
{
[...]
while(ioread32(mailbox + STATUS_OFFSET) != 1) {
schedule(); // or maybe some interruptible_sleep ?
}
[...]
}
这个想法是为了防止内核在有更好的事情要做时被卡住。如果您想到更好的方法来做到这一点,我很乐意阅读它!
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。