Date: Fri, 3 Jun 2016 10:13:18 +0000 (UTC) From: Andrew Turner <andrew@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r301263 - in head/sys: kern sys Message-ID: <201606031013.u53ADIbC054635@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: andrew Date: Fri Jun 3 10:13:18 2016 New Revision: 301263 URL: https://svnweb.freebsd.org/changeset/base/301263 Log: Add an interface to handle interrupt controllers that have a contiguous range of interrupts they pass to a second controller driver to handle. The parent driver is expected to detect when one of these interrupts has been triggered and call intr_child_irq_handler to pass the interrupt to a child. The children controllers are then expected to manage the range by allocating interrupts as needed. This will initially be used by the ARM GICv3 driver, but is is expected to be useful for other driver where this type of allocation applies. Obtained from: ABT Systems Ltd Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D6436 Modified: head/sys/kern/subr_intr.c head/sys/sys/intr.h Modified: head/sys/kern/subr_intr.c ============================================================================== --- head/sys/kern/subr_intr.c Fri Jun 3 09:17:22 2016 (r301262) +++ head/sys/kern/subr_intr.c Fri Jun 3 10:13:18 2016 (r301263) @@ -98,6 +98,15 @@ static intr_irq_filter_t *irq_root_filte static void *irq_root_arg; static u_int irq_root_ipicount; +struct intr_pic_child { + SLIST_ENTRY(intr_pic_child) pc_next; + struct intr_pic *pc_pic; + intr_child_irq_filter_t *pc_filter; + void *pc_filter_arg; + uintptr_t pc_start; + uintptr_t pc_length; +}; + /* Interrupt controller definition. */ struct intr_pic { SLIST_ENTRY(intr_pic) pic_next; @@ -106,6 +115,8 @@ struct intr_pic { #define FLAG_PIC (1 << 0) #define FLAG_MSI (1 << 1) u_int pic_flags; + struct mtx pic_child_lock; + SLIST_HEAD(, intr_pic_child) pic_children; }; static struct mtx pic_list_lock; @@ -323,6 +334,29 @@ intr_irq_handler(struct trapframe *tf) #endif } +int +intr_child_irq_handler(struct intr_pic *parent, uintptr_t irq) +{ + struct intr_pic_child *child; + bool found; + + found = false; + mtx_lock_spin(&parent->pic_child_lock); + SLIST_FOREACH(child, &parent->pic_children, pc_next) { + if (child->pc_start <= irq && + irq < (child->pc_start + child->pc_length)) { + found = true; + break; + } + } + mtx_unlock_spin(&parent->pic_child_lock); + + if (found) + return (child->pc_filter(child->pc_filter_arg, irq)); + + return (FILTER_STRAY); +} + /* * interrupt controller dispatch function for interrupts. It should * be called straight from the interrupt controller, when associated interrupt @@ -892,6 +926,7 @@ pic_create(device_t dev, intptr_t xref) } pic->pic_xref = xref; pic->pic_dev = dev; + mtx_init(&pic->pic_child_lock, "pic child lock", NULL, MTX_SPIN); SLIST_INSERT_HEAD(&pic_list, pic, pic_next); mtx_unlock(&pic_list_lock); @@ -1001,6 +1036,44 @@ intr_pic_claim_root(device_t dev, intptr return (0); } +/* + * Add a handler to manage a sub range of a parents interrupts. + */ +struct intr_pic * +intr_pic_add_handler(device_t parent, struct intr_pic *pic, + intr_child_irq_filter_t *filter, void *arg, uintptr_t start, + uintptr_t length) +{ + struct intr_pic *parent_pic; + struct intr_pic_child *newchild; +#ifdef INVARIANTS + struct intr_pic_child *child; +#endif + + parent_pic = pic_lookup(parent, 0); + if (parent_pic == NULL) + return (NULL); + + newchild = malloc(sizeof(*newchild), M_INTRNG, M_WAITOK | M_ZERO); + newchild->pc_pic = pic; + newchild->pc_filter = filter; + newchild->pc_filter_arg = arg; + newchild->pc_start = start; + newchild->pc_length = length; + + mtx_lock_spin(&parent_pic->pic_child_lock); +#ifdef INVARIANTS + SLIST_FOREACH(child, &parent_pic->pic_children, pc_next) { + KASSERT(child->pc_pic != pic, ("%s: Adding a child PIC twice", + __func__)); + } +#endif + SLIST_INSERT_HEAD(&parent_pic->pic_children, newchild, pc_next); + mtx_unlock_spin(&parent_pic->pic_child_lock); + + return (pic); +} + int intr_map_irq(device_t dev, intptr_t xref, struct intr_map_data *data, u_int *irqp) Modified: head/sys/sys/intr.h ============================================================================== --- head/sys/sys/intr.h Fri Jun 3 09:17:22 2016 (r301262) +++ head/sys/sys/intr.h Fri Jun 3 10:13:18 2016 (r301263) @@ -74,6 +74,7 @@ typedef int intr_irq_filter_t(void *arg, #else typedef int intr_irq_filter_t(void *arg); #endif +typedef int intr_child_irq_filter_t(void *arg, uintptr_t irq); #define INTR_ISRC_NAMELEN (MAXCOMLEN + 1) @@ -81,6 +82,8 @@ typedef int intr_irq_filter_t(void *arg) #define INTR_ISRCF_PPI 0x02 /* PPI interrupt */ #define INTR_ISRCF_BOUND 0x04 /* bound to a CPU */ +struct intr_pic; + /* Interrupt source definition. */ struct intr_irqsrc { device_t isrc_dev; /* where isrc is mapped */ @@ -113,6 +116,8 @@ u_int intr_irq_next_cpu(u_int current_cp struct intr_pic *intr_pic_register(device_t, intptr_t); int intr_pic_deregister(device_t, intptr_t); int intr_pic_claim_root(device_t, intptr_t, intr_irq_filter_t *, void *, u_int); +struct intr_pic *intr_pic_add_handler(device_t, struct intr_pic *, + intr_child_irq_filter_t *, void *, uintptr_t, uintptr_t); extern device_t intr_irq_root_dev; @@ -127,6 +132,7 @@ int intr_setup_irq(device_t, struct reso int intr_teardown_irq(device_t, struct resource *, void *); int intr_describe_irq(device_t, struct resource *, void *, const char *); +int intr_child_irq_handler(struct intr_pic *, uintptr_t); /* MSI/MSI-X handling */ int intr_msi_register(device_t, intptr_t);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201606031013.u53ADIbC054635>