Module Name: src Committed By: knakahara Date: Mon Aug 17 06:16:03 UTC 2015
Modified Files: src/sys/arch/x86/include: intr.h intr_distribute.h pci_machdep_common.h src/sys/arch/x86/pci: pci_intr_machdep.c pci_msi_machdep.c pci_msi_machdep.h src/sys/arch/x86/x86: intr.c src/sys/conf: files src/sys/dev/pci: if_wm.c pci_stub.c pcivar.h src/sys/dev/pci/ixgbe: ixgbe.c ixgbe.h ixv.c ixv.h src/sys/kern: files.kern kern_stub.c src/sys/secmodel/suser: secmodel_suser.c src/sys/sys: Makefile intr.h kauth.h Added Files: src/sys/kern: subr_interrupt.c src/sys/sys: interrupt.h intrio.h Log Message: Add kernel code to support intrctl(8). To generate a diff of this commit: cvs rdiff -u -r1.47 -r1.48 src/sys/arch/x86/include/intr.h cvs rdiff -u -r1.1 -r1.2 src/sys/arch/x86/include/intr_distribute.h cvs rdiff -u -r1.20 -r1.21 src/sys/arch/x86/include/pci_machdep_common.h cvs rdiff -u -r1.36 -r1.37 src/sys/arch/x86/pci/pci_intr_machdep.c cvs rdiff -u -r1.8 -r1.9 src/sys/arch/x86/pci/pci_msi_machdep.c cvs rdiff -u -r1.2 -r1.3 src/sys/arch/x86/pci/pci_msi_machdep.h cvs rdiff -u -r1.86 -r1.87 src/sys/arch/x86/x86/intr.c cvs rdiff -u -r1.1130 -r1.1131 src/sys/conf/files cvs rdiff -u -r1.345 -r1.346 src/sys/dev/pci/if_wm.c cvs rdiff -u -r1.1 -r1.2 src/sys/dev/pci/pci_stub.c cvs rdiff -u -r1.103 -r1.104 src/sys/dev/pci/pcivar.h cvs rdiff -u -r1.35 -r1.36 src/sys/dev/pci/ixgbe/ixgbe.c cvs rdiff -u -r1.8 -r1.9 src/sys/dev/pci/ixgbe/ixgbe.h cvs rdiff -u -r1.14 -r1.15 src/sys/dev/pci/ixgbe/ixv.c cvs rdiff -u -r1.6 -r1.7 src/sys/dev/pci/ixgbe/ixv.h cvs rdiff -u -r1.6 -r1.7 src/sys/kern/files.kern cvs rdiff -u -r1.39 -r1.40 src/sys/kern/kern_stub.c cvs rdiff -u -r0 -r1.1 src/sys/kern/subr_interrupt.c cvs rdiff -u -r1.41 -r1.42 src/sys/secmodel/suser/secmodel_suser.c cvs rdiff -u -r1.156 -r1.157 src/sys/sys/Makefile cvs rdiff -u -r0 -r1.1 src/sys/sys/interrupt.h src/sys/sys/intrio.h cvs rdiff -u -r1.18 -r1.19 src/sys/sys/intr.h cvs rdiff -u -r1.71 -r1.72 src/sys/sys/kauth.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/arch/x86/include/intr.h diff -u src/sys/arch/x86/include/intr.h:1.47 src/sys/arch/x86/include/intr.h:1.48 --- src/sys/arch/x86/include/intr.h:1.47 Mon Apr 27 06:51:40 2015 +++ src/sys/arch/x86/include/intr.h Mon Aug 17 06:16:02 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: intr.h,v 1.47 2015/04/27 06:51:40 knakahara Exp $ */ +/* $NetBSD: intr.h,v 1.48 2015/08/17 06:16:02 knakahara Exp $ */ /*- * Copyright (c) 1998, 2001, 2006, 2007, 2008 The NetBSD Foundation, Inc. @@ -86,13 +86,14 @@ struct intrsource { void *is_recurse; /* entry for spllower */ void *is_resume; /* entry for doreti */ lwp_t *is_lwp; /* for soft interrupts */ - struct evcnt is_evcnt; /* interrupt counter */ + struct evcnt is_evcnt; /* interrupt counter per cpu */ int is_flags; /* see below */ int is_type; /* level, edge */ int is_idtvec; int is_minlevel; char is_evname[32]; /* event counter name */ char is_intrid[INTRIDBUF]; /* intrid created by create_intrid() */ + char is_xname[INTRDEVNAMEBUF]; /* device names */ cpuid_t is_active_cpu; /* active cpuid */ struct percpu_evcnt *is_saved_evcnt; /* interrupt count of deactivated cpus */ SIMPLEQ_ENTRY(intrsource) is_list; /* link of intrsources */ @@ -185,6 +186,8 @@ typedef uint64_t intr_handle_t; void intr_default_setup(void); void x86_nmi(void); +void *intr_establish_xname(int, struct pic *, int, int, int, int (*)(void *), + void *, bool, const char *); void *intr_establish(int, struct pic *, int, int, int, int (*)(void *), void *, bool); void intr_disestablish(struct intrhand *); void intr_add_pcibus(struct pcibus_attach_args *); Index: src/sys/arch/x86/include/intr_distribute.h diff -u src/sys/arch/x86/include/intr_distribute.h:1.1 src/sys/arch/x86/include/intr_distribute.h:1.2 --- src/sys/arch/x86/include/intr_distribute.h:1.1 Mon Apr 27 06:42:52 2015 +++ src/sys/arch/x86/include/intr_distribute.h Mon Aug 17 06:16:02 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: intr_distribute.h,v 1.1 2015/04/27 06:42:52 knakahara Exp $ */ +/* $NetBSD: intr_distribute.h,v 1.2 2015/08/17 06:16:02 knakahara Exp $ */ /* * Copyright (c) 2015 Internet Initiative Japan Inc. @@ -34,6 +34,7 @@ #include <sys/kcpuset.h> int intr_distribute(struct intrhand *, const kcpuset_t *, kcpuset_t *); +int intr_distribute_handler(const char *, const kcpuset_t *, kcpuset_t *); #endif /* _KERNEL */ Index: src/sys/arch/x86/include/pci_machdep_common.h diff -u src/sys/arch/x86/include/pci_machdep_common.h:1.20 src/sys/arch/x86/include/pci_machdep_common.h:1.21 --- src/sys/arch/x86/include/pci_machdep_common.h:1.20 Thu Aug 13 04:39:33 2015 +++ src/sys/arch/x86/include/pci_machdep_common.h Mon Aug 17 06:16:02 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: pci_machdep_common.h,v 1.20 2015/08/13 04:39:33 msaitoh Exp $ */ +/* $NetBSD: pci_machdep_common.h,v 1.21 2015/08/17 06:16:02 knakahara Exp $ */ /* * Copyright (c) 1996 Christopher G. Demetriou. All rights reserved. @@ -118,7 +118,6 @@ const struct evcnt *pci_intr_evcnt(pci_c void *pci_intr_establish(pci_chipset_tag_t, pci_intr_handle_t, int, int (*)(void *), void *); void pci_intr_disestablish(pci_chipset_tag_t, void *); -int pci_intr_distribute(void *, const kcpuset_t *, kcpuset_t *); typedef enum { PCI_INTR_TYPE_INTX = 0, Index: src/sys/arch/x86/pci/pci_intr_machdep.c diff -u src/sys/arch/x86/pci/pci_intr_machdep.c:1.36 src/sys/arch/x86/pci/pci_intr_machdep.c:1.37 --- src/sys/arch/x86/pci/pci_intr_machdep.c:1.36 Thu Aug 13 04:39:33 2015 +++ src/sys/arch/x86/pci/pci_intr_machdep.c Mon Aug 17 06:16:03 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: pci_intr_machdep.c,v 1.36 2015/08/13 04:39:33 msaitoh Exp $ */ +/* $NetBSD: pci_intr_machdep.c,v 1.37 2015/08/17 06:16:03 knakahara Exp $ */ /*- * Copyright (c) 1997, 1998, 2009 The NetBSD Foundation, Inc. @@ -73,7 +73,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: pci_intr_machdep.c,v 1.36 2015/08/13 04:39:33 msaitoh Exp $"); +__KERNEL_RCSID(0, "$NetBSD: pci_intr_machdep.c,v 1.37 2015/08/17 06:16:03 knakahara Exp $"); #include <sys/types.h> #include <sys/param.h> @@ -275,8 +275,8 @@ pci_intr_setattr(pci_chipset_tag_t pc, p } void * -pci_intr_establish(pci_chipset_tag_t pc, pci_intr_handle_t ih, - int level, int (*func)(void *), void *arg) +pci_intr_establish_xname(pci_chipset_tag_t pc, pci_intr_handle_t ih, + int level, int (*func)(void *), void *arg, const char *xname) { int pin, irq; struct pic *pic; @@ -295,9 +295,11 @@ pci_intr_establish(pci_chipset_tag_t pc, if (INT_VIA_MSI(ih)) { if (MSI_INT_IS_MSIX(ih)) - return x86_pci_msix_establish(pc, ih, level, func, arg); + return x86_pci_msix_establish(pc, ih, level, func, arg, + xname); else - return x86_pci_msi_establish(pc, ih, level, func, arg); + return x86_pci_msi_establish(pc, ih, level, func, arg, + xname); } pic = &i8259_pic; @@ -320,8 +322,16 @@ pci_intr_establish(pci_chipset_tag_t pc, } #endif - return intr_establish(irq, pic, pin, IST_LEVEL, level, func, arg, - mpsafe); + return intr_establish_xname(irq, pic, pin, IST_LEVEL, level, func, arg, + mpsafe, xname); +} + +void * +pci_intr_establish(pci_chipset_tag_t pc, pci_intr_handle_t ih, + int level, int (*func)(void *), void *arg) +{ + + return pci_intr_establish_xname(pc, ih, level, func, arg, "unknown"); } void @@ -340,15 +350,6 @@ pci_intr_disestablish(pci_chipset_tag_t intr_disestablish(cookie); } -int -pci_intr_distribute(void *cookie, const kcpuset_t *newset, kcpuset_t *oldset) -{ - - /* XXX Is pc_ov->ov_intr_distribute required? */ - - return intr_distribute(cookie, newset, oldset); -} - #if NIOAPIC > 0 pci_intr_type_t pci_intr_type(pci_intr_handle_t ih) Index: src/sys/arch/x86/pci/pci_msi_machdep.c diff -u src/sys/arch/x86/pci/pci_msi_machdep.c:1.8 src/sys/arch/x86/pci/pci_msi_machdep.c:1.9 --- src/sys/arch/x86/pci/pci_msi_machdep.c:1.8 Thu Aug 13 04:39:33 2015 +++ src/sys/arch/x86/pci/pci_msi_machdep.c Mon Aug 17 06:16:03 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: pci_msi_machdep.c,v 1.8 2015/08/13 04:39:33 msaitoh Exp $ */ +/* $NetBSD: pci_msi_machdep.c,v 1.9 2015/08/17 06:16:03 knakahara Exp $ */ /* * Copyright (c) 2015 Internet Initiative Japan Inc. @@ -34,7 +34,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: pci_msi_machdep.c,v 1.8 2015/08/13 04:39:33 msaitoh Exp $"); +__KERNEL_RCSID(0, "$NetBSD: pci_msi_machdep.c,v 1.9 2015/08/17 06:16:03 knakahara Exp $"); #include "opt_intrdebug.h" @@ -208,7 +208,8 @@ pci_msi_alloc_common(pci_intr_handle_t * static void * pci_msi_common_establish(pci_chipset_tag_t pc, pci_intr_handle_t ih, - int level, int (*func)(void *), void *arg, struct pic *pic) + int level, int (*func)(void *), void *arg, struct pic *pic, + const char *xname) { int irq, pin; bool mpsafe; @@ -219,8 +220,8 @@ pci_msi_common_establish(pci_chipset_tag pin = MSI_INT_VEC(ih); mpsafe = ((ih & MPSAFE_MASK) != 0); - return intr_establish(irq, pic, pin, IST_EDGE, level, func, arg, - mpsafe); + return intr_establish_xname(irq, pic, pin, IST_EDGE, level, func, arg, + mpsafe, xname); } static void @@ -396,7 +397,7 @@ x86_pci_msi_release(pci_chipset_tag_t pc */ void * x86_pci_msi_establish(pci_chipset_tag_t pc, pci_intr_handle_t ih, - int level, int (*func)(void *), void *arg) + int level, int (*func)(void *), void *arg, const char *xname) { struct pic *pic; @@ -406,7 +407,7 @@ x86_pci_msi_establish(pci_chipset_tag_t return NULL; } - return pci_msi_common_establish(pc, ih, level, func, arg, pic); + return pci_msi_common_establish(pc, ih, level, func, arg, pic, xname); } /* @@ -441,7 +442,7 @@ x86_pci_msix_release(pci_chipset_tag_t p */ void * x86_pci_msix_establish(pci_chipset_tag_t pc, pci_intr_handle_t ih, - int level, int (*func)(void *), void *arg) + int level, int (*func)(void *), void *arg, const char *xname) { struct pic *pic; @@ -451,7 +452,7 @@ x86_pci_msix_establish(pci_chipset_tag_t return NULL; } - return pci_msi_common_establish(pc, ih, level, func, arg, pic); + return pci_msi_common_establish(pc, ih, level, func, arg, pic, xname); } /* Index: src/sys/arch/x86/pci/pci_msi_machdep.h diff -u src/sys/arch/x86/pci/pci_msi_machdep.h:1.2 src/sys/arch/x86/pci/pci_msi_machdep.h:1.3 --- src/sys/arch/x86/pci/pci_msi_machdep.h:1.2 Fri May 15 08:36:41 2015 +++ src/sys/arch/x86/pci/pci_msi_machdep.h Mon Aug 17 06:16:03 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: pci_msi_machdep.h,v 1.2 2015/05/15 08:36:41 knakahara Exp $ */ +/* $NetBSD: pci_msi_machdep.h,v 1.3 2015/08/17 06:16:03 knakahara Exp $ */ /* * Copyright (c) 2015 Internet Initiative Japan Inc. @@ -34,13 +34,13 @@ const char *x86_pci_msi_string(pci_chips void x86_pci_msi_release(pci_chipset_tag_t, pci_intr_handle_t *, int); void *x86_pci_msi_establish(pci_chipset_tag_t, pci_intr_handle_t, - int, int (*)(void *), void *); + int, int (*)(void *), void *, const char *); void x86_pci_msi_disestablish(pci_chipset_tag_t, void *); void x86_pci_msix_release(pci_chipset_tag_t, pci_intr_handle_t *, int); void *x86_pci_msix_establish(pci_chipset_tag_t, pci_intr_handle_t, - int, int (*)(void *), void *); + int, int (*)(void *), void *, const char *xname); void x86_pci_msix_disestablish(pci_chipset_tag_t, void *); #endif /* _X86_PCI_PCI_MSI_MACHDEP_H_ */ Index: src/sys/arch/x86/x86/intr.c diff -u src/sys/arch/x86/x86/intr.c:1.86 src/sys/arch/x86/x86/intr.c:1.87 --- src/sys/arch/x86/x86/intr.c:1.86 Tue Jun 23 10:00:13 2015 +++ src/sys/arch/x86/x86/intr.c Mon Aug 17 06:16:03 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: intr.c,v 1.86 2015/06/23 10:00:13 msaitoh Exp $ */ +/* $NetBSD: intr.c,v 1.87 2015/08/17 06:16:03 knakahara Exp $ */ /*- * Copyright (c) 2007, 2008, 2009 The NetBSD Foundation, Inc. @@ -133,7 +133,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: intr.c,v 1.86 2015/06/23 10:00:13 msaitoh Exp $"); +__KERNEL_RCSID(0, "$NetBSD: intr.c,v 1.87 2015/08/17 06:16:03 knakahara Exp $"); #include "opt_intrdebug.h" #include "opt_multiprocessor.h" @@ -151,6 +151,10 @@ __KERNEL_RCSID(0, "$NetBSD: intr.c,v 1.8 #include <sys/cpu.h> #include <sys/atomic.h> #include <sys/xcall.h> +#include <sys/interrupt.h> + +#include <sys/kauth.h> +#include <sys/conf.h> #include <uvm/uvm_extern.h> @@ -224,6 +228,8 @@ static void intr_source_free(struct cpu_ static void intr_establish_xcall(void *, void *); static void intr_disestablish_xcall(void *, void *); +static const char *legacy_intr_string(int, char *, size_t, struct pic *); + static inline bool redzone_const_or_false(bool); static inline int redzone_const_or_zero(int); @@ -829,6 +835,19 @@ intr_findpic(int num) } /* + * Append device name to intrsource. If device A and device B share IRQ number, + * the device name of the interrupt id is "device A, device B". + */ +static void +intr_append_intrsource_xname(struct intrsource *isp, const char *xname) +{ + + if (isp->is_xname[0] != '\0') + strlcat(isp->is_xname, ", ", sizeof(isp->is_xname)); + strlcat(isp->is_xname, xname, sizeof(isp->is_xname)); +} + +/* * Handle per-CPU component of interrupt establish. * * => caller (on initiating CPU) holds cpu_lock on our behalf @@ -882,8 +901,9 @@ intr_establish_xcall(void *arg1, void *a } void * -intr_establish(int legacy_irq, struct pic *pic, int pin, int type, int level, - int (*handler)(void *), void *arg, bool known_mpsafe) +intr_establish_xname(int legacy_irq, struct pic *pic, int pin, int type, + int level, int (*handler)(void *), void *arg, + bool known_mpsafe, const char *xname) { struct intrhand **p, *q, *ih; struct cpu_info *ci; @@ -958,7 +978,7 @@ intr_establish(int legacy_irq, struct pi source->is_pin = pin; source->is_pic = pic; - + intr_append_intrsource_xname(source, xname); switch (source->is_type) { case IST_NONE: source->is_type = type; @@ -1047,6 +1067,15 @@ intr_establish(int legacy_irq, struct pi return (ih); } +void * +intr_establish(int legacy_irq, struct pic *pic, int pin, int type, int level, + int (*handler)(void *), void *arg, bool known_mpsafe) +{ + + return intr_establish_xname(legacy_irq, pic, pin, type, + level, handler, arg, known_mpsafe, "unknown"); +} + /* * Called on bound CPU to handle intr_disestablish(). * @@ -1918,17 +1947,159 @@ intr_set_affinity(struct intrsource *isp return err; } -int -intr_distribute(struct intrhand *ih, const kcpuset_t *newset, kcpuset_t *oldset) +static bool +intr_is_affinity_intrsource(struct intrsource *isp, const kcpuset_t *cpuset) { + struct cpu_info *ci; + + KASSERT(mutex_owned(&cpu_lock)); + + ci = isp->is_handlers->ih_cpu; + KASSERT(ci != NULL); + + return kcpuset_isset(cpuset, cpu_index(ci)); +} + +static struct intrhand * +intr_get_handler(const char *intrid) +{ + struct intrsource *isp; + + KASSERT(mutex_owned(&cpu_lock)); + + isp = intr_get_io_intrsource(intrid); + if (isp == NULL) + return NULL; + + return isp->is_handlers; +} + +/* + * MI interface for subr_interrupt.c + */ +uint64_t +interrupt_get_count(const char *intrid, u_int cpu_idx) +{ + struct cpu_info *ci; struct intrsource *isp; - int ret, slot; + struct intrhand *ih; + struct percpu_evcnt pep; + cpuid_t cpuid; + int i, slot; + uint64_t count = 0; + ci = cpu_lookup(cpu_idx); + cpuid = ci->ci_cpuid; + + mutex_enter(&cpu_lock); + + ih = intr_get_handler(intrid); + if (ih == NULL) { + count = 0; + goto out; + } + slot = ih->ih_slot; + isp = ih->ih_cpu->ci_isources[slot]; + + for (i = 0; i < ncpu; i++) { + pep = isp->is_saved_evcnt[i]; + if (cpuid == pep.cpuid) { + if (isp->is_active_cpu == pep.cpuid) { + count = isp->is_evcnt.ev_count; + goto out; + } else { + count = pep.count; + goto out; + } + } + } + + out: + mutex_exit(&cpu_lock); + return count; +} + +/* + * MI interface for subr_interrupt.c + */ +void +interrupt_get_assigned(const char *intrid, kcpuset_t *cpuset) +{ + struct cpu_info *ci; + struct intrhand *ih; + + kcpuset_zero(cpuset); + + mutex_enter(&cpu_lock); + + ih = intr_get_handler(intrid); if (ih == NULL) - return EINVAL; + goto out; + + ci = ih->ih_cpu; + kcpuset_set(cpuset, cpu_index(ci)); + + out: + mutex_exit(&cpu_lock); +} + +/* + * MI interface for subr_interrupt.c + */ +void +interrupt_get_available(kcpuset_t *cpuset) +{ + CPU_INFO_ITERATOR cii; + struct cpu_info *ci; + + kcpuset_zero(cpuset); + + mutex_enter(&cpu_lock); + for (CPU_INFO_FOREACH(cii, ci)) { + if ((ci->ci_schedstate.spc_flags & SPCF_NOINTR) == 0) { + kcpuset_set(cpuset, cpu_index(ci)); + } + } + mutex_exit(&cpu_lock); +} + +/* + * MI interface for subr_interrupt.c + */ +void +interrupt_get_devname(const char *intrid, char *buf, size_t len) +{ + struct intrsource *isp; + struct intrhand *ih; + int slot; mutex_enter(&cpu_lock); + ih = intr_get_handler(intrid); + if (ih == NULL) { + buf[0] = '\0'; + goto out; + } + slot = ih->ih_slot; + isp = ih->ih_cpu->ci_isources[slot]; + strncpy(buf, isp->is_xname, INTRDEVNAMEBUF); + + out: + mutex_exit(&cpu_lock); +} + +static int +intr_distribute_locked(struct intrhand *ih, const kcpuset_t *newset, + kcpuset_t *oldset) +{ + struct intrsource *isp; + int slot; + + KASSERT(mutex_owned(&cpu_lock)); + + if (ih == NULL) + return EINVAL; + slot = ih->ih_slot; isp = ih->ih_cpu->ci_isources[slot]; KASSERT(isp != NULL); @@ -1936,9 +2107,114 @@ intr_distribute(struct intrhand *ih, con if (oldset != NULL) intr_get_affinity(isp, oldset); - ret = intr_set_affinity(isp, newset); + return intr_set_affinity(isp, newset); +} + +/* + * MI interface for subr_interrupt.c + */ +int +interrupt_distribute(void *cookie, const kcpuset_t *newset, kcpuset_t *oldset) +{ + int error; + struct intrhand *ih = cookie; + mutex_enter(&cpu_lock); + error = intr_distribute_locked(ih, newset, oldset); mutex_exit(&cpu_lock); - return ret; + return error; +} + +/* + * MI interface for subr_interrupt.c + */ +int +interrupt_distribute_handler(const char *intrid, const kcpuset_t *newset, + kcpuset_t *oldset) +{ + int error; + struct intrhand *ih; + + mutex_enter(&cpu_lock); + + ih = intr_get_handler(intrid); + if (ih == NULL) { + error = ENOENT; + goto out; + } + error = intr_distribute_locked(ih, newset, oldset); + + out: + mutex_exit(&cpu_lock); + return error; +} + +/* + * MI interface for subr_interrupt.c + */ +struct intrids_handler * +interrupt_construct_intrids(const kcpuset_t *cpuset) +{ + struct intrsource *isp; + struct intrids_handler *ii_handler; + intrid_t *ids; + int i, count; + + if (kcpuset_iszero(cpuset)) + return 0; + + /* + * Count the number of interrupts which affinity to any cpu of "cpuset". + */ + count = 0; + mutex_enter(&cpu_lock); + SIMPLEQ_FOREACH(isp, &io_interrupt_sources, is_list) { + if (intr_is_affinity_intrsource(isp, cpuset)) + count++; + } + mutex_exit(&cpu_lock); + + ii_handler = kmem_zalloc(sizeof(int) + sizeof(intrid_t) * count, + KM_SLEEP); + if (ii_handler == NULL) + return NULL; + ii_handler->iih_nids = count; + if (count == 0) + return ii_handler; + + ids = ii_handler->iih_intrids; + i = 0; + mutex_enter(&cpu_lock); + SIMPLEQ_FOREACH(isp, &io_interrupt_sources, is_list) { + /* Ignore devices attached after counting "count". */ + if (i >= count) { + DPRINTF(("New devices are attached after counting.\n")); + break; + } + + if (!intr_is_affinity_intrsource(isp, cpuset)) + continue; + + strncpy(ids[i], isp->is_intrid, sizeof(intrid_t)); + i++; + } + mutex_exit(&cpu_lock); + + return ii_handler; +} + +/* + * MI interface for subr_interrupt.c + */ +void +interrupt_destruct_intrids(struct intrids_handler *ii_handler) +{ + size_t iih_size; + + if (ii_handler == NULL) + return; + + iih_size = sizeof(int) + sizeof(intrid_t) * ii_handler->iih_nids; + kmem_free(ii_handler, iih_size); } Index: src/sys/conf/files diff -u src/sys/conf/files:1.1130 src/sys/conf/files:1.1131 --- src/sys/conf/files:1.1130 Sat Aug 1 21:19:24 2015 +++ src/sys/conf/files Mon Aug 17 06:16:03 2015 @@ -1,4 +1,4 @@ -# $NetBSD: files,v 1.1130 2015/08/01 21:19:24 jmcneill Exp $ +# $NetBSD: files,v 1.1131 2015/08/17 06:16:03 knakahara Exp $ # @(#)files.newconf 7.5 (Berkeley) 5/10/93 version 20141030 @@ -1443,6 +1443,9 @@ file kern/kern_drvctl.c drvctl needs-f defpseudo cpuctl defflag CPU_UCODE: firmload +# interrupt control +defpseudo intrctl + # pass-to-userspace transporter defpseudo putter file dev/putter/putter.c putter Index: src/sys/dev/pci/if_wm.c diff -u src/sys/dev/pci/if_wm.c:1.345 src/sys/dev/pci/if_wm.c:1.346 --- src/sys/dev/pci/if_wm.c:1.345 Tue Jul 28 07:15:03 2015 +++ src/sys/dev/pci/if_wm.c Mon Aug 17 06:16:03 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: if_wm.c,v 1.345 2015/07/28 07:15:03 msaitoh Exp $ */ +/* $NetBSD: if_wm.c,v 1.346 2015/08/17 06:16:03 knakahara Exp $ */ /* * Copyright (c) 2001, 2002, 2003, 2004 Wasabi Systems, Inc. @@ -81,7 +81,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.345 2015/07/28 07:15:03 msaitoh Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.346 2015/08/17 06:16:03 knakahara Exp $"); #ifdef _KERNEL_OPT #include "opt_net_mpsafe.h" @@ -99,6 +99,7 @@ __KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1. #include <sys/device.h> #include <sys/queue.h> #include <sys/syslog.h> +#include <sys/interrupt.h> #include <sys/rndsource.h> @@ -1601,7 +1602,8 @@ wm_attach(device_t parent, device_t self #ifdef WM_MPSAFE pci_intr_setattr(pc, &ih, PCI_INTR_MPSAFE, true); #endif - sc->sc_ihs[0] = pci_intr_establish(pc, ih, IPL_NET, wm_intr_legacy,sc); + sc->sc_ihs[0] = pci_intr_establish_xname(pc, ih, IPL_NET, + wm_intr_legacy, sc, device_xname(sc->sc_dev)); if (sc->sc_ihs[0] == NULL) { aprint_error_dev(sc->sc_dev, "unable to establish interrupt"); if (intrstr != NULL) @@ -1627,6 +1629,7 @@ alloc_retry: if (pci_intr_type(sc->sc_intrs[0]) == PCI_INTR_TYPE_MSIX) { void *vih; kcpuset_t *affinity; + char intr_xname[INTRDEVNAMEBUF]; kcpuset_create(&affinity, false); @@ -1639,9 +1642,14 @@ alloc_retry: &sc->sc_intrs[msix_matrix[i].intridx], PCI_INTR_MPSAFE, true); #endif - vih = pci_intr_establish(pc, + memset(intr_xname, 0, sizeof(intr_xname)); + strlcat(intr_xname, device_xname(sc->sc_dev), + sizeof(intr_xname)); + strlcat(intr_xname, msix_matrix[i].intrname, + sizeof(intr_xname)); + vih = pci_intr_establish_xname(pc, sc->sc_intrs[msix_matrix[i].intridx], IPL_NET, - msix_matrix[i].func, sc); + msix_matrix[i].func, sc, intr_xname); if (vih == NULL) { aprint_error_dev(sc->sc_dev, "unable to establish MSI-X(for %s)%s%s\n", @@ -1661,7 +1669,7 @@ alloc_retry: kcpuset_zero(affinity); /* Round-robin affinity */ kcpuset_set(affinity, msix_matrix[i].cpuid % ncpu); - error = pci_intr_distribute(vih, affinity, NULL); + error = interrupt_distribute(vih, affinity, NULL); if (error == 0) { aprint_normal_dev(sc->sc_dev, "for %s interrupting at %s affinity to %u\n", @@ -1684,8 +1692,8 @@ alloc_retry: #ifdef WM_MPSAFE pci_intr_setattr(pc, &sc->sc_intrs[0], PCI_INTR_MPSAFE, true); #endif - sc->sc_ihs[0] = pci_intr_establish(pc, sc->sc_intrs[0], - IPL_NET, wm_intr_legacy, sc); + sc->sc_ihs[0] = pci_intr_establish_xname(pc, sc->sc_intrs[0], + IPL_NET, wm_intr_legacy, sc, device_xname(sc->sc_dev)); if (sc->sc_ihs[0] == NULL) { aprint_error_dev(sc->sc_dev,"unable to establish %s\n", (pci_intr_type(sc->sc_intrs[0]) Index: src/sys/dev/pci/pci_stub.c diff -u src/sys/dev/pci/pci_stub.c:1.1 src/sys/dev/pci/pci_stub.c:1.2 --- src/sys/dev/pci/pci_stub.c:1.1 Wed Aug 24 20:27:35 2011 +++ src/sys/dev/pci/pci_stub.c Mon Aug 17 06:16:03 2015 @@ -1,5 +1,5 @@ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: pci_stub.c,v 1.1 2011/08/24 20:27:35 dyoung Exp $"); +__KERNEL_RCSID(0, "$NetBSD: pci_stub.c,v 1.2 2015/08/17 06:16:03 knakahara Exp $"); #include "opt_pci.h" @@ -14,11 +14,15 @@ int default_pci_bus_devorder(pci_chipset int default_pci_chipset_tag_create(pci_chipset_tag_t, uint64_t, const struct pci_overrides *, void *, pci_chipset_tag_t *); void default_pci_chipset_tag_destroy(pci_chipset_tag_t); +void *default_pci_intr_establish_xname(pci_chipset_tag_t, pci_intr_handle_t, + int, int (*)(void *), void *, const char *); __strict_weak_alias(pci_bus_devorder, default_pci_bus_devorder); __strict_weak_alias(pci_chipset_tag_create, default_pci_chipset_tag_create); __strict_weak_alias(pci_chipset_tag_destroy, default_pci_chipset_tag_destroy); +__strict_weak_alias(pci_intr_establish_xname, default_pci_intr_establish_xname); + int default_pci_bus_devorder(pci_chipset_tag_t pc, int bus, uint8_t *devs, int maxdevs) @@ -43,3 +47,11 @@ default_pci_chipset_tag_create(pci_chips { return EOPNOTSUPP; } + +void * +default_pci_intr_establish_xname(pci_chipset_tag_t pc, pci_intr_handle_t ih, + int level, int (*func)(void *), void *arg, const char *__nouse) +{ + + return pci_intr_establish(pc, ih, level, func, arg); +} Index: src/sys/dev/pci/pcivar.h diff -u src/sys/dev/pci/pcivar.h:1.103 src/sys/dev/pci/pcivar.h:1.104 --- src/sys/dev/pci/pcivar.h:1.103 Thu Aug 13 04:39:33 2015 +++ src/sys/dev/pci/pcivar.h Mon Aug 17 06:16:03 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: pcivar.h,v 1.103 2015/08/13 04:39:33 msaitoh Exp $ */ +/* $NetBSD: pcivar.h,v 1.104 2015/08/17 06:16:03 knakahara Exp $ */ /* * Copyright (c) 1996, 1997 Christopher G. Demetriou. All rights reserved. @@ -340,6 +340,8 @@ int pci_chipset_tag_create(pci_chipset_t void *, pci_chipset_tag_t *); void pci_chipset_tag_destroy(pci_chipset_tag_t); int pci_bus_devorder(pci_chipset_tag_t, int, uint8_t *, int); +void *pci_intr_establish_xname(pci_chipset_tag_t, pci_intr_handle_t, + int, int (*)(void *), void *, const char *); /* * Device abstraction for inheritance by elanpci(4), for example. Index: src/sys/dev/pci/ixgbe/ixgbe.c diff -u src/sys/dev/pci/ixgbe/ixgbe.c:1.35 src/sys/dev/pci/ixgbe/ixgbe.c:1.36 --- src/sys/dev/pci/ixgbe/ixgbe.c:1.35 Thu Aug 13 10:03:37 2015 +++ src/sys/dev/pci/ixgbe/ixgbe.c Mon Aug 17 06:16:03 2015 @@ -59,7 +59,7 @@ * POSSIBILITY OF SUCH DAMAGE. */ /*$FreeBSD: head/sys/dev/ixgbe/ixgbe.c 279805 2015-03-09 10:29:15Z araujo $*/ -/*$NetBSD: ixgbe.c,v 1.35 2015/08/13 10:03:37 msaitoh Exp $*/ +/*$NetBSD: ixgbe.c,v 1.36 2015/08/17 06:16:03 knakahara Exp $*/ #include "opt_inet.h" #include "opt_inet6.h" @@ -2689,7 +2689,7 @@ ixgbe_allocate_msix(struct adapter *adap /* Round-robin affinity */ kcpuset_zero(affinity); kcpuset_set(affinity, cpu_id % ncpu); - error = pci_intr_distribute(adapter->osdep.ihs[i], affinity, + error = interrupt_distribute(adapter->osdep.ihs[i], affinity, NULL); aprint_normal_dev(dev, "for TX/RX, interrupting at %s", intrstr); @@ -2736,7 +2736,7 @@ ixgbe_allocate_msix(struct adapter *adap /* Round-robin affinity */ kcpuset_zero(affinity); kcpuset_set(affinity, cpu_id % ncpu); - error = pci_intr_distribute(adapter->osdep.ihs[vector], affinity,NULL); + error = interrupt_distribute(adapter->osdep.ihs[vector], affinity,NULL); aprint_normal_dev(dev, "for link, interrupting at %s", intrstr); Index: src/sys/dev/pci/ixgbe/ixgbe.h diff -u src/sys/dev/pci/ixgbe/ixgbe.h:1.8 src/sys/dev/pci/ixgbe/ixgbe.h:1.9 --- src/sys/dev/pci/ixgbe/ixgbe.h:1.8 Wed Aug 5 04:08:44 2015 +++ src/sys/dev/pci/ixgbe/ixgbe.h Mon Aug 17 06:16:03 2015 @@ -59,7 +59,7 @@ * POSSIBILITY OF SUCH DAMAGE. */ /*$FreeBSD: head/sys/dev/ixgbe/ixgbe.h 279393 2015-02-28 14:57:57Z ngie $*/ -/*$NetBSD: ixgbe.h,v 1.8 2015/08/05 04:08:44 msaitoh Exp $*/ +/*$NetBSD: ixgbe.h,v 1.9 2015/08/17 06:16:03 knakahara Exp $*/ #ifndef _IXGBE_H_ @@ -107,6 +107,7 @@ #include <sys/endian.h> #include <sys/workqueue.h> #include <sys/cpu.h> +#include <sys/interrupt.h> #include "ixgbe_netbsd.h" #include "ixgbe_api.h" Index: src/sys/dev/pci/ixgbe/ixv.c diff -u src/sys/dev/pci/ixgbe/ixv.c:1.14 src/sys/dev/pci/ixgbe/ixv.c:1.15 --- src/sys/dev/pci/ixgbe/ixv.c:1.14 Fri Aug 14 15:27:28 2015 +++ src/sys/dev/pci/ixgbe/ixv.c Mon Aug 17 06:16:03 2015 @@ -31,7 +31,7 @@ ******************************************************************************/ /*$FreeBSD: head/sys/dev/ixgbe/ixv.c 275358 2014-12-01 11:45:24Z hselasky $*/ -/*$NetBSD: ixv.c,v 1.14 2015/08/14 15:27:28 martin Exp $*/ +/*$NetBSD: ixv.c,v 1.15 2015/08/17 06:16:03 knakahara Exp $*/ #include "opt_inet.h" #include "opt_inet6.h" @@ -1713,7 +1713,7 @@ ixv_allocate_msix(struct adapter *adapte /* Round-robin affinity */ kcpuset_zero(affinity); kcpuset_set(affinity, cpu_id % ncpu); - error = pci_intr_distribute(adapter->osdep.ihs[i], affinity, + error = interrupt_distribute(adapter->osdep.ihs[i], affinity, NULL); aprint_normal_dev(dev, "for TX/RX, interrupting at %s", intrstr); @@ -1750,7 +1750,7 @@ ixv_allocate_msix(struct adapter *adapte /* Round-robin affinity */ kcpuset_zero(affinity); kcpuset_set(affinity, cpu_id % ncpu); - error = pci_intr_distribute(adapter->osdep.ihs[vector], affinity,NULL); + error = interrupt_distribute(adapter->osdep.ihs[vector], affinity,NULL); aprint_normal_dev(dev, "for link, interrupting at %s, ", intrstr); Index: src/sys/dev/pci/ixgbe/ixv.h diff -u src/sys/dev/pci/ixgbe/ixv.h:1.6 src/sys/dev/pci/ixgbe/ixv.h:1.7 --- src/sys/dev/pci/ixgbe/ixv.h:1.6 Wed Aug 5 04:08:44 2015 +++ src/sys/dev/pci/ixgbe/ixv.h Mon Aug 17 06:16:03 2015 @@ -31,7 +31,7 @@ ******************************************************************************/ /*$FreeBSD: head/sys/dev/ixgbe/ixv.h 257176 2013-10-26 17:58:36Z glebius $*/ -/*$NetBSD: ixv.h,v 1.6 2015/08/05 04:08:44 msaitoh Exp $*/ +/*$NetBSD: ixv.h,v 1.7 2015/08/17 06:16:03 knakahara Exp $*/ #ifndef _IXV_H_ @@ -75,6 +75,7 @@ #include <sys/proc.h> #include <sys/sysctl.h> #include <sys/endian.h> +#include <sys/interrupt.h> #include "ixgbe_netbsd.h" #include "ixgbe_api.h" Index: src/sys/kern/files.kern diff -u src/sys/kern/files.kern:1.6 src/sys/kern/files.kern:1.7 --- src/sys/kern/files.kern:1.6 Sun May 10 07:41:15 2015 +++ src/sys/kern/files.kern Mon Aug 17 06:16:03 2015 @@ -1,4 +1,4 @@ -# $NetBSD: files.kern,v 1.6 2015/05/10 07:41:15 pgoyette Exp $ +# $NetBSD: files.kern,v 1.7 2015/08/17 06:16:03 knakahara Exp $ # # kernel sources @@ -131,6 +131,7 @@ file kern/subr_exec_fd.c kern file kern/subr_extent.c kern file kern/subr_hash.c kern file kern/subr_humanize.c kern +file kern/subr_interrupt.c kern file kern/subr_iostat.c kern file kern/subr_ipi.c kern file kern/subr_kcpuset.c kern Index: src/sys/kern/kern_stub.c diff -u src/sys/kern/kern_stub.c:1.39 src/sys/kern/kern_stub.c:1.40 --- src/sys/kern/kern_stub.c:1.39 Mon Apr 27 06:42:53 2015 +++ src/sys/kern/kern_stub.c Mon Aug 17 06:16:03 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: kern_stub.c,v 1.39 2015/04/27 06:42:53 knakahara Exp $ */ +/* $NetBSD: kern_stub.c,v 1.40 2015/08/17 06:16:03 knakahara Exp $ */ /*- * Copyright (c) 2007, 2008 The NetBSD Foundation, Inc. @@ -62,7 +62,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: kern_stub.c,v 1.39 2015/04/27 06:42:53 knakahara Exp $"); +__KERNEL_RCSID(0, "$NetBSD: kern_stub.c,v 1.40 2015/08/17 06:16:03 knakahara Exp $"); #include "opt_ptrace.h" #include "opt_ktrace.h" @@ -147,7 +147,14 @@ __weak_alias(userconf_prompt, voidop); __weak_alias(kobj_renamespace, nullop); -__weak_alias(pci_intr_distribute, eopnotsupp); +__weak_alias(interrupt_get_count, eopnotsupp); +__weak_alias(interrupt_get_assigned, eopnotsupp); +__weak_alias(interrupt_get_available, eopnotsupp); +__weak_alias(interrupt_get_devname, eopnotsupp); +__weak_alias(interrupt_construct_intrids, eopnotsupp); +__weak_alias(interrupt_destruct_intrids, eopnotsupp); +__weak_alias(interrupt_distribute, eopnotsupp); +__weak_alias(interrupt_distribute_handler, eopnotsupp); /* * Scheduler activations system calls. These need to remain until libc's Index: src/sys/secmodel/suser/secmodel_suser.c diff -u src/sys/secmodel/suser/secmodel_suser.c:1.41 src/sys/secmodel/suser/secmodel_suser.c:1.42 --- src/sys/secmodel/suser/secmodel_suser.c:1.41 Tue Feb 25 18:30:13 2014 +++ src/sys/secmodel/suser/secmodel_suser.c Mon Aug 17 06:16:03 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: secmodel_suser.c,v 1.41 2014/02/25 18:30:13 pooka Exp $ */ +/* $NetBSD: secmodel_suser.c,v 1.42 2015/08/17 06:16:03 knakahara Exp $ */ /*- * Copyright (c) 2006 Elad Efrat <e...@netbsd.org> * All rights reserved. @@ -38,7 +38,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: secmodel_suser.c,v 1.41 2014/02/25 18:30:13 pooka Exp $"); +__KERNEL_RCSID(0, "$NetBSD: secmodel_suser.c,v 1.42 2015/08/17 06:16:03 knakahara Exp $"); #include <sys/types.h> #include <sys/param.h> @@ -443,6 +443,20 @@ secmodel_suser_system_cb(kauth_cred_t cr break; + case KAUTH_SYSTEM_INTR: + switch (req) { + case KAUTH_REQ_SYSTEM_INTR_AFFINITY: + if (isroot) + result = KAUTH_RESULT_ALLOW; + + break; + + default: + break; + } + + break; + default: break; } Index: src/sys/sys/Makefile diff -u src/sys/sys/Makefile:1.156 src/sys/sys/Makefile:1.157 --- src/sys/sys/Makefile:1.156 Fri Jul 31 12:51:32 2015 +++ src/sys/sys/Makefile Mon Aug 17 06:16:03 2015 @@ -1,4 +1,4 @@ -# $NetBSD: Makefile,v 1.156 2015/07/31 12:51:32 kamil Exp $ +# $NetBSD: Makefile,v 1.157 2015/08/17 06:16:03 knakahara Exp $ .include <bsd.own.mk> @@ -21,7 +21,7 @@ INCS= acct.h agpio.h aio.h ansi.h aout_m exec_coff.h exec_ecoff.h exec_elf.h exec_script.h extattr.h extent.h \ fcntl.h fd_set.h fdio.h featuretest.h file.h filedesc.h filio.h \ flashio.h float_ieee754.h fstypes.h gcq.h gmon.h gpio.h hash.h \ - ieee754.h inttypes.h ioccom.h ioctl.h ioctl_compat.h iostat.h ipc.h \ + ieee754.h intr.h intrio.h inttypes.h ioccom.h ioctl.h ioctl_compat.h iostat.h ipc.h \ joystick.h \ kcore.h kcpuset.h kgdb.h kmem.h ksem.h ksyms.h ktrace.h \ localedef.h lock.h lockf.h lua.h lwp.h lwpctl.h \ Index: src/sys/sys/intr.h diff -u src/sys/sys/intr.h:1.18 src/sys/sys/intr.h:1.19 --- src/sys/sys/intr.h:1.18 Mon Apr 27 06:42:53 2015 +++ src/sys/sys/intr.h Mon Aug 17 06:16:03 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: intr.h,v 1.18 2015/04/27 06:42:53 knakahara Exp $ */ +/* $NetBSD: intr.h,v 1.19 2015/08/17 06:16:03 knakahara Exp $ */ /*- * Copyright (c) 2007 The NetBSD Foundation, Inc. @@ -33,6 +33,7 @@ #define _SYS_INTR_H_ #define INTRIDBUF 64 +#define INTRDEVNAMEBUF 256 #ifdef _KERNEL Index: src/sys/sys/kauth.h diff -u src/sys/sys/kauth.h:1.71 src/sys/sys/kauth.h:1.72 --- src/sys/sys/kauth.h:1.71 Mon Mar 18 19:35:46 2013 +++ src/sys/sys/kauth.h Mon Aug 17 06:16:03 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: kauth.h,v 1.71 2013/03/18 19:35:46 plunky Exp $ */ +/* $NetBSD: kauth.h,v 1.72 2015/08/17 06:16:03 knakahara Exp $ */ /*- * Copyright (c) 2005, 2006 Elad Efrat <e...@netbsd.org> @@ -111,6 +111,7 @@ enum { KAUTH_SYSTEM_LFS, KAUTH_SYSTEM_FS_EXTATTR, KAUTH_SYSTEM_FS_SNAPSHOT, + KAUTH_SYSTEM_INTR, }; /* @@ -156,6 +157,7 @@ enum kauth_system_req { KAUTH_REQ_SYSTEM_LFS_FCNTL, KAUTH_REQ_SYSTEM_MOUNT_UMAP, KAUTH_REQ_SYSTEM_MOUNT_DEVICE, + KAUTH_REQ_SYSTEM_INTR_AFFINITY, }; /* Added files: Index: src/sys/kern/subr_interrupt.c diff -u /dev/null src/sys/kern/subr_interrupt.c:1.1 --- /dev/null Mon Aug 17 06:16:03 2015 +++ src/sys/kern/subr_interrupt.c Mon Aug 17 06:16:03 2015 @@ -0,0 +1,513 @@ +/* $NetBSD: subr_interrupt.c,v 1.1 2015/08/17 06:16:03 knakahara Exp $ */ + +/* + * Copyright (c) 2015 Internet Initiative Japan Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__KERNEL_RCSID(0, "$NetBSD: subr_interrupt.c,v 1.1 2015/08/17 06:16:03 knakahara Exp $"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/errno.h> +#include <sys/cpu.h> +#include <sys/interrupt.h> +#include <sys/intr.h> +#include <sys/kcpuset.h> +#include <sys/kmem.h> +#include <sys/proc.h> +#include <sys/xcall.h> +#include <sys/sysctl.h> + +#include <sys/conf.h> +#include <sys/intrio.h> +#include <sys/kauth.h> + +#include <machine/limits.h> + +#ifdef INTR_DEBUG +#define DPRINTF(msg) printf msg +#else +#define DPRINTF(msg) +#endif + +static struct intrio_set kintrio_set = { "\0", NULL, 0 }; + +#define UNSET_NOINTR_SHIELD 0 +#define SET_NOINTR_SHIELD 1 + +static void +interrupt_shield_xcall(void *arg1, void *arg2) +{ + struct cpu_info *ci; + struct schedstate_percpu *spc; + int s, shield; + + ci = arg1; + shield = (int)(intptr_t)arg2; + spc = &ci->ci_schedstate; + + s = splsched(); + if (shield == UNSET_NOINTR_SHIELD) + spc->spc_flags &= ~SPCF_NOINTR; + else if (shield == SET_NOINTR_SHIELD) + spc->spc_flags |= SPCF_NOINTR; + splx(s); +} + +/* + * Change SPCF_NOINTR flag of schedstate_percpu->spc_flags. + */ +static int +interrupt_shield(u_int cpu_idx, int shield) +{ + struct cpu_info *ci; + struct schedstate_percpu *spc; + + KASSERT(mutex_owned(&cpu_lock)); + + ci = cpu_lookup(cpu_idx); + if (ci == NULL) + return EINVAL; + + spc = &ci->ci_schedstate; + if (shield == UNSET_NOINTR_SHIELD) { + if ((spc->spc_flags & SPCF_NOINTR) == 0) + return 0; + } else if (shield == SET_NOINTR_SHIELD) { + if ((spc->spc_flags & SPCF_NOINTR) != 0) + return 0; + } + + if (ci == curcpu() || !mp_online) { + interrupt_shield_xcall(ci, (void *)(intptr_t)shield); + } else { + uint64_t where; + where = xc_unicast(0, interrupt_shield_xcall, ci, + (void *)(intptr_t)shield, ci); + xc_wait(where); + } + + spc->spc_lastmod = time_second; + return 0; +} + +/* + * Move all assigned interrupts from "cpu_idx" to the other cpu as possible. + * The destination cpu is the lowest cpuid of available cpus. + * If there are no available cpus, give up to move interrupts. + */ +static int +interrupt_avert_intr(u_int cpu_idx) +{ + kcpuset_t *cpuset; + struct intrids_handler *ii_handler; + intrid_t *ids; + int error, i, nids; + + kcpuset_create(&cpuset, true); + kcpuset_set(cpuset, cpu_idx); + + ii_handler = interrupt_construct_intrids(cpuset); + if (ii_handler == NULL) { + error = ENOMEM; + goto out; + } + nids = ii_handler->iih_nids; + if (nids == 0) { + error = 0; + goto destruct_out; + } + + interrupt_get_available(cpuset); + kcpuset_clear(cpuset, cpu_idx); + if (kcpuset_iszero(cpuset)) { + DPRINTF(("%s: no available cpu\n", __func__)); + error = ENOENT; + goto destruct_out; + } + + ids = ii_handler->iih_intrids; + for (i = 0; i < nids; i++) { + error = interrupt_distribute_handler(ids[i], cpuset, NULL); + if (error) + break; + } + + destruct_out: + interrupt_destruct_intrids(ii_handler); + out: + kcpuset_destroy(cpuset); + return error; +} + +/* + * Return actual intrio_list_line size. + * intrio_list_line size is variable by ncpu. + */ +static size_t +interrupt_intrio_list_line_size(void) +{ + + return sizeof(struct intrio_list_line) + + sizeof(struct intrio_list_line_cpu) * (ncpu - 1); +} + +/* + * Return the size of interrupts list data on success. + * Reterun 0 on failed. + */ +static size_t +interrupt_intrio_list_size(void) +{ + struct intrids_handler *ii_handler; + size_t ilsize; + + ilsize = 0; + + /* buffer header */ + ilsize += sizeof(struct intrio_list); + + /* il_line body */ + ii_handler = interrupt_construct_intrids(kcpuset_running); + if (ii_handler == NULL) + return 0; + ilsize += interrupt_intrio_list_line_size() * (ii_handler->iih_nids); + + interrupt_destruct_intrids(ii_handler); + return ilsize; +} + +/* + * Set intrctl list data to "il", and return list structure bytes. + * If error occured, return <0. + * If "data" == NULL, simply return list structure bytes. + */ +static int +interrupt_intrio_list(struct intrio_list *il, int length) +{ + struct intrio_list_line *illine; + kcpuset_t *assigned, *avail; + struct intrids_handler *ii_handler; + intrid_t *ids; + size_t ilsize; + u_int cpu_idx; + int nids, intr_idx, ret, line_size; + + ilsize = interrupt_intrio_list_size(); + if (ilsize == 0) + return -ENOMEM; + + if (il == NULL) + return ilsize; + + if (length < ilsize) + return -ENOMEM; + + illine = (struct intrio_list_line *) + ((char *)il + sizeof(struct intrio_list)); + il->il_lineoffset = (off_t)((uintptr_t)illine - (uintptr_t)il); + + kcpuset_create(&avail, true); + interrupt_get_available(avail); + kcpuset_create(&assigned, true); + + ii_handler = interrupt_construct_intrids(kcpuset_running); + if (ii_handler == NULL) { + DPRINTF(("%s: interrupt_construct_intrids() failed\n", + __func__)); + ret = -ENOMEM; + goto out; + } + + line_size = interrupt_intrio_list_line_size(); + /* ensure interrupts are not added after interrupt_intrio_list_size(). */ + nids = ii_handler->iih_nids; + ids = ii_handler->iih_intrids; + if (ilsize < sizeof(struct intrio_list) + line_size * nids) { + DPRINTF(("%s: interrupts are added during execution.\n", + __func__)); + ret = -ENOMEM; + goto destruct_out; + } + + for (intr_idx = 0; intr_idx < nids; intr_idx++) { + char devname[INTRDEVNAMEBUF]; + + strncpy(illine->ill_intrid, ids[intr_idx], INTRIDBUF); + interrupt_get_devname(ids[intr_idx], devname, sizeof(devname)); + strncpy(illine->ill_xname, devname, INTRDEVNAMEBUF); + + interrupt_get_assigned(ids[intr_idx], assigned); + for (cpu_idx = 0; cpu_idx < ncpu; cpu_idx++) { + struct intrio_list_line_cpu *illcpu = + &illine->ill_cpu[cpu_idx]; + + illcpu->illc_assigned = + kcpuset_isset(assigned, cpu_idx) ? true : false; + illcpu->illc_count = + interrupt_get_count(ids[intr_idx], cpu_idx); + } + + illine = (struct intrio_list_line *) + ((char *)illine + line_size); + } + + ret = ilsize; + il->il_version = INTRIO_LIST_VERSION; + il->il_ncpus = ncpu; + il->il_nintrs = nids; + il->il_linesize = line_size; + il->il_bufsize = ilsize; + + destruct_out: + interrupt_destruct_intrids(ii_handler); + out: + kcpuset_destroy(assigned); + kcpuset_destroy(avail); + + return ret; +} + +/* + * "intrctl list" entry + */ +static int +interrupt_intrio_list_sysctl(SYSCTLFN_ARGS) +{ + int ret, error; + void *buf; + + if (oldlenp == NULL) + return EINVAL; + + /* + * If oldp == NULL, the sysctl(8) caller process want to get the size of + * intrctl list data only. + */ + if (oldp == NULL) { + ret = interrupt_intrio_list(NULL, 0); + if (ret < 0) + return -ret; + + *oldlenp = ret; + return 0; + } + + /* + * If oldp != NULL, the sysctl(8) caller process want to get both the size + * and the contents of intrctl list data. + */ + if (*oldlenp == 0) + return ENOMEM; + + buf = kmem_zalloc(*oldlenp, KM_SLEEP); + if (buf == NULL) + return ENOMEM; + + ret = interrupt_intrio_list(buf, *oldlenp); + if (ret < 0) { + error = -ret; + goto out; + } + error = copyout(buf, oldp, *oldlenp); + + out: + kmem_free(buf, *oldlenp); + return error; +} + +/* + * "intrctl affinity" entry + */ +static int +interrupt_set_affinity_sysctl(SYSCTLFN_ARGS) +{ + struct sysctlnode node; + struct intrio_set *iset; + cpuset_t *ucpuset; + kcpuset_t *kcpuset; + int error; + + error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_INTR, + KAUTH_REQ_SYSTEM_INTR_AFFINITY, NULL, NULL, NULL); + if (error) + return EPERM; + + node = *rnode; + iset = (struct intrio_set *)node.sysctl_data; + + error = sysctl_lookup(SYSCTLFN_CALL(&node)); + if (error != 0 || newp == NULL) + return error; + + ucpuset = iset->cpuset; + kcpuset_create(&kcpuset, true); + error = kcpuset_copyin(ucpuset, kcpuset, iset->cpuset_size); + if (error) + goto out; + if (kcpuset_iszero(kcpuset)) { + error = EINVAL; + goto out; + } + + error = interrupt_distribute_handler(iset->intrid, kcpuset, NULL); + + out: + kcpuset_destroy(kcpuset); + return error; +} + +/* + * "intrctl intr" entry + */ +static int +interrupt_intr_sysctl(SYSCTLFN_ARGS) +{ + struct sysctlnode node; + struct intrio_set *iset; + cpuset_t *ucpuset; + kcpuset_t *kcpuset; + int error; + u_int cpu_idx; + + error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_CPU, + KAUTH_REQ_SYSTEM_CPU_SETSTATE, NULL, NULL, NULL); + if (error) + return EPERM; + + node = *rnode; + iset = (struct intrio_set *)node.sysctl_data; + + error = sysctl_lookup(SYSCTLFN_CALL(&node)); + if (error != 0 || newp == NULL) + return error; + + ucpuset = iset->cpuset; + kcpuset_create(&kcpuset, true); + error = kcpuset_copyin(ucpuset, kcpuset, iset->cpuset_size); + if (error) + goto out; + if (kcpuset_iszero(kcpuset)) { + error = EINVAL; + goto out; + } + + cpu_idx = kcpuset_ffs(kcpuset) - 1; /* support one CPU only */ + + mutex_enter(&cpu_lock); + error = interrupt_shield(cpu_idx, UNSET_NOINTR_SHIELD); + mutex_exit(&cpu_lock); + + out: + kcpuset_destroy(kcpuset); + return error; +} + +/* + * "intrctl nointr" entry + */ +static int +interrupt_nointr_sysctl(SYSCTLFN_ARGS) +{ + struct sysctlnode node; + struct intrio_set *iset; + cpuset_t *ucpuset; + kcpuset_t *kcpuset; + int error; + u_int cpu_idx; + + error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_CPU, + KAUTH_REQ_SYSTEM_CPU_SETSTATE, NULL, NULL, NULL); + if (error) + return EPERM; + + node = *rnode; + iset = (struct intrio_set *)node.sysctl_data; + + error = sysctl_lookup(SYSCTLFN_CALL(&node)); + if (error != 0 || newp == NULL) + return error; + + ucpuset = iset->cpuset; + kcpuset_create(&kcpuset, true); + error = kcpuset_copyin(ucpuset, kcpuset, iset->cpuset_size); + if (error) + goto out; + if (kcpuset_iszero(kcpuset)) { + error = EINVAL; + goto out; + } + + cpu_idx = kcpuset_ffs(kcpuset) - 1; /* support one CPU only */ + + mutex_enter(&cpu_lock); + error = interrupt_shield(cpu_idx, SET_NOINTR_SHIELD); + mutex_exit(&cpu_lock); + if (error) + goto out; + + error = interrupt_avert_intr(cpu_idx); + + out: + kcpuset_destroy(kcpuset); + return error; +} + +SYSCTL_SETUP(sysctl_interrupt_setup, "sysctl interrupt setup") +{ + const struct sysctlnode *node = NULL; + + sysctl_createv(clog, 0, NULL, &node, + CTLFLAG_PERMANENT, CTLTYPE_NODE, + "intr", SYSCTL_DESCR("Interrupt options"), + NULL, 0, NULL, 0, + CTL_KERN, CTL_CREATE, CTL_EOL); + + sysctl_createv(clog, 0, &node, NULL, + CTLFLAG_PERMANENT, CTLTYPE_STRUCT, + "list", SYSCTL_DESCR("intrctl list"), + interrupt_intrio_list_sysctl, 0, NULL, + 0, CTL_CREATE, CTL_EOL); + + sysctl_createv(clog, 0, &node, NULL, + CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_STRUCT, + "affinity", SYSCTL_DESCR("set affinity"), + interrupt_set_affinity_sysctl, 0, &kintrio_set, + sizeof(kintrio_set), CTL_CREATE, CTL_EOL); + + sysctl_createv(clog, 0, &node, NULL, + CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_STRUCT, + "intr", SYSCTL_DESCR("set intr"), + interrupt_intr_sysctl, 0, &kintrio_set, + sizeof(kintrio_set), CTL_CREATE, CTL_EOL); + + sysctl_createv(clog, 0, &node, NULL, + CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_STRUCT, + "nointr", SYSCTL_DESCR("set nointr"), + interrupt_nointr_sysctl, 0, &kintrio_set, + sizeof(kintrio_set), CTL_CREATE, CTL_EOL); +} Index: src/sys/sys/interrupt.h diff -u /dev/null src/sys/sys/interrupt.h:1.1 --- /dev/null Mon Aug 17 06:16:03 2015 +++ src/sys/sys/interrupt.h Mon Aug 17 06:16:03 2015 @@ -0,0 +1,56 @@ +/* $NetBSD: interrupt.h,v 1.1 2015/08/17 06:16:03 knakahara Exp $ */ + +/* + * Copyright (c) 2015 Internet Initiative Japan Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _SYS_INTERRUPT_H_ +#define _SYS_INTERUPT_H_ + +#include <sys/types.h> +#include <sys/intr.h> +#include <sys/kcpuset.h> + +typedef char intrid_t[INTRIDBUF]; +struct intrids_handler { + int iih_nids; + intrid_t iih_intrids[1]; + /* + * The number of the "iih_intrids" array will be overwritten by + * "iih_nids" after intr_construct_intrids(). + */ +}; + +uint64_t interrupt_get_count(const char *, u_int); +void interrupt_get_assigned(const char *, kcpuset_t *); +void interrupt_get_available(kcpuset_t *); +void interrupt_get_devname(const char *, char *, size_t); +struct intrids_handler *interrupt_construct_intrids(const kcpuset_t *); +void interrupt_destruct_intrids(struct intrids_handler *); +int interrupt_distribute(void *, const kcpuset_t *, kcpuset_t *); +int interrupt_distribute_handler(const char *, const kcpuset_t *, + kcpuset_t *); + +#endif /* !_SYS_INTERRUPT_H_ */ Index: src/sys/sys/intrio.h diff -u /dev/null src/sys/sys/intrio.h:1.1 --- /dev/null Mon Aug 17 06:16:03 2015 +++ src/sys/sys/intrio.h Mon Aug 17 06:16:03 2015 @@ -0,0 +1,68 @@ +/* $NetBSD: intrio.h,v 1.1 2015/08/17 06:16:03 knakahara Exp $ */ + +/* + * Copyright (c) 2015 Internet Initiative Japan Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _SYS_INTRIO_H_ +#define _SYS_INTRIO_H_ + +#include <sys/types.h> +#include <sys/intr.h> +#include <sys/sched.h> + +#define INTRIO_LIST_VERSION 1 + +struct intrio_set { + char intrid[INTRIDBUF]; + cpuset_t *cpuset; + size_t cpuset_size; +}; + +struct intrio_list_line_cpu { + bool illc_assigned; + uint64_t illc_count; +}; + +struct intrio_list_line { + char ill_intrid[INTRIDBUF]; + char ill_xname[INTRDEVNAMEBUF]; + struct intrio_list_line_cpu ill_cpu[1]; /* Array size is overwritten to ncpu. */ +}; + +struct intrio_list { + int il_version; /* Version number of this struct. */ + int il_ncpus; + int il_nintrs; + size_t il_bufsize; + + size_t il_linesize; + off_t il_lineoffset; +/* + * struct intrio_list_line il_lines[interrupt_num] must be followed here. + */ +}; + +#endif /* !_SYS_INTRIO_H_ */