Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F140113286
D30549.id91069.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
5 KB
Referenced Files
None
Subscribers
None
D30549.id91069.diff
View Options
diff --git a/sys/compat/linuxkpi/common/include/linux/interrupt.h b/sys/compat/linuxkpi/common/include/linux/interrupt.h
--- a/sys/compat/linuxkpi/common/include/linux/interrupt.h
+++ b/sys/compat/linuxkpi/common/include/linux/interrupt.h
@@ -37,6 +37,7 @@
#include <linux/irqreturn.h>
#include <linux/hardirq.h>
+#include <sys/param.h>
#include <sys/bus.h>
#include <sys/rman.h>
#include <sys/interrupt.h>
@@ -51,10 +52,15 @@
struct resource *res;
void *arg;
irqreturn_t (*handler)(int, void *);
+ irqreturn_t (*thread_handler)(int, void *);
void *tag;
unsigned int irq;
};
+void linux_irq_handler(void *);
+void lkpi_devm_irq_release(struct device *, void *);
+void lkpi_irq_release(struct device *, struct irq_ent *);
+
static inline int
linux_irq_rid(struct device *dev, unsigned int irq)
{
@@ -65,8 +71,6 @@
return (0);
}
-extern void linux_irq_handler(void *);
-
static inline struct irq_ent *
linux_irq_ent(struct device *dev, unsigned int irq)
{
@@ -80,8 +84,9 @@
}
static inline int
-request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,
- const char *name, void *arg)
+_request_irq(struct device *xdev, unsigned int irq,
+ irq_handler_t handler, irq_handler_t thread_handler,
+ unsigned long flags, const char *name, void *arg)
{
struct resource *res;
struct irq_ent *irqe;
@@ -92,27 +97,70 @@
dev = linux_pci_find_irq_dev(irq);
if (dev == NULL)
return -ENXIO;
+ if (xdev != NULL && xdev != dev)
+ return -ENXIO;
rid = linux_irq_rid(dev, irq);
res = bus_alloc_resource_any(dev->bsddev, SYS_RES_IRQ, &rid,
flags | RF_ACTIVE);
if (res == NULL)
return (-ENXIO);
- irqe = kmalloc(sizeof(*irqe), GFP_KERNEL);
+ if (xdev != NULL)
+ irqe = lkpi_devres_alloc(lkpi_devm_irq_release, sizeof(*irqe),
+ GFP_KERNEL | __GFP_ZERO);
+ else
+ irqe = kzalloc(sizeof(*irqe), GFP_KERNEL);
irqe->dev = dev;
irqe->res = res;
irqe->arg = arg;
irqe->handler = handler;
+ irqe->thread_handler = thread_handler;
irqe->irq = irq;
+
error = bus_setup_intr(dev->bsddev, res, INTR_TYPE_NET | INTR_MPSAFE,
NULL, linux_irq_handler, irqe, &irqe->tag);
- if (error) {
- bus_release_resource(dev->bsddev, SYS_RES_IRQ, rid, irqe->res);
- kfree(irqe);
- return (-error);
- }
+ if (error)
+ goto errout;
list_add(&irqe->links, &dev->irqents);
+ if (xdev != NULL)
+ devres_add(xdev, irqe);
return 0;
+
+errout:
+ bus_release_resource(dev->bsddev, SYS_RES_IRQ, rid, irqe->res);
+ if (xdev != NULL)
+ devres_free(irqe);
+ else
+ kfree(irqe);
+ return (-error);
+}
+
+static inline int
+request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,
+ const char *name, void *arg)
+{
+
+ return (_request_irq(NULL, irq, handler, NULL, flags, name, arg));
+}
+
+static inline int
+request_threaded_irq(int irq, irq_handler_t handler,
+ irq_handler_t thread_handler, unsigned long flags,
+ const char *name, void *arg)
+{
+
+ return (_request_irq(NULL, irq, handler, thread_handler,
+ flags, name, arg));
+}
+
+static inline int
+devm_request_threaded_irq(struct device *dev, int irq,
+ irq_handler_t handler, irq_handler_t thread_handler,
+ unsigned long flags, const char *name, void *arg)
+{
+
+ return (_request_irq(dev, irq, handler, thread_handler,
+ flags, name, arg));
}
static inline int
@@ -166,26 +214,41 @@
}
static inline void
-free_irq(unsigned int irq, void *device)
+free_irq(unsigned int irq, void *device __unused)
{
struct irq_ent *irqe;
struct device *dev;
- int rid;
dev = linux_pci_find_irq_dev(irq);
if (dev == NULL)
return;
- rid = linux_irq_rid(dev, irq);
irqe = linux_irq_ent(dev, irq);
if (irqe == NULL)
return;
- if (irqe->tag != NULL)
- bus_teardown_intr(dev->bsddev, irqe->res, irqe->tag);
- bus_release_resource(dev->bsddev, SYS_RES_IRQ, rid, irqe->res);
- list_del(&irqe->links);
+ lkpi_irq_release(dev, irqe);
kfree(irqe);
}
+static inline void
+devm_free_irq(struct device *xdev, unsigned int irq, void *p)
+{
+ struct device *dev;
+ struct irq_ent *irqe;
+
+ dev = linux_pci_find_irq_dev(irq);
+ if (dev == NULL)
+ return;
+ if (xdev != dev)
+ return;
+ irqe = linux_irq_ent(dev, irq);
+ if (irqe == NULL)
+ return;
+ lkpi_irq_release(dev, irqe);
+ lkpi_devres_unlink(dev, irqe);
+ lkpi_devres_free(irqe);
+ return;
+}
+
static inline int
irq_set_affinity_hint(int vector, cpumask_t *mask)
{
diff --git a/sys/compat/linuxkpi/common/src/linux_compat.c b/sys/compat/linuxkpi/common/src/linux_compat.c
--- a/sys/compat/linuxkpi/common/src/linux_compat.c
+++ b/sys/compat/linuxkpi/common/src/linux_compat.c
@@ -2463,6 +2463,30 @@
free(ar, M_KMALLOC);
}
+void
+lkpi_irq_release(struct device *dev, struct irq_ent *irqe)
+{
+
+ if (irqe->tag != NULL)
+ bus_teardown_intr(dev->bsddev, irqe->res, irqe->tag);
+ if (irqe->res != NULL)
+ bus_release_resource(dev->bsddev, SYS_RES_IRQ,
+ rman_get_rid(irqe->res), irqe->res);
+ list_del(&irqe->links);
+}
+
+void
+lkpi_devm_irq_release(struct device *dev, void *p)
+{
+ struct irq_ent *irqe;
+
+ if (dev == NULL || p == NULL)
+ return;
+
+ irqe = p;
+ lkpi_irq_release(dev, irqe);
+}
+
void
linux_irq_handler(void *ent)
{
@@ -2472,7 +2496,12 @@
return;
irqe = ent;
- irqe->handler(irqe->irq, irqe->arg);
+ if (irqe->handler(irqe->irq, irqe->arg) == IRQ_WAKE_THREAD &&
+ irqe->thread_handler != NULL) {
+ THREAD_SLEEPING_OK();
+ irqe->thread_handler(irqe->irq, irqe->arg);
+ THREAD_NO_SLEEPING();
+ }
}
#if defined(__i386__) || defined(__amd64__)
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Dec 21, 10:10 AM (5 h, 7 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
27111232
Default Alt Text
D30549.id91069.diff (5 KB)
Attached To
Mode
D30549: LinuxKPI: enhance the irq KPI for managed and threaded operations.
Attached
Detach File
Event Timeline
Log In to Comment