处理字符设备中的中断
Handling interrupt in character device
我正在尝试在用户界面的内核中正确注册中断。
令人惊讶的是,我没有在内核中找到很多这样的例子。
irq 处理程序
static irqreturn_t irq_handler(int irq, void *dev_id)
{
struct el_irq_dev *el_irq = &el_irq_devices[0];
printk("irq in\n");
spin_lock(&el->my_lock,flags);
clear_interrupt()
some_buffer[buf_wr] = ch;
el_irq->buf_wr++;
if (el_irqbuf_wr >= 16)
el_irqbuf_wr = 0;
spin_unlock(&el->my_lock,flags);
wake_up_interruptible(&el->pollw);
return IRQ_HANDLED;
}
ioctl 用于等待中断
static long el_device_ioctl( struct file *filp,
unsigned int ioctl_num,
unsigned long ioctl_param)
{
struct el_irq_dev *el_irq = &el_irq_devices[0];
switch (ioctl_num) {
case IOCTL_WAIT_IRQ: <<<---- using ioctl (no poll) to wait on interrupt
wait_event_interruptible(el_irq->pollw, &el_irq->buf_wr != &el_irq->buf_rd) ;
spin_lock(&el_irq->my_lock);
if (el_irq->buf_wr != &el_irq->buf_rd)
{
my_value=some_buffer[el_irq->buf_rd];
el_irq->buf_rd++;
if (el_irq->buf_rd >= 16)
el_irq->buf_rd = 0;
}
spin_unlock(&el_irq->my_lock);
copy_to_user(ioctl_param,&my_value,sizeof(my_value));
default:
break;
}
return 0;
}
我的问题是:
- 我们是否应该将fpga中的中断清除(clear_interrupt())放在中断中
在 wake_up 之前还是之后?我们能否将清除中断事件放在用户空间处理程序 (IOCTL_WAIT_IRQ) 中,而不是在
中断处理程序 ?
- 如您在代码中所见,我使用循环缓冲区来处理用户空间处理程序缺少中断的情况。这真的是必需的,还是我们可以假设没有遗漏?
换句话说,假设永远不会错过中断是否合理?这样 ioctl 调用就永远不会看到超过 1 个等待中断?如果是 - 也许我不需要中断处理程序和 ioctl 处理程序之间的缓冲机制。
谢谢,
运行
简答。
- 我认为清除 user-space 处理程序中的中断似乎是合理的。在完成所有工作之后,尽可能晚地进行是有道理的,只要您在清除后再次检查确实没有剩下的工作要做(可能在清除之前还有一些工作已经到达)。
- user-space 处理程序可能确实错过了中断,例如如果在调用 IOCTL_WAIT_IRQ 之间有几个到达。如果在清除中断之前有几项工作到达,中断在某种意义上也可能会得到 "missed"。堆栈(硬件和软件)的设计应确保这不是问题。中断应该只发出有工作要做的信号,user-space 处理程序应该能够在返回之前完成所有未完成的工作。
- 您可能应该在 IOCtl 代码中使用 spin_lock_irqsave()[1]。
我正在尝试在用户界面的内核中正确注册中断。
令人惊讶的是,我没有在内核中找到很多这样的例子。
irq 处理程序
static irqreturn_t irq_handler(int irq, void *dev_id)
{
struct el_irq_dev *el_irq = &el_irq_devices[0];
printk("irq in\n");
spin_lock(&el->my_lock,flags);
clear_interrupt()
some_buffer[buf_wr] = ch;
el_irq->buf_wr++;
if (el_irqbuf_wr >= 16)
el_irqbuf_wr = 0;
spin_unlock(&el->my_lock,flags);
wake_up_interruptible(&el->pollw);
return IRQ_HANDLED;
}
ioctl 用于等待中断
static long el_device_ioctl( struct file *filp,
unsigned int ioctl_num,
unsigned long ioctl_param)
{
struct el_irq_dev *el_irq = &el_irq_devices[0];
switch (ioctl_num) {
case IOCTL_WAIT_IRQ: <<<---- using ioctl (no poll) to wait on interrupt
wait_event_interruptible(el_irq->pollw, &el_irq->buf_wr != &el_irq->buf_rd) ;
spin_lock(&el_irq->my_lock);
if (el_irq->buf_wr != &el_irq->buf_rd)
{
my_value=some_buffer[el_irq->buf_rd];
el_irq->buf_rd++;
if (el_irq->buf_rd >= 16)
el_irq->buf_rd = 0;
}
spin_unlock(&el_irq->my_lock);
copy_to_user(ioctl_param,&my_value,sizeof(my_value));
default:
break;
}
return 0;
}
我的问题是:
- 我们是否应该将fpga中的中断清除(clear_interrupt())放在中断中 在 wake_up 之前还是之后?我们能否将清除中断事件放在用户空间处理程序 (IOCTL_WAIT_IRQ) 中,而不是在 中断处理程序 ?
- 如您在代码中所见,我使用循环缓冲区来处理用户空间处理程序缺少中断的情况。这真的是必需的,还是我们可以假设没有遗漏? 换句话说,假设永远不会错过中断是否合理?这样 ioctl 调用就永远不会看到超过 1 个等待中断?如果是 - 也许我不需要中断处理程序和 ioctl 处理程序之间的缓冲机制。
谢谢, 运行
简答。
- 我认为清除 user-space 处理程序中的中断似乎是合理的。在完成所有工作之后,尽可能晚地进行是有道理的,只要您在清除后再次检查确实没有剩下的工作要做(可能在清除之前还有一些工作已经到达)。
- user-space 处理程序可能确实错过了中断,例如如果在调用 IOCTL_WAIT_IRQ 之间有几个到达。如果在清除中断之前有几项工作到达,中断在某种意义上也可能会得到 "missed"。堆栈(硬件和软件)的设计应确保这不是问题。中断应该只发出有工作要做的信号,user-space 处理程序应该能够在返回之前完成所有未完成的工作。
- 您可能应该在 IOCtl 代码中使用 spin_lock_irqsave()[1]。