From c3895badf7af698d10fdd2c6d3bbb188c8346b02 Mon Sep 17 00:00:00 2001 From: John Baldwin Date: Thu, 21 Jan 2010 17:55:47 +0000 Subject: MFC 198134,198149,198170,198171,198391,200948: Add a facility for associating optional descriptions with active interrupt handlers. This is primarily intended as a way to allow devices that use multiple interrupts (e.g. MSI) to meaningfully distinguish the various interrupt handlers. - Add a new BUS_DESCRIBE_INTR() method to the bus interface to associate a description with an active interrupt handler setup by BUS_SETUP_INTR. It has a default method (bus_generic_describe_intr()) which simply passes the request up to the parent device. - Add a bus_describe_intr() wrapper around BUS_DESCRIBE_INTR() that supports printf(9) style formatting using var args. - Reserve MAXCOMLEN bytes in the intr_handler structure to hold the name of an interrupt handler and copy the name passed to intr_event_add_handler() into that buffer instead of just saving the pointer to the name. - Add a new intr_event_describe_handler() which appends a description string to an interrupt handler's name. - Implement support for interrupt descriptions on amd64, i386, and sparc64 by having the nexus(4) driver supply a custom bus_describe_intr method that invokes a new intr_describe() MD routine which in turn looks up the associated interrupt event and invokes intr_event_describe_handler(). --- sys/kern/bus_if.m | 20 +++++++++++++++++- sys/kern/kern_intr.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++-- sys/kern/subr_bus.c | 40 +++++++++++++++++++++++++++++++++++ 3 files changed, 116 insertions(+), 3 deletions(-) (limited to 'sys/kern') diff --git a/sys/kern/bus_if.m b/sys/kern/bus_if.m index 72817e72f7b8..3e23a8b915f3 100644 --- a/sys/kern/bus_if.m +++ b/sys/kern/bus_if.m @@ -509,7 +509,6 @@ METHOD int bind_intr { int _cpu; } DEFAULT bus_generic_bind_intr; - /** * @brief Allow (bus) drivers to specify the trigger mode and polarity * of the specified interrupt. @@ -526,6 +525,25 @@ METHOD int config_intr { enum intr_polarity _pol; } DEFAULT bus_generic_config_intr; +/** + * @brief Allow drivers to associate a description with an active + * interrupt handler. + * + * @param _dev the parent device of @p _child + * @param _child the device which allocated the resource + * @param _irq the resource representing the interrupt + * @param _cookie the cookie value returned when the interrupt + * was originally registered + * @param _descr the description to associate with the interrupt + */ +METHOD int describe_intr { + device_t _dev; + device_t _child; + struct resource *_irq; + void *_cookie; + const char *_descr; +} DEFAULT bus_generic_describe_intr; + /** * @brief Notify a (bus) driver about a child that the hints mechanism * believes it has discovered. diff --git a/sys/kern/kern_intr.c b/sys/kern/kern_intr.c index e2bf380ecc2d..b09fe829337c 100644 --- a/sys/kern/kern_intr.c +++ b/sys/kern/kern_intr.c @@ -506,7 +506,7 @@ intr_event_add_handler(struct intr_event *ie, const char *name, ih->ih_filter = filter; ih->ih_handler = handler; ih->ih_argument = arg; - ih->ih_name = name; + strlcpy(ih->ih_name, name, sizeof(ih->ih_name)); ih->ih_event = ie; ih->ih_pri = pri; if (flags & INTR_EXCL) @@ -579,7 +579,7 @@ intr_event_add_handler(struct intr_event *ie, const char *name, ih->ih_filter = filter; ih->ih_handler = handler; ih->ih_argument = arg; - ih->ih_name = name; + strlcpy(ih->ih_name, name, sizeof(ih->ih_name)); ih->ih_event = ie; ih->ih_pri = pri; if (flags & INTR_EXCL) @@ -646,6 +646,61 @@ intr_event_add_handler(struct intr_event *ie, const char *name, } #endif +/* + * Append a description preceded by a ':' to the name of the specified + * interrupt handler. + */ +int +intr_event_describe_handler(struct intr_event *ie, void *cookie, + const char *descr) +{ + struct intr_handler *ih; + size_t space; + char *start; + + mtx_lock(&ie->ie_lock); +#ifdef INVARIANTS + TAILQ_FOREACH(ih, &ie->ie_handlers, ih_next) { + if (ih == cookie) + break; + } + if (ih == NULL) { + mtx_unlock(&ie->ie_lock); + panic("handler %p not found in interrupt event %p", cookie, ie); + } +#endif + ih = cookie; + + /* + * Look for an existing description by checking for an + * existing ":". This assumes device names do not include + * colons. If one is found, prepare to insert the new + * description at that point. If one is not found, find the + * end of the name to use as the insertion point. + */ + start = index(ih->ih_name, ':'); + if (start == NULL) + start = index(ih->ih_name, 0); + + /* + * See if there is enough remaining room in the string for the + * description + ":". The "- 1" leaves room for the trailing + * '\0'. The "+ 1" accounts for the colon. + */ + space = sizeof(ih->ih_name) - (start - ih->ih_name) - 1; + if (strlen(descr) + 1 > space) { + mtx_unlock(&ie->ie_lock); + return (ENOSPC); + } + + /* Append a colon followed by the description. */ + *start = ':'; + strcpy(start + 1, descr); + intr_event_update(ie); + mtx_unlock(&ie->ie_lock); + return (0); +} + /* * Return the ie_source field from the intr_event an intr_handler is * associated with. diff --git a/sys/kern/subr_bus.c b/sys/kern/subr_bus.c index 127691e94af1..7bcaf92fb546 100644 --- a/sys/kern/subr_bus.c +++ b/sys/kern/subr_bus.c @@ -3263,6 +3263,24 @@ bus_generic_config_intr(device_t dev, int irq, enum intr_trigger trig, return (EINVAL); } +/** + * @brief Helper function for implementing BUS_DESCRIBE_INTR(). + * + * This simple implementation of BUS_DESCRIBE_INTR() simply calls the + * BUS_DESCRIBE_INTR() method of the parent of @p dev. + */ +int +bus_generic_describe_intr(device_t dev, device_t child, struct resource *irq, + void *cookie, const char *descr) +{ + + /* Propagate up the bus hierarchy until someone handles it. */ + if (dev->parent) + return (BUS_DESCRIBE_INTR(dev->parent, child, irq, cookie, + descr)); + return (EINVAL); +} + /** * @brief Helper function for implementing BUS_GET_DMA_TAG(). * @@ -3568,6 +3586,28 @@ bus_bind_intr(device_t dev, struct resource *r, int cpu) return (BUS_BIND_INTR(dev->parent, dev, r, cpu)); } +/** + * @brief Wrapper function for BUS_DESCRIBE_INTR(). + * + * This function first formats the requested description into a + * temporary buffer and then calls the BUS_DESCRIBE_INTR() method of + * the parent of @p dev. + */ +int +bus_describe_intr(device_t dev, struct resource *irq, void *cookie, + const char *fmt, ...) +{ + char descr[MAXCOMLEN]; + va_list ap; + + if (dev->parent == NULL) + return (EINVAL); + va_start(ap, fmt); + vsnprintf(descr, sizeof(descr), fmt, ap); + va_end(ap); + return (BUS_DESCRIBE_INTR(dev->parent, dev, irq, cookie, descr)); +} + /** * @brief Wrapper function for BUS_SET_RESOURCE(). * -- cgit v1.3