Can I use sysfs_notify() from several attributes on the same kobj simultaneously?
I'm trying to make a linux device driver for notify interrupt comes from HW to userspace.Yes I know there are other several methods for this(uio, mmap and etc) but my legacy driver used sysfs so I trying to use sysfs_notify() from interrupt handler.
My driver has to handle some of interrupt sources more than two so I made one of sysfs class and some attributes to notify interrupt via attirutes with sysfs_notify().The interrupts will be occurred 30 times in a second and there are multiple interrupt sources.
I've found there are attributes after insmod foo.ko in sysfs like /sys/devices/platform/foo_device/intr0 and /sys/devices/platform/foo_device/intr1.
My problem comes from here. If I enabled only one interrupt and one of ISR call sysfs_notify() then it works well but if I enabled more than two interrups then kernel stucks on spin_lock or some conditions and doesn't give any reactions even if I type the keyboard, ping to the targer and so on.
My source code looks like this
static struct foo_attr foo_notify_0;static struct foo_attr foo_notify_1;static struct attribute *foo_attrs[] = {&foo_notify_0.attr.attr,&foo_notify_1.attr.attr, NULL};ATTRIBUTE_GROUPS(foo);static ssize_t foo_sysfs_push_intr_0(struct device *dev, struct device_attribute *attr, const char *buf, size_t len){ // USER_DEFINE function struct foo_attr *foo = container_of(attr, struct foo_attr, attr); sscanf(buf, "%d", &foo->value); sysfs_notify(&dev->kobj, NULL, "foo_notify_0"); return len;}static ssize_t foo_sysfs_push_intr_1(struct device *dev, struct device_attribute *attr, const char *buf, size_t len){ // USER_DEFINE function struct foo_attr *foo = container_of(attr, struct foo_attr, attr); static int count = 0; if(count++%30==0) printk("1 %p\n", &dev->kobj); sscanf(buf, "%d", &foo->value); sysfs_notify(&dev->kobj, NULL, "foo_notify_1"); return len;}static struct foo_attr foo_notify_0 = { .attr = __ATTR(intr0, 0644, foo_sysfs_show, foo_sysfs_push_intr_0), .value = 0,};static struct foo_attr foo_notify_1 = { .attr = __ATTR(intr1, 0644, foo_sysfs_show, foo_sysfs_push_intr_1), .value = 0,};static struct platform_device foo_device = { .name = "nextchip,foo", .id = PLATFORM_DEVID_NONE, .dev.groups = foo_groups,};static irqreturn_t foo_isr_intp_0(int irq, void *priv){ struct device *dev = &foo_device.dev; struct device_attribute *attr = &foo_notify_0.attr; struct foo_attr *foo = container_of(attr, struct foo_attr, attr); int ch = 0; //DEBUG_TRACE; // interrupt pending clear writel(1<<ch, foo_res->base + 0x140); foo_sysfs_push_intr_0(dev, attr, "1", 1); return IRQ_HANDLED;}static irqreturn_t foo_isr_intp_1(int irq, void *priv){ struct device *dev = &foo_device.dev; struct device_attribute *attr = &foo_notify_1.attr; struct foo_attr *foo = container_of(attr, struct foo_attr, attr); int ch = 1; //DEBUG_TRACE; // interrupt pending clear writel(1<<ch, foo_res->base + 0x140); foo_sysfs_push_intr_1(dev, attr, "1", 1); return IRQ_HANDLED;}static int foo_probe(struct platform_device *pdev){ ... foo_res->irq[0] = platform_get_irq_byname(pdev, "foo_vsip"); foo_res->irq[1] = platform_get_irq_byname(pdev, "foo_vsin"); ret = devm_request_irq(&pdev->dev, foo_res->irq[0], foo_isr_intp_0, IRQF_TRIGGER_RISING, "foo_vsip", NULL); ret = devm_request_irq(&pdev->dev, foo_res->irq[1], foo_isr_intp_1, IRQF_TRIGGER_RISING, "foo_vsin", NULL); ...}