printf "\x01\x00\x00\x00" > /dev/qemu-io-intr
gic_poke_irq: mask=0x40000000, offset=0x200 (hwirq=94)
IO-INTR Interrupt triggered! (irq=27, count=12, cpu=0)
IO-INTR Trigger IRQ 27 pending state
/ #
/ #
/ #
/ # cat /proc/interrupts
CPU0
16: 162498 GIC 29 Edge twd
17: 6 GIC 34 Level timer
27: 12 GIC 94 Level qemu-io-intr
29: 0 GIC 47 Level eth0
32: 1065 GIC 41 Level mmci-pl18x (cmd)
33: 40749 GIC 42 Level mmci-pl18x (pio)
34: 8 GIC 44 Level kmi-pl050
35: 100 GIC 45 Level kmi-pl050
36: 241 GIC 37 Level uart-pl011
42: 0 GIC 36 Level rtc-pl031
IPI0: 0 CPU wakeup interrupts
IPI1: 0 Timer broadcast interrupts
IPI2: 0 Rescheduling interrupts
IPI3: 0 Function call interrupts
IPI4: 0 Single function call interrupts
IPI5: 0 CPU stop interrupts
IPI6: 0 IRQ work interrupts
IPI7: 0 completion interrupts
Err: 0
#if 1
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/sched.h>
#include <linux/uaccess.h>
#include <linux/irqdesc.h>
#include <linux/of.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/moduleparam.h>
#define DEV_NAME "qemu-io-intr"
static int dev_major = 241;
#define VIRTUAL_IRQ 27 // 内核虚拟中断号
static int irq_count = 0; // 中断计数
static dev_t devno; // 设备号
static struct cdev cdev; // 字符设备结构体
static struct class *io_intr_class;
static int test_irq_dev_id = 1; // 中断dev_id(必须和request_irq保持一致)
// 中断处理函数(自动ACK模式:仅计数+日志,内核自动处理ACK)
irqreturn_t io_intr_handler(int irq, void *dev_id)
{
// 移除手动清除挂起位的代码,由内核自动ACK
irq_count++;
printk(KERN_INFO "IO-INTR Interrupt triggered! (irq=%d, count=%d, cpu=%d)\n",
irq, irq_count, raw_smp_processor_id());
// 返回IRQ_HANDLED后,内核会自动完成中断应答和清除
return IRQ_HANDLED;
}
// write函数:仅触发中断,不手动处理ACK
ssize_t io_intr_write(struct file *filp, const char __user *buf, size_t len, loff_t *off)
{
u32 val = 0;
int ret = 0;
if (len < sizeof(u32)) {
return -EINVAL;
}
ret = copy_from_user(&val, buf, sizeof(u32));
if (ret) {
return -EFAULT;
}
// 仅触发中断,内核自动处理ACK
if (val == 1) {
irq_set_irqchip_state(VIRTUAL_IRQ, IRQCHIP_STATE_PENDING, true);
printk(KERN_INFO "IO-INTR Trigger IRQ %d pending state\n", VIRTUAL_IRQ);
}
return sizeof(u32);
}
// read函数:读取中断计数
ssize_t io_intr_read(struct file *filp, char __user *buf, size_t len, loff_t *off)
{
u32 val = irq_count;
int ret = 0;
if (len < sizeof(u32)) {
return -EINVAL;
}
ret = copy_to_user(buf, &val, sizeof(u32));
if (ret) {
return -EFAULT;
}
return sizeof(u32);
}
// 字符设备操作集
static const struct file_operations io_intr_fops = {
.owner = THIS_MODULE,
.write = io_intr_write,
.read = io_intr_read,
.llseek = default_llseek,
};
// platform驱动probe函数(核心:恢复内核自动ACK流程)
static int io_intr_probe(struct platform_device *pdev)
{
int ret;
// 申请中断:使用内核默认的处理流程(自动ACK)
// 关键:移除IRQF_TRIGGER_RISING,使用Level触发(匹配GIC默认),不手动切换handler
ret = request_irq(VIRTUAL_IRQ, // 中断号27
io_intr_handler, // 中断处理函数
IRQF_TRIGGER_HIGH | IRQF_NO_SUSPEND, // Level高电平触发(内核自动ACK)
DEV_NAME, // 中断名称
&test_irq_dev_id); // dev_id(和free_irq保持一致)
if (ret < 0) {
printk(KERN_ERR "IO-INTR request_irq failed (ret=%d)\n", ret);
return ret;
}
// 移除手动切换handler和clear_flags的代码:使用内核默认handler(自动ACK)
// 移除enable_irq:request_irq后内核自动使能中断,避免不平衡警告
printk(KERN_INFO "IO-INTR Request irq %d success (auto ACK mode)\n", VIRTUAL_IRQ);
// 字符设备注册流程
if (dev_major) {
devno = MKDEV(dev_major, 0);
ret = register_chrdev_region(devno, 1, DEV_NAME);
} else {
ret = alloc_chrdev_region(&devno, 0, 1, DEV_NAME);
dev_major = MAJOR(devno); // 动态分配时更新主设备号
}
if (ret < 0) {
free_irq(VIRTUAL_IRQ, &test_irq_dev_id); // 传匹配的dev_id
return ret;
}
cdev_init(&cdev, &io_intr_fops);
cdev.owner = THIS_MODULE;
ret = cdev_add(&cdev, devno, 1);
if (ret < 0) {
unregister_chrdev_region(devno, 1);
free_irq(VIRTUAL_IRQ, &test_irq_dev_id);
return ret;
}
// 创建设备类和设备节点(自动生成/dev/qemu-io-intr)
io_intr_class = class_create(THIS_MODULE, DEV_NAME);
if (IS_ERR(io_intr_class)) {
ret = PTR_ERR(io_intr_class);
cdev_del(&cdev);
unregister_chrdev_region(devno, 1);
free_irq(VIRTUAL_IRQ, &test_irq_dev_id);
return ret;
}
device_create(io_intr_class, NULL, devno, NULL, DEV_NAME);
printk(KERN_INFO "IO-INTR Probed successfully! (irq=%d, major=%d)\n",
VIRTUAL_IRQ, dev_major);
return 0;
}
// platform驱动remove函数(修正free_irq传参)
static int io_intr_remove(struct platform_device *pdev)
{
// 清理设备节点
device_destroy(io_intr_class, devno);
class_destroy(io_intr_class);
cdev_del(&cdev);
unregister_chrdev_region(devno, 1);
// 关键:free_irq的dev_id必须和request_irq一致(不能传NULL)
free_irq(VIRTUAL_IRQ, &test_irq_dev_id);
printk(KERN_INFO "IO-INTR Removed successfully (irq_count=%d)\n", irq_count);
return 0;
}
// 设备树匹配表
static const struct of_device_id io_intr_of_match\[\] = {
{ .compatible = "qemu,io-intr" },
{ },
};
MODULE_DEVICE_TABLE(of, io_intr_of_match);
// platform驱动结构体
static struct platform_driver io_intr_driver = {
.probe = io_intr_probe,
.remove = io_intr_remove,
.driver = {
.name = DEV_NAME,
.of_match_table = io_intr_of_match,
.owner = THIS_MODULE,
},
};
// 注册platform驱动
module_platform_driver(io_intr_driver);
module_param(dev_major, int, S_IRUGO);
MODULE_PARM_DESC(dev_major, "Major device number for qemu-io-intr (0=dynamic)");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("xiao dou AI");
#endif