Date: Sun, 18 Jul 2021 00:36:51 GMT From: "Bjoern A. Zeeb" <bz@FreeBSD.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org Subject: git: 1eaaada457d6 - stable/13 - LinuxKPI: enhance the irq KPI for managed and threaded operations. Message-ID: <202107180036.16I0apIi049660@gitrepo.freebsd.org>
next in thread | raw e-mail | index | archive | help
The branch stable/13 has been updated by bz: URL: https://cgit.FreeBSD.org/src/commit/?id=1eaaada457d6c559188c7abb5c8fc1fa372ec231 commit 1eaaada457d6c559188c7abb5c8fc1fa372ec231 Author: Bjoern A. Zeeb <bz@FreeBSD.org> AuthorDate: 2021-05-30 13:54:13 +0000 Commit: Bjoern A. Zeeb <bz@FreeBSD.org> CommitDate: 2021-07-18 00:35:03 +0000 LinuxKPI: enhance the irq KPI for managed and threaded operations. Move request_irq() to an internal function which serves request_irq() and the newly added request_threaded_irq() and devm_request_threaded_irq(). Likewise factor out parts of free_irq() to also be used with devm_free_irq(). Add the storage and call to a thread_handler in case of IRQ_WAKE_THREAD. This is needed for the iwlwifi driver. Sponsored by: The FreeBSD Foundation Reviewed by: hselasky Differential Revision: https://reviews.freebsd.org/D30549 (cherry picked from commit d16b6cb17837162d685c960deb28f26f716fa440) --- .../linuxkpi/common/include/linux/interrupt.h | 97 ++++++++++++++++++---- sys/compat/linuxkpi/common/src/linux_compat.c | 31 ++++++- 2 files changed, 110 insertions(+), 18 deletions(-) diff --git a/sys/compat/linuxkpi/common/include/linux/interrupt.h b/sys/compat/linuxkpi/common/include/linux/interrupt.h index 90994a2f2315..6770adad2293 100644 --- 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 irq_ent { 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 @@ linux_irq_rid(struct device *dev, unsigned int irq) 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 @@ linux_irq_ent(struct device *dev, unsigned int irq) } 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 @@ request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, 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 @@ bind_irq_to_cpu(unsigned int irq, int cpu_id) } 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 index d4571173f93d..217c4081c603 100644 --- a/sys/compat/linuxkpi/common/src/linux_compat.c +++ b/sys/compat/linuxkpi/common/src/linux_compat.c @@ -2463,6 +2463,30 @@ list_sort(void *priv, struct list_head *head, int (*cmp)(void *priv, 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 @@ linux_irq_handler(void *ent) 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__)
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202107180036.16I0apIi049660>