diff options
author | jhb <jhb@FreeBSD.org> | 2009-10-15 14:54:35 +0000 |
---|---|---|
committer | jhb <jhb@FreeBSD.org> | 2009-10-15 14:54:35 +0000 |
commit | 45688ed39df1a016dde3d3f3cb4f19e562a683c2 (patch) | |
tree | 822343884edf055be1b27eb1097d39bdd975cf43 /sys | |
parent | c369f72e79562af70cc2ac640a8099842519403d (diff) | |
download | FreeBSD-src-45688ed39df1a016dde3d3f3cb4f19e562a683c2.zip FreeBSD-src-45688ed39df1a016dde3d3f3cb4f19e562a683c2.tar.gz |
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 and i386 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().
Requested by: many
Reviewed by: scottl
MFC after: 2 weeks
Diffstat (limited to 'sys')
-rw-r--r-- | sys/amd64/amd64/intr_machdep.c | 17 | ||||
-rw-r--r-- | sys/amd64/amd64/nexus.c | 12 | ||||
-rw-r--r-- | sys/amd64/include/intr_machdep.h | 1 | ||||
-rw-r--r-- | sys/i386/i386/intr_machdep.c | 17 | ||||
-rw-r--r-- | sys/i386/i386/nexus.c | 12 | ||||
-rw-r--r-- | sys/i386/include/intr_machdep.h | 1 | ||||
-rw-r--r-- | sys/kern/bus_if.m | 20 | ||||
-rw-r--r-- | sys/kern/kern_intr.c | 59 | ||||
-rw-r--r-- | sys/kern/subr_bus.c | 40 | ||||
-rw-r--r-- | sys/sys/bus.h | 5 | ||||
-rw-r--r-- | sys/sys/interrupt.h | 4 |
11 files changed, 184 insertions, 4 deletions
diff --git a/sys/amd64/amd64/intr_machdep.c b/sys/amd64/amd64/intr_machdep.c index 212ac0d..e72e13a 100644 --- a/sys/amd64/amd64/intr_machdep.c +++ b/sys/amd64/amd64/intr_machdep.c @@ -466,6 +466,23 @@ intr_bind(u_int vector, u_char cpu) return (intr_event_bind(isrc->is_event, cpu)); } +/* Add a description to an active interrupt handler. */ +int +intr_describe(u_int vector, void *ih, const char *descr) +{ + struct intsrc *isrc; + int error; + + isrc = intr_lookup_source(vector); + if (isrc == NULL) + return (EINVAL); + error = intr_event_describe_handler(isrc->is_event, ih, descr); + if (error) + return (error); + intrcnt_updatename(isrc); + return (0); +} + /* * Add a CPU to our mask of valid CPUs that can be destinations of * interrupts. diff --git a/sys/amd64/amd64/nexus.c b/sys/amd64/amd64/nexus.c index 5eafd3b..61cb587 100644 --- a/sys/amd64/amd64/nexus.c +++ b/sys/amd64/amd64/nexus.c @@ -92,6 +92,9 @@ static int nexus_bind_intr(device_t, device_t, struct resource *, int); #endif static int nexus_config_intr(device_t, int, enum intr_trigger, enum intr_polarity); +static int nexus_describe_intr(device_t dev, device_t child, + struct resource *irq, void *cookie, + const char *descr); static int nexus_activate_resource(device_t, device_t, int, int, struct resource *); static int nexus_deactivate_resource(device_t, device_t, int, int, @@ -135,6 +138,7 @@ static device_method_t nexus_methods[] = { DEVMETHOD(bus_bind_intr, nexus_bind_intr), #endif DEVMETHOD(bus_config_intr, nexus_config_intr), + DEVMETHOD(bus_describe_intr, nexus_describe_intr), DEVMETHOD(bus_get_resource_list, nexus_get_reslist), DEVMETHOD(bus_set_resource, nexus_set_resource), DEVMETHOD(bus_get_resource, nexus_get_resource), @@ -479,6 +483,14 @@ nexus_config_intr(device_t dev, int irq, enum intr_trigger trig, return (intr_config_intr(irq, trig, pol)); } +static int +nexus_describe_intr(device_t dev, device_t child, struct resource *irq, + void *cookie, const char *descr) +{ + + return (intr_describe(rman_get_start(irq), cookie, descr)); +} + static struct resource_list * nexus_get_reslist(device_t dev, device_t child) { diff --git a/sys/amd64/include/intr_machdep.h b/sys/amd64/include/intr_machdep.h index 634db19..6cd4eee 100644 --- a/sys/amd64/include/intr_machdep.h +++ b/sys/amd64/include/intr_machdep.h @@ -151,6 +151,7 @@ int intr_bind(u_int vector, u_char cpu); #endif int intr_config_intr(int vector, enum intr_trigger trig, enum intr_polarity pol); +int intr_describe(u_int vector, void *ih, const char *descr); void intr_execute_handlers(struct intsrc *isrc, struct trapframe *frame); u_int intr_next_cpu(void); struct intsrc *intr_lookup_source(int vector); diff --git a/sys/i386/i386/intr_machdep.c b/sys/i386/i386/intr_machdep.c index 3d1b0c4..5a74a9d 100644 --- a/sys/i386/i386/intr_machdep.c +++ b/sys/i386/i386/intr_machdep.c @@ -432,6 +432,23 @@ intr_bind(u_int vector, u_char cpu) return (intr_event_bind(isrc->is_event, cpu)); } +/* Add a description to an active interrupt handler. */ +int +intr_describe(u_int vector, void *ih, const char *descr) +{ + struct intsrc *isrc; + int error; + + isrc = intr_lookup_source(vector); + if (isrc == NULL) + return (EINVAL); + error = intr_event_describe_handler(isrc->is_event, ih, descr); + if (error) + return (error); + intrcnt_updatename(isrc); + return (0); +} + /* * Add a CPU to our mask of valid CPUs that can be destinations of * interrupts. diff --git a/sys/i386/i386/nexus.c b/sys/i386/i386/nexus.c index 98adc93..8eacc6a 100644 --- a/sys/i386/i386/nexus.c +++ b/sys/i386/i386/nexus.c @@ -96,6 +96,9 @@ static int nexus_bind_intr(device_t, device_t, struct resource *, int); #endif static int nexus_config_intr(device_t, int, enum intr_trigger, enum intr_polarity); +static int nexus_describe_intr(device_t dev, device_t child, + struct resource *irq, void *cookie, + const char *descr); static int nexus_activate_resource(device_t, device_t, int, int, struct resource *); static int nexus_deactivate_resource(device_t, device_t, int, int, @@ -141,6 +144,7 @@ static device_method_t nexus_methods[] = { DEVMETHOD(bus_bind_intr, nexus_bind_intr), #endif DEVMETHOD(bus_config_intr, nexus_config_intr), + DEVMETHOD(bus_describe_intr, nexus_describe_intr), DEVMETHOD(bus_get_resource_list, nexus_get_reslist), DEVMETHOD(bus_set_resource, nexus_set_resource), DEVMETHOD(bus_get_resource, nexus_get_resource), @@ -526,6 +530,14 @@ nexus_config_intr(device_t dev, int irq, enum intr_trigger trig, return (intr_config_intr(irq, trig, pol)); } +static int +nexus_describe_intr(device_t dev, device_t child, struct resource *irq, + void *cookie, const char *descr) +{ + + return (intr_describe(rman_get_start(irq), cookie, descr)); +} + static struct resource_list * nexus_get_reslist(device_t dev, device_t child) { diff --git a/sys/i386/include/intr_machdep.h b/sys/i386/include/intr_machdep.h index f21e0bcf..bcff6c2 100644 --- a/sys/i386/include/intr_machdep.h +++ b/sys/i386/include/intr_machdep.h @@ -138,6 +138,7 @@ int intr_bind(u_int vector, u_char cpu); #endif int intr_config_intr(int vector, enum intr_trigger trig, enum intr_polarity pol); +int intr_describe(u_int vector, void *ih, const char *descr); void intr_execute_handlers(struct intsrc *isrc, struct trapframe *frame); u_int intr_next_cpu(void); struct intsrc *intr_lookup_source(int vector); diff --git a/sys/kern/bus_if.m b/sys/kern/bus_if.m index c1c0e34..c0924c8 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. @@ -527,6 +526,25 @@ METHOD int config_intr { } 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 3eb2c6c..42d5f16 100644 --- a/sys/kern/kern_intr.c +++ b/sys/kern/kern_intr.c @@ -524,7 +524,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) @@ -597,7 +597,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) @@ -665,6 +665,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 find 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 3f51c5c..e4d1f9b 100644 --- a/sys/kern/subr_bus.c +++ b/sys/kern/subr_bus.c @@ -3520,6 +3520,24 @@ bus_generic_config_intr(device_t dev, int irq, enum intr_trigger trig, } /** + * @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(). * * This simple implementation of BUS_GET_DMA_TAG() simply calls the @@ -3824,6 +3842,28 @@ bus_bind_intr(device_t dev, struct resource *r, int 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(). * * This function simply calls the BUS_SET_RESOURCE() method of the diff --git a/sys/sys/bus.h b/sys/sys/bus.h index 794dc47..454f510 100644 --- a/sys/sys/bus.h +++ b/sys/sys/bus.h @@ -292,6 +292,9 @@ int bus_generic_bind_intr(device_t dev, device_t child, int bus_generic_child_present(device_t dev, device_t child); int bus_generic_config_intr(device_t, int, enum intr_trigger, enum intr_polarity); +int bus_generic_describe_intr(device_t dev, device_t child, + struct resource *irq, void *cookie, + const char *descr); int bus_generic_deactivate_resource(device_t dev, device_t child, int type, int rid, struct resource *r); int bus_generic_detach(device_t dev); @@ -363,6 +366,8 @@ int bus_setup_intr(device_t dev, struct resource *r, int flags, void *arg, void **cookiep); int bus_teardown_intr(device_t dev, struct resource *r, void *cookie); int bus_bind_intr(device_t dev, struct resource *r, int cpu); +int bus_describe_intr(device_t dev, struct resource *irq, void *cookie, + const char *fmt, ...); int bus_set_resource(device_t dev, int type, int rid, u_long start, u_long count); int bus_get_resource(device_t dev, int type, int rid, diff --git a/sys/sys/interrupt.h b/sys/sys/interrupt.h index 92c0f03..18f73d9 100644 --- a/sys/sys/interrupt.h +++ b/sys/sys/interrupt.h @@ -47,7 +47,7 @@ struct intr_handler { driver_intr_t *ih_handler; /* Threaded handler function. */ void *ih_argument; /* Argument to pass to handlers. */ int ih_flags; - const char *ih_name; /* Name of handler. */ + char ih_name[MAXCOMLEN]; /* Name of handler. */ struct intr_event *ih_event; /* Event we are connected to. */ int ih_need; /* Needs service. */ TAILQ_ENTRY(intr_handler) ih_next; /* Next handler for this event. */ @@ -172,6 +172,8 @@ int intr_event_destroy(struct intr_event *ie); void intr_event_execute_handlers(struct proc *p, struct intr_event *ie); int intr_event_handle(struct intr_event *ie, struct trapframe *frame); int intr_event_remove_handler(void *cookie); +int intr_event_describe_handler(struct intr_event *ie, void *cookie, + const char *descr); int intr_getaffinity(int irq, void *mask); void *intr_handler_source(void *cookie); int intr_setaffinity(int irq, void *mask); |