인터럽트 후반부를 처리하는 soft irq를 배웠다. 자 이제 사용해 보자. 불행히도 요즘은 일반화된 tasklet을 사용하고 low level인 soft irq를 사용하지 않는다고 한다. 그래도 아래 사이트에서 강제로?? 사용할 수 있는 방법을 찾았다. 실습하고 쓰지 말아야 한다. 드라이버를 로딩 후 언로딩하면 시스템이 죽어버린다.
https://embetronicx.com/tutorials/linux/device-drivers/softirq-in-linux-kernel/
요점은 kernel에서 export_symbol로 raise_softirq, open_softiq 등 3개 함수를 내보내 사용할 수 있게한다. interrrupt.h에 사용자 정의 softirq를 설정해야 한다. 기존 등록된 이벤를 사용하면 시스템이 죽는다.
https://stackoverflow.com/questions/39691131/undefined-functions-while-compiling-linux-kernel-module
튜토리얼이 시스템에 장치를 설치하여 인터럽트를 하는 방법으로 했다. 딱히 장치를 추가할 이유가 없는데 왜 했는지 모르겠으나, 아래 사이트에서 간략한 규칙을 찾았다.
https://temp123.tistory.com/16?category=877924
인터럽트를 만들어야 확인할 수 있다. 리눅스가 제공하는 명령어로 gpio를 쉽게 컨트롤 할 수 있다. 당연하게도 출력으로 설정하고 값을 써야한다.
https://infoarts.tistory.com/21
돌고 돌아 장치를 추가하고, 인터럽트를 만들어 softirq를 실행했다. tutorial site에 잘 설명되어 있다. 나중에 디바이스 read, write를 인터럽트로 설정할 수도 있을 듯 하다.
i@raspberrypi:~/RaspberryDebug/my_driver $ cat Makefile obj-m := my_driver.o #obj-m := sample_driver.o all: make -C /lib/modules/`uname -r`/build M=`pwd` modules clean: rm *.o *.ko *.mod *.mod.c *.mod.o
#include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/irq.h> #include <linux/interrupt.h> #include <linux/gpio.h> //GPIO #include <linux/fs.h> #include <linux/cdev.h> #include <linux/device.h> #define GPIO_10_OUT (10) unsigned int GPIO_irqNumber; //softirq handler static void pesudo_interrupt_softirq_handler(struct softirq_action *action) { pr_info("pesudo interreupt occured\n"); } static irqreturn_t gpio_irq_handler(int irq, void *dev_id) { /* Raise the softirq */ raise_softirq(TEST_SOFT_IRQ); return IRQ_HANDLED; } //device driver \uc791\uc131 \ubd80\ubd84. /*************\ub4dc\ub77c\uc774\ubc84 \ud568\uc218 ******************/ static int mydriver_open(struct inode *inode, struct file *file); static int mydriver_release(struct inode *inode, struct file *file); static ssize_t mydriver_read(struct file *flip, char *buf, size_t len, loff_t *off); static ssize_t mydriver_write(struct file *flip, const char *buf, size_t len, loff_t *off); /********************************************/ //file operation structure static struct file_operations fops = { .owner = THIS_MODULE, .read = mydriver_read, .write = mydriver_write, .open = mydriver_open, .release = mydriver_release, }; static int mydriver_open(struct inode *inode, struct file *file) { pr_info("Deviced file was opend.\n"); return 0; } static int mydriver_release(struct inode *inode, struct file *file) { return 0; } static int mydriver_read(struct file *flip, char *buf, size_t len, loff_t *off) { return 0; } static int mydriver_write(struct file *flip, const char *buf, size_t len, loff_t *off) { return 0; } dev_t dev = 0; static struct cdev my_cdev; static struct class *dev_class; static int __init init_hw(void) { //\ub514\ubc14\uc774\uc2a4 \ub4f1\ub85d if(( alloc_chrdev_region(&dev, 0, 1, "test_device") < 0)) { pr_err("[!]character device was not allocated\n"); goto r_unreg; } pr_info("[=]%d-%d, was allocated\n", MAJOR(dev), MINOR(dev)); //\ucd08\uae30\ud654 cdev_init(&my_cdev, &fops); pr_info("[=]driver was initialized\n"); //\uc2dc\uc2a4\ud15c\uc5d0 \ucd94\uac00 if((cdev_add(&my_cdev, dev, 1)) < 0) { pr_err("[!]cannot add device to kernel\n"); goto r_del; } //class \ub9cc\ub4e6. if((dev_class=class_create(THIS_MODULE, "my_class")) == NULL) { pr_err("[!]cannot add class\n"); goto r_class; } if((device_create(dev_class, NULL, dev, NULL, "my_device")) == NULL) { pr_err("[!]cannot create device\n"); goto r_device; } //gpio 10\ubc88\uc744 \uc0ac\uc6a9. //export\ud558\uc5ec \uac04\ub2e8\ud788 \uc0ac\uc6a9. //\uc785\ub825\uc740 \uac12\uc744 \uc368 \ub123\uc744 \uc218 \uc5c6\uc74c. \ucd9c\ub825\uc73c\ub85c \uc124\uc815. GPIO_irqNumber = gpio_to_irq(GPIO_10_OUT); pr_info("[=]irq %d was assinged\n",GPIO_irqNumber); //interrupt \ub4f1\ub85d \ud544\uc694 if (request_irq(GPIO_irqNumber, (void*)gpio_irq_handler, IRQF_TRIGGER_RISING, "my_device", NULL)) { pr_err("[!]my_device: cannot register IRQ\n"); goto r_gpio; } open_softirq(TEST_SOFT_IRQ, pesudo_interrupt_softirq_handler); pr_info("[=]module was installed\n"); return 0; r_gpio: gpio_free(GPIO_10_OUT); r_device: device_destroy(dev_class,dev); r_class: class_destroy(dev_class); r_del: cdev_del(&my_cdev); r_unreg: unregister_chrdev_region(dev,1); return -1; } static void __exit exit_hw(void) { device_destroy(dev_class,dev); class_destroy(dev_class); cdev_del(&my_cdev); unregister_chrdev_region(dev,1); printk(KERN_INFO "module was removed\n"); } module_init(init_hw); module_exit(exit_hw); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Eunseong Park (esp-ark.com)"); MODULE_DESCRIPTION("Hello, world!");
pi@raspberrypi:~/RaspberryDebug/my_driver $ echo "10" > /sys/class/gpio/export pi@raspberrypi:~/RaspberryDebug/my_driver $ echo "out" > /sys/class/gpio/gpio10/direction pi@raspberrypi:~/RaspberryDebug/my_driver $ gpio read 10 1 pi@raspberrypi:~/RaspberryDebug/my_driver $ echo 0 > /sys/class/gpio/gpio10/value ; echo 1 > /sys/class/gpio/gpio10/value; pi@raspberrypi:~/RaspberryDebug/my_driver $ echo 0 > /sys/class/gpio/gpio10/value ; echo 1 > /sys/class/gpio/gpio10/value; pi@raspberrypi:~/RaspberryDebug/my_driver $ echo 0 > /sys/class/gpio/gpio10/value ; echo 1 > /sys/class/gpio/gpio10/value;
[ 281.496011] my_driver: loading out-of-tree module taints kernel. [ 281.496218] my_driver: no symbol version for raise_softirq [ 281.496487] [=]236-0, was allocated [ 281.496492] [=]driver was initialized [ 281.496679] [=]irq 54 was assinged [ 281.496713] [=]module was installed [ 439.643072] pesudo interreupt occured pi@raspberrypi:/sys/class/gpio $ dmesg | tail -10;cat /proc/softirqs [ 21.513881] input: Keyboard K480 Consumer Control as /devices/platform/soc/fe201000.serial/tty/ttyAMA0/hci0/hci0:11/0005:046D:B33C.0003/input/input5 [ 21.514017] input: Keyboard K480 System Control as /devices/platform/soc/fe201000.serial/tty/ttyAMA0/hci0/hci0:11/0005:046D:B33C.0003/input/input6 [ 21.514160] hid-generic 0005:046D:B33C.0003: input,hidraw2: BLUETOOTH HID v28.02 Keyboard [Keyboard K480] on e4:5f:01:06:e9:01 [ 281.496011] my_driver: loading out-of-tree module taints kernel. [ 281.496218] my_driver: no symbol version for raise_softirq [ 281.496487] [=]236-0, was allocated [ 281.496492] [=]driver was initialized [ 281.496679] [=]irq 54 was assinged [ 281.496713] [=]module was installed [ 439.643072] pesudo interreupt occured CPU0 CPU1 CPU2 CPU3 HI: 1 0 0 0 TIMER: 18713 21705 20854 19911 NET_TX: 95 49 315 19 NET_RX: 1125 324 1051 398 BLOCK: 0 0 0 0 IRQ_POLL: 0 0 0 0 TASKLET: 44263 453 587 288 SCHED: 17064 20646 19843 18418 HRTIMER: 0 0 0 0 RCU: 19242 23191 20816 20212 (null): 1 0 0 0 pi@raspberrypi:/sys/class/gpio $ dmesg | tail -10;cat /proc/softirqs [ 21.514017] input: Keyboard K480 System Control as /devices/platform/soc/fe201000.serial/tty/ttyAMA0/hci0/hci0:11/0005:046D:B33C.0003/input/input6 [ 21.514160] hid-generic 0005:046D:B33C.0003: input,hidraw2: BLUETOOTH HID v28.02 Keyboard [Keyboard K480] on e4:5f:01:06:e9:01 [ 281.496011] my_driver: loading out-of-tree module taints kernel. [ 281.496218] my_driver: no symbol version for raise_softirq [ 281.496487] [=]236-0, was allocated [ 281.496492] [=]driver was initialized [ 281.496679] [=]irq 54 was assinged [ 281.496713] [=]module was installed [ 439.643072] pesudo interreupt occured [ 471.316929] pesudo interreupt occured CPU0 CPU1 CPU2 CPU3 HI: 1 0 0 0 TIMER: 18828 21849 21047 20104 NET_TX: 95 49 321 19 NET_RX: 1125 324 1063 398 BLOCK: 0 0 0 0 IRQ_POLL: 0 0 0 0 TASKLET: 44459 453 609 288 SCHED: 17173 20815 20069 18623 HRTIMER: 0 0 0 0 RCU: 19350 23343 20917 20386 (null): 2 0 0 0 pi@raspberrypi:/sys/class/gpio $ dmesg | tail -10;cat /proc/softirqs [ 21.514160] hid-generic 0005:046D:B33C.0003: input,hidraw2: BLUETOOTH HID v28.02 Keyboard [Keyboard K480] on e4:5f:01:06:e9:01 [ 281.496011] my_driver: loading out-of-tree module taints kernel. [ 281.496218] my_driver: no symbol version for raise_softirq [ 281.496487] [=]236-0, was allocated [ 281.496492] [=]driver was initialized [ 281.496679] [=]irq 54 was assinged [ 281.496713] [=]module was installed [ 439.643072] pesudo interreupt occured [ 471.316929] pesudo interreupt occured [ 477.954727] pesudo interreupt occured CPU0 CPU1 CPU2 CPU3 HI: 1 0 0 0 TIMER: 18963 22041 21297 20379 NET_TX: 95 50 325 19 NET_RX: 1128 326 1068 409 BLOCK: 0 0 0 0 IRQ_POLL: 0 0 0 0 TASKLET: 44749 453 647 288 SCHED: 17324 21034 20344 18910 HRTIMER: 0 0 0 0 RCU: 19496 23548 21158 20547 (null): 3 0 0 0 pi@raspberrypi:/sys/class/gpio $ sudo rmmod my_driver pi@raspberrypi:/sys/class/gpio $ dmesg | tail -10;cat /proc/softirqs [ 281.496011] my_driver: loading out-of-tree module taints kernel. [ 281.496218] my_driver: no symbol version for raise_softirq [ 281.496487] [=]236-0, was allocated [ 281.496492] [=]driver was initialized [ 281.496679] [=]irq 54 was assinged [ 281.496713] [=]module was installed [ 439.643072] pesudo interreupt occured [ 471.316929] pesudo interreupt occured [ 477.954727] pesudo interreupt occured [ 497.174610] module was removed CPU0 CPU1 CPU2 CPU3 HI: 1 0 0 0 TIMER: 19416 22394 21661 20809 NET_TX: 95 50 335 19 NET_RX: 1141 331 1087 409 BLOCK: 0 0 0 0 IRQ_POLL: 0 0 0 0 TASKLET: 45416 479 678 288 SCHED: 17800 21462 20753 19347 HRTIMER: 0 0 0 0 RCU: 19908 23925 21541 20832 (null): 3 0 0 0
pi@raspberrypi:/sys/class/gpio $ cat /proc/interrupts CPU0 CPU1 CPU2 CPU3 17: 0 0 0 0 GICv2 29 Level arch_timer 18: 13237 9026 7126 13623 GICv2 30 Level arch_timer 23: 352 0 0 0 GICv2 114 Level DMA IRQ 31: 3111 0 0 0 GICv2 65 Level fe00b880.mailbox 34: 8655 0 0 0 GICv2 153 Level uart-pl011 35: 0 0 0 0 GICv2 169 Level brcmstb_thermal 36: 33671 0 0 0 GICv2 158 Level mmc1, mmc0 37: 17923 0 0 0 GICv2 144 Level vc4 firmware kms 38: 0 0 0 0 GICv2 48 Level arm-pmu 39: 0 0 0 0 GICv2 49 Level arm-pmu 40: 0 0 0 0 GICv2 50 Level arm-pmu 41: 0 0 0 0 GICv2 51 Level arm-pmu 42: 8559 0 0 0 GICv2 106 Level v3d 44: 1557 0 0 0 GICv2 189 Level eth0 45: 52 0 0 0 GICv2 190 Level eth0 51: 707 0 0 0 GICv2 66 Level VCHIQ doorbell 52: 0 0 0 0 GICv2 175 Level PCIe PME, aerdrv 53: 1053 0 0 0 Brcm_MSI 524288 Edge xhci_hcd 54: 2 0 0 0 pinctrl-bcm2835 10 Edge my_device IPI0: 0 0 0 0 CPU wakeup interrupts IPI1: 0 0 0 0 Timer broadcast interrupts IPI2: 12130 21051 27290 15651 Rescheduling interrupts IPI3: 785 1597 1554 1937 Function call interrupts IPI4: 0 0 0 0 CPU stop interrupts IPI5: 793 414 433 246 IRQ work interrupts IPI6: 0 0 0 0 completion interrupts Err: 0
자 이제 커널을 다시 돌리고 tasklet으로 가자. 드라이버를 언로딩하고 cat /proc/interrupt를 하면 시스템이 어쩃든 죽는다. softirq 문제가 아니라, 인터럽트 핸들러를 해제하지 않아서 죽었다.
pi@raspberrypi:~/RaspberryDebug/my_driver $ diff my_driver.c my_driver.c.bak 164d163 < free_irq(GPIO_irqNumber, NULL);