diff --git a/distrib/sets/lists/base/mi b/distrib/sets/lists/base/mi index 6d619f3..dc0e5cd 100644 --- a/distrib/sets/lists/base/mi +++ b/distrib/sets/lists/base/mi @@ -1642,6 +1642,7 @@ ./usr/sbin/ifwatchd base-netutil-bin ./usr/sbin/inetd base-netutil-bin ./usr/sbin/installboot base-sysutil-bin +./usr/sbin/intrctl base-sysutil-bin ./usr/sbin/iopctl base-sysutil-bin ./usr/sbin/iostat base-sysutil-bin ./usr/sbin/ipfs base-ipf-bin ipfilter diff --git a/distrib/sets/lists/comp/mi b/distrib/sets/lists/comp/mi index e19c796..7e365d4 100644 --- a/distrib/sets/lists/comp/mi +++ b/distrib/sets/lists/comp/mi @@ -3203,6 +3203,8 @@ ./usr/include/sys/gpio.h comp-c-include ./usr/include/sys/hash.h comp-c-include ./usr/include/sys/ieee754.h comp-c-include +./usr/include/sys/intr.h comp-c-include +./usr/include/sys/intrio.h comp-c-include ./usr/include/sys/inttypes.h comp-c-include ./usr/include/sys/ioccom.h comp-c-include ./usr/include/sys/ioctl.h comp-c-include @@ -10382,6 +10384,7 @@ ./usr/share/man/cat9/in_getifa.0 comp-sys-catman .cat ./usr/share/man/cat9/incore.0 comp-sys-catman .cat ./usr/share/man/cat9/inittodr.0 comp-sys-catman .cat +./usr/share/man/cat9/interrupt_distribute.0 comp-sys-catman .cat ./usr/share/man/cat9/intro.0 comp-sys-catman .cat ./usr/share/man/cat9/ioasic.0 comp-sys-catman .cat ./usr/share/man/cat9/ioasic_attach_devs.0 comp-sys-catman .cat @@ -10620,7 +10623,6 @@ ./usr/share/man/cat9/pci_intr.0 comp-sys-catman .cat ./usr/share/man/cat9/pci_intr_alloc.0 comp-sys-catman .cat ./usr/share/man/cat9/pci_intr_disestablish.0 comp-sys-catman .cat -./usr/share/man/cat9/pci_intr_distribute.0 comp-sys-catman .cat ./usr/share/man/cat9/pci_intr_establish.0 comp-sys-catman .cat ./usr/share/man/cat9/pci_intr_evcnt.0 comp-sys-catman .cat ./usr/share/man/cat9/pci_intr_map.0 comp-sys-catman .cat @@ -17195,6 +17197,7 @@ ./usr/share/man/html9/in_getifa.html comp-sys-htmlman html ./usr/share/man/html9/incore.html comp-sys-htmlman html ./usr/share/man/html9/inittodr.html comp-sys-htmlman html +./usr/share/man/html9/interrupt_distribute.html comp-sys-htmlman html ./usr/share/man/html9/intro.html comp-sys-htmlman html ./usr/share/man/html9/ioasic.html comp-sys-htmlman html ./usr/share/man/html9/ioasic_attach_devs.html comp-sys-htmlman html @@ -17427,7 +17430,6 @@ ./usr/share/man/html9/pci_intr.html comp-sys-htmlman html ./usr/share/man/html9/pci_intr_alloc.html comp-sys-htmlman html ./usr/share/man/html9/pci_intr_disestablish.html comp-sys-htmlman html -./usr/share/man/html9/pci_intr_distribute.html comp-sys-htmlman html ./usr/share/man/html9/pci_intr_establish.html comp-sys-htmlman html ./usr/share/man/html9/pci_intr_evcnt.html comp-sys-htmlman html ./usr/share/man/html9/pci_intr_map.html comp-sys-htmlman html @@ -24161,6 +24163,7 @@ ./usr/share/man/man9/in_getifa.9 comp-sys-man .man ./usr/share/man/man9/incore.9 comp-sys-man .man ./usr/share/man/man9/inittodr.9 comp-sys-man .man +./usr/share/man/man9/interrupt_distribute.9 comp-sys-man .man ./usr/share/man/man9/intro.9 comp-sys-man .man ./usr/share/man/man9/ioasic.9 comp-sys-man .man ./usr/share/man/man9/ioasic_attach_devs.9 comp-sys-man .man @@ -24399,7 +24402,6 @@ ./usr/share/man/man9/pci_intr.9 comp-sys-man .man ./usr/share/man/man9/pci_intr_alloc.9 comp-sys-man .man ./usr/share/man/man9/pci_intr_disestablish.9 comp-sys-man .man -./usr/share/man/man9/pci_intr_distribute.9 comp-sys-man .man ./usr/share/man/man9/pci_intr_establish.9 comp-sys-man .man ./usr/share/man/man9/pci_intr_evcnt.9 comp-sys-man .man ./usr/share/man/man9/pci_intr_map.9 comp-sys-man .man diff --git a/distrib/sets/lists/debug/mi b/distrib/sets/lists/debug/mi index 7cb465a..e8ea44a 100644 --- a/distrib/sets/lists/debug/mi +++ b/distrib/sets/lists/debug/mi @@ -1058,6 +1058,7 @@ ./usr/libdata/debug/usr/sbin/ifwatchd.debug comp-netutil-debug debug ./usr/libdata/debug/usr/sbin/inetd.debug comp-netutil-debug debug ./usr/libdata/debug/usr/sbin/installboot.debug comp-sysutil-debug debug +./usr/libdata/debug/usr/sbin/intrctl.debug comp-sysutil-debug debug ./usr/libdata/debug/usr/sbin/iopctl.debug comp-sysutil-debug debug ./usr/libdata/debug/usr/sbin/iostat.debug comp-sysutil-debug debug ./usr/libdata/debug/usr/sbin/ipfs.debug comp-ipf-debug ipfilter,debug diff --git a/distrib/sets/lists/man/mi b/distrib/sets/lists/man/mi index 89b860b..7b90684 100644 --- a/distrib/sets/lists/man/mi +++ b/distrib/sets/lists/man/mi @@ -2545,6 +2545,7 @@ ./usr/share/man/cat8/inetd.0 man-netutil-catman .cat ./usr/share/man/cat8/init.0 man-sysutil-catman .cat ./usr/share/man/cat8/installboot.0 man-sysutil-catman .cat +./usr/share/man/cat8/intrctl.0 man-sysutil-catman .cat ./usr/share/man/cat8/intro.0 man-sys-catman .cat ./usr/share/man/cat8/iopctl.0 man-sysutil-catman .cat ./usr/share/man/cat8/iostat.0 man-sysutil-catman .cat @@ -5420,6 +5421,7 @@ ./usr/share/man/html8/inetd.html man-netutil-htmlman html ./usr/share/man/html8/init.html man-sysutil-htmlman html ./usr/share/man/html8/installboot.html man-sysutil-htmlman html +./usr/share/man/html8/intrctl.html man-sysutil-htmlman html ./usr/share/man/html8/intro.html man-sys-htmlman html ./usr/share/man/html8/iopctl.html man-sysutil-htmlman html ./usr/share/man/html8/iostat.html man-sysutil-htmlman html @@ -8441,6 +8443,7 @@ ./usr/share/man/man8/inetd.8 man-netutil-man .man ./usr/share/man/man8/init.8 man-sysutil-man .man ./usr/share/man/man8/installboot.8 man-sysutil-man .man +./usr/share/man/man8/intrctl.8 man-sysutil-man .man ./usr/share/man/man8/intro.8 man-sys-man .man ./usr/share/man/man8/iopctl.8 man-sysutil-man .man ./usr/share/man/man8/iostat.8 man-sysutil-man .man diff --git a/sbin/sysctl/sysctl.c b/sbin/sysctl/sysctl.c index 931b7c3..9a9f32e 100644 --- a/sbin/sysctl/sysctl.c +++ b/sbin/sysctl/sysctl.c @@ -197,6 +197,11 @@ static const struct handlespec { { "/kern/coredump/setid/mode", mode_bits, mode_bits, NULL }, { "/kern/drivers", kern_drivers, NULL, NULL }, + { "/kern/intr/list", printother, NULL, "intrctl" }, + { "/kern/intr/affinity", printother, NULL, "intrctl" }, + { "/kern/intr/intr", printother, NULL, "intrctl" }, + { "/kern/intr/nointr", printother, NULL, "intrctl" }, + { "/vm/vmmeter", printother, NULL, "vmstat' or 'systat" }, { "/vm/loadavg", vm_loadavg, NULL, NULL }, diff --git a/share/man/man9/Makefile b/share/man/man9/Makefile index 5acf48a..66feca6 100644 --- a/share/man/man9/Makefile +++ b/share/man/man9/Makefile @@ -27,9 +27,9 @@ MAN= accept_filter.9 accf_data.9 accf_http.9 \ ieee80211_node.9 ieee80211_output.9 ieee80211_proto.9 \ ieee80211_radiotap.9 iic.9 imax.9 \ in_getifa.9 \ - in4_cksum.9 inittodr.9 intro.9 ioasic.9 ioctl.9 ipkdb.9 ipi.9 isa.9 \ - isapnp.9 itimerfix.9 kauth.9 kcopy.9 kcpuset.9 kmem.9 \ - kpause.9 \ + in4_cksum.9 inittodr.9 interrupt_distribute.9 intro.9 ioasic.9 \ + ioctl.9 ipkdb.9 ipi.9 isa.9 isapnp.9 itimerfix.9 kauth.9 kcopy.9 \ + kcpuset.9 kmem.9 kpause.9 \ kfilter_register.9 knote.9 \ kprintf.9 kthread.9 linedisc.9 lock.9 log.9 ltsleep.9 \ LWP_CACHE_CREDS.9 \ @@ -40,7 +40,7 @@ MAN= accept_filter.9 accf_data.9 accf_http.9 \ mstohz.9 mutex.9 m_tag.9 namecache.9 \ namei.9 nullop.9 opencrypto.9 optstr.9 \ panic.9 pathbuf.9 pci.9 pci_configure_bus.9 pci_intr.9 \ - pci_intr_distribute.9 pci_msi.9 pckbport.9 pcmcia.9 pcq.9 pcu.9 \ + pci_msi.9 pckbport.9 pcmcia.9 pcq.9 pcu.9 \ percpu.9 pfil.9 physio.9 pmap.9 pmatch.9 pmc.9 pmf.9 pool.9 \ pool_cache.9 powerhook_establish.9 ppi.9 ppsratecheck.9 preempt.9 \ proc_find.9 pserialize.9 putter.9 \ diff --git a/share/man/man9/interrupt_distribute.9 b/share/man/man9/interrupt_distribute.9 new file mode 100644 index 0000000..bc8ad22 --- /dev/null +++ b/share/man/man9/interrupt_distribute.9 @@ -0,0 +1,54 @@ +.\" $NetBSD: pci_intr_distribute.9,v 1.2 2015/04/27 10:32:22 wiz 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. +.\" +.Dd April 8, 2015 +.Dt INTERRUPT_DISTRIBUTE 9 +.Os +.Sh NAME +.Nm interrupt_distribute +.Sh SYNOPSIS +.In sys/interrupt.h +.Ft int +.Fn interrupt_distribute "void *ich" "const kcpuset_t *newset" \ +"kcpuset_t *oldset" +.Sh DESCRIPTION +The +.Nm +function exists to assign an interrupt to a CPU. +.Pp +If a driver (or the other kernel component) wishes to assign an +interrupt to a CPU, it should pass a interrupt handler such as +the return value of +.Fn pci_intr_establish +as +.Fa ich +argument, and it should pass the kcpuset to which it should be +assigned as +.Fa newset . +To get the previous value, pass a +.Pf non- Dv NULL +value to +.Ft oldset . diff --git a/share/man/man9/pci_intr_distribute.9 b/share/man/man9/pci_intr_distribute.9 deleted file mode 100644 index dbe84df..0000000 --- a/share/man/man9/pci_intr_distribute.9 +++ /dev/null @@ -1,53 +0,0 @@ -.\" $NetBSD: pci_intr_distribute.9,v 1.2 2015/04/27 10:32:22 wiz 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. -.\" -.Dd April 8, 2015 -.Dt PCI_INTR_DISTRIBUTE 9 -.Os -.Sh NAME -.Nm pci_intr_distribute -.Sh SYNOPSIS -.In dev/pci/pcivar.h -.Ft int -.Fn pci_intr_distribute "void *ich" "const kcpuset_t *newset" \ -"kcpuset_t *oldset" -.Sh DESCRIPTION -The -.Nm -function exists to assign an interrupt to a CPU. -.Pp -If a driver (or the other kernel component) wishes to assign an -interrupt to a CPU, it should pass the return value of -.Fn pci_intr_establish -as -.Fa ich -argument, and it should pass the kcpuset to which it should be -assigned as -.Fa newset . -To get the previous value, pass a -.Pf non- Dv NULL -value to -.Ft oldset . diff --git a/sys/arch/x86/include/intr.h b/sys/arch/x86/include/intr.h index f60ef25..1a52a33 100644 --- a/sys/arch/x86/include/intr.h +++ b/sys/arch/x86/include/intr.h @@ -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 *); diff --git a/sys/arch/x86/include/intr_distribute.h b/sys/arch/x86/include/intr_distribute.h index bae9fa0..c769e89 100644 --- a/sys/arch/x86/include/intr_distribute.h +++ b/sys/arch/x86/include/intr_distribute.h @@ -34,6 +34,7 @@ #include int intr_distribute(struct intrhand *, const kcpuset_t *, kcpuset_t *); +int intr_distribute_handler(const char *, const kcpuset_t *, kcpuset_t *); #endif /* _KERNEL */ diff --git a/sys/arch/x86/include/pci_machdep_common.h b/sys/arch/x86/include/pci_machdep_common.h index d27d21a..e8f40ea 100644 --- a/sys/arch/x86/include/pci_machdep_common.h +++ b/sys/arch/x86/include/pci_machdep_common.h @@ -115,10 +115,11 @@ int pci_intr_map(const struct pci_attach_args *, const char *pci_intr_string(pci_chipset_tag_t, pci_intr_handle_t, char *, size_t); const struct evcnt *pci_intr_evcnt(pci_chipset_tag_t, pci_intr_handle_t); +void *pci_intr_establish_xname(pci_chipset_tag_t, pci_intr_handle_t, + int, int (*)(void *), void *, const char *); 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, diff --git a/sys/arch/x86/pci/pci_intr_machdep.c b/sys/arch/x86/pci/pci_intr_machdep.c index bc5f6df..4f98f25 100644 --- a/sys/arch/x86/pci/pci_intr_machdep.c +++ b/sys/arch/x86/pci/pci_intr_machdep.c @@ -275,8 +275,8 @@ pci_intr_setattr(pci_chipset_tag_t pc, pci_intr_handle_t *ih, } 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, pci_intr_handle_t ih, 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, pci_intr_handle_t ih, } #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 pc, void *cookie) 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) diff --git a/sys/arch/x86/pci/pci_msi_machdep.c b/sys/arch/x86/pci/pci_msi_machdep.c index 420c4bd..4445b01 100644 --- a/sys/arch/x86/pci/pci_msi_machdep.c +++ b/sys/arch/x86/pci/pci_msi_machdep.c @@ -206,7 +206,8 @@ pci_msi_alloc_common(pci_intr_handle_t **ihps, int *count, 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; @@ -217,8 +218,8 @@ pci_msi_common_establish(pci_chipset_tag_t pc, pci_intr_handle_t ih, 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 @@ -394,7 +395,7 @@ x86_pci_msi_release(pci_chipset_tag_t pc, pci_intr_handle_t *pihs, int count) */ 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; @@ -404,7 +405,7 @@ x86_pci_msi_establish(pci_chipset_tag_t pc, pci_intr_handle_t ih, 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); } /* @@ -439,7 +440,7 @@ x86_pci_msix_release(pci_chipset_tag_t pc, pci_intr_handle_t *pihs, int count) */ 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; @@ -449,7 +450,7 @@ x86_pci_msix_establish(pci_chipset_tag_t pc, pci_intr_handle_t ih, 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); } /* diff --git a/sys/arch/x86/pci/pci_msi_machdep.h b/sys/arch/x86/pci/pci_msi_machdep.h index f20ce49..a655e3d 100644 --- a/sys/arch/x86/pci/pci_msi_machdep.h +++ b/sys/arch/x86/pci/pci_msi_machdep.h @@ -34,13 +34,13 @@ const char *x86_pci_msi_string(pci_chipset_tag_t, pci_intr_handle_t, 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_ */ diff --git a/sys/arch/x86/x86/intr.c b/sys/arch/x86/x86/intr.c index 30761a6..5cd7a73 100644 --- a/sys/arch/x86/x86/intr.c +++ b/sys/arch/x86/x86/intr.c @@ -151,6 +151,10 @@ __KERNEL_RCSID(0, "$NetBSD: intr.c,v 1.86 2015/06/23 10:00:13 msaitoh Exp $"); #include #include #include +#include + +#include +#include #include @@ -224,6 +228,8 @@ static void intr_source_free(struct cpu_info *, int, struct pic *, int); 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 *arg2) } 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 pic *pic, int pin, int type, int level, 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 pic *pic, int pin, int type, int level, 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, const kcpuset_t *cpuset) 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, const kcpuset_t *newset, kcpuset_t *oldset) 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); } diff --git a/sys/conf/files b/sys/conf/files index bb80985..760eb18 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -1439,6 +1439,9 @@ file kern/kern_drvctl.c drvctl needs-flag defpseudo cpuctl defflag CPU_UCODE: firmload +# interrupt control +defpseudo intrctl + # pass-to-userspace transporter defpseudo putter file dev/putter/putter.c putter diff --git a/sys/dev/pci/if_wm.c b/sys/dev/pci/if_wm.c index 5c7e45b..f48f4ce 100644 --- a/sys/dev/pci/if_wm.c +++ b/sys/dev/pci/if_wm.c @@ -99,6 +99,7 @@ __KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.342 2015/07/22 11:14:13 knakahara Exp $" #include #include #include +#include #include @@ -1601,7 +1602,12 @@ wm_attach(device_t parent, device_t self, void *aux) #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) { + sc->sc_ihs[0] = pci_intr_establish(pc, ih, IPL_NET, + wm_intr_legacy, sc); + } if (sc->sc_ihs[0] == NULL) { aprint_error_dev(sc->sc_dev, "unable to establish interrupt"); if (intrstr != NULL) @@ -1627,6 +1633,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 +1646,19 @@ 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) { + vih = pci_intr_establish(pc, + sc->sc_intrs[msix_matrix[i].intridx], + IPL_NET, msix_matrix[i].func, sc); + } if (vih == NULL) { aprint_error_dev(sc->sc_dev, "unable to establish MSI-X(for %s)%s%s\n", @@ -1661,7 +1678,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 TX interrupting at %s affinity to %u\n", @@ -1682,8 +1699,12 @@ 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) { + sc->sc_ihs[0] = pci_intr_establish(pc, sc->sc_intrs[0], + IPL_NET, wm_intr_legacy, sc); + } if (sc->sc_ihs[0] == NULL) { aprint_error_dev(sc->sc_dev,"unable to establish %s\n", (pci_intr_type(sc->sc_intrs[0]) diff --git a/sys/kern/files.kern b/sys/kern/files.kern index 2399590..0edfac7 100644 --- a/sys/kern/files.kern +++ b/sys/kern/files.kern @@ -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 diff --git a/sys/kern/kern_stub.c b/sys/kern/kern_stub.c index 5a0231c..d91957a 100644 --- a/sys/kern/kern_stub.c +++ b/sys/kern/kern_stub.c @@ -147,7 +147,16 @@ __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); + +__weak_alias(pci_intr_establish_xname, voidop); /* * Scheduler activations system calls. These need to remain until libc's diff --git a/sys/kern/subr_interrupt.c b/sys/kern/subr_interrupt.c new file mode 100644 index 0000000..798c193 --- /dev/null +++ b/sys/kern/subr_interrupt.c @@ -0,0 +1,513 @@ +/* $NetBSD$ */ + +/* + * 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 +__KERNEL_RCSID(0, "$NetBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#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); +} diff --git a/sys/secmodel/suser/secmodel_suser.c b/sys/secmodel/suser/secmodel_suser.c index cbd6fcf..bbb15a0 100644 --- a/sys/secmodel/suser/secmodel_suser.c +++ b/sys/secmodel/suser/secmodel_suser.c @@ -443,6 +443,20 @@ secmodel_suser_system_cb(kauth_cred_t cred, kauth_action_t action, 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; } diff --git a/sys/sys/Makefile b/sys/sys/Makefile index 57e9a55..9bcd930 100644 --- a/sys/sys/Makefile +++ b/sys/sys/Makefile @@ -21,7 +21,7 @@ INCS= acct.h agpio.h aio.h ansi.h aout_mids.h ataio.h atomic.h audioio.h \ 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 \ diff --git a/sys/sys/interrupt.h b/sys/sys/interrupt.h new file mode 100644 index 0000000..9316d3c --- /dev/null +++ b/sys/sys/interrupt.h @@ -0,0 +1,56 @@ +/* $NetBSD$ */ + +/* + * 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 +#include +#include + +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_ */ diff --git a/sys/sys/intr.h b/sys/sys/intr.h index b080a6e..a034c68 100644 --- a/sys/sys/intr.h +++ b/sys/sys/intr.h @@ -33,6 +33,7 @@ #define _SYS_INTR_H_ #define INTRIDBUF 64 +#define INTRDEVNAMEBUF 256 #ifdef _KERNEL diff --git a/sys/sys/intrio.h b/sys/sys/intrio.h new file mode 100644 index 0000000..0ba8610 --- /dev/null +++ b/sys/sys/intrio.h @@ -0,0 +1,68 @@ +/* $NetBSD$ */ + +/* + * 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 +#include +#include + +#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_ */ diff --git a/sys/sys/kauth.h b/sys/sys/kauth.h index 6e53424..970afdc 100644 --- a/sys/sys/kauth.h +++ b/sys/sys/kauth.h @@ -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, }; /* diff --git a/usr.sbin/Makefile b/usr.sbin/Makefile index 752faca..702944c 100644 --- a/usr.sbin/Makefile +++ b/usr.sbin/Makefile @@ -11,7 +11,7 @@ SUBDIR= ac accton acpitools altq apm apmd arp \ flashctl fssconfig fusermount fwctl \ gpioctl grfconfig gspa \ hdaudioctl \ - i2cscan ifwatchd inetd installboot iopctl iostat ipwctl irdaattach \ + i2cscan ifwatchd inetd installboot intrctl iopctl iostat ipwctl irdaattach \ isdn isibootd iteconfig iwictl \ kgmon \ lastlogin ldpd link lmcconfig lockstat lpr \ diff --git a/usr.sbin/intrctl/Makefile b/usr.sbin/intrctl/Makefile new file mode 100644 index 0000000..b684086 --- /dev/null +++ b/usr.sbin/intrctl/Makefile @@ -0,0 +1,9 @@ +# $NetBSD$ + +.include + +PROG= intrctl +MAN= intrctl.8 +SRCS= intrctl.c intrctl_io.c + +.include diff --git a/usr.sbin/intrctl/intrctl.8 b/usr.sbin/intrctl/intrctl.8 new file mode 100644 index 0000000..b7665cc --- /dev/null +++ b/usr.sbin/intrctl/intrctl.8 @@ -0,0 +1,70 @@ +.\" $NetBSD$ +.\" +.\" 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. +.\" +.Dd July 22, 2015 +.Dt INTRCTL 8 +.Os +.Sh NAME +.Nm intrctl +.Nd program to control interrupts +.Sh SYNOPSIS +.Nm intrctl +.Ar command +.Op Ar options +.Sh DESCRIPTION +The +.Nm +command can be used to control and inspect the state of intrerupts +in the system. +.Pp +The first argument, +.Ar command , +specifies the action to take. +Valid commands are: +.Bl -tag -width XofflineXcpunoX +.It list +for each intrid in the system, display interrupt counts per CPU. +The intrid is an interrupt name such as "ioapic0 pin 22" for x86. +.It affinity Fl c Ar cpu_index Fl i Ar intrid +set an +.Ar intrid +interrupt's affinity to +.Ar cpu_index . +.It intr Fl c Ar cpu_index +enable to set an interrupt's affinity to +.Ar cpu_index . +If +.Ar cpu_index +is already enabled, this command has no effect. +.It nointr Fl c Ar cpu_index +disable to set an interrupt's affinity to +.Ar cpu_index . +If +.Ar cpu_index +is already disabled, this command has no effect. +.Ed +.Sh SEE ALSO +.Xr cpuctl 8 diff --git a/usr.sbin/intrctl/intrctl.c b/usr.sbin/intrctl/intrctl.c new file mode 100644 index 0000000..5f4bef2 --- /dev/null +++ b/usr.sbin/intrctl/intrctl.c @@ -0,0 +1,271 @@ +/* $NetBSD$ */ + +/* + * 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 +__RCSID("$NetBSD$"); + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "intrctl_io.h" + +__dead static void usage(void); + +int verbose; + +static void intrctl_list(int, char **); +static void intrctl_affinity(int, char **); +static void intrctl_intr(int, char **); +static void intrctl_nointr(int, char **); + +static struct cmdtab { + const char *label; + void (*func)(int, char **); +} const intrctl_cmdtab[] = { + { "list", intrctl_list }, + { "affinity", intrctl_affinity }, + { "intr", intrctl_intr }, + { "nointr", intrctl_nointr }, + { NULL, NULL }, +}; + +int +main(int argc, char **argv) +{ + const struct cmdtab *ct; + char *cmdname; + + if (argc < 2) + usage(); + + cmdname = argv[1]; + argv += 1; + argc -= 1; + + for (ct = intrctl_cmdtab; ct->label != NULL; ct++) { + if (strcmp(cmdname, ct->label) == 0) { + break; + } + } + if (ct->label == NULL) + errx(EXIT_FAILURE, "unknown command ``%s''", cmdname); + + (*ct->func)(argc, argv); + exit(EXIT_SUCCESS); + /* NOTREACHED */ +} + +static void +usage(void) +{ + const char *progname = getprogname(); + + fprintf(stderr, "usage: %s list\n", progname); + fprintf(stderr, " %s affinity -i interrupt_name -c cpu_index\n", progname); + fprintf(stderr, " %s intr -c cpu_index\n", progname); + fprintf(stderr, " %s nointr -c cpu_index\n", progname); + exit(EXIT_FAILURE); + /* NOTREACHED */ +} + +static int intrctl_io_alloc_retry_count = 4; + +static void +intrctl_list(int argc, char **argv) +{ + struct intrio_list_line *illine; + int i, ncpus; + void *handle; + + handle = intrctl_io_alloc(intrctl_io_alloc_retry_count); + if (handle == NULL) + err(EXIT_FAILURE, "intrctl_io_alloc"); + + /* header */ + ncpus = intrctl_io_ncpus(handle); + printf("interrupt id\t"); + for (i = 0; i < ncpus; i++) { + printf(" CPU#%02u\t", i); + } + printf("device name(s)\n"); + + /* body */ + illine = intrctl_io_firstline(handle); + for (; illine != NULL; illine = intrctl_io_nextline(handle, illine)) { + printf("%s\t", illine->ill_intrid); + for (i = 0; i < ncpus; i++) { + struct intrio_list_line_cpu *illc = &illine->ill_cpu[i]; + printf("%8" PRIu64 "%c\t", illc->illc_count, + illc->illc_assigned ? '*' : ' '); + } + + printf("%s\n", illine->ill_xname); + } + + intrctl_io_free(handle); +} + +static void +intrctl_affinity(int argc, char **argv) +{ + struct intrio_set iset; + cpuset_t *cpuset; + unsigned long index; + int ch, error; + + index = ULONG_MAX; + memset(&iset.intrid, 0, sizeof(iset.intrid)); + + while ((ch = getopt(argc, argv, "c:i:")) != -1) { + switch (ch) { + case 'c': + index = strtoul(optarg, NULL, 10); + break; + case 'i': + if (strnlen(optarg, ARG_MAX) > INTRIDBUF) + usage(); + strlcpy(iset.intrid, optarg, INTRIDBUF); + break; + default: + usage(); + } + } + + if (iset.intrid[0] == '\0' || index == ULONG_MAX) + usage(); + + if (index >= (u_long)sysconf(_SC_NPROCESSORS_CONF)) + err(EXIT_FAILURE, "invalid cpu index"); + + cpuset = cpuset_create(); + if (cpuset == NULL) + err(EXIT_FAILURE, "create_cpuset()"); + + cpuset_zero(cpuset); + cpuset_set(index, cpuset); + iset.cpuset = cpuset; + iset.cpuset_size = cpuset_size(cpuset); + error = sysctlbyname("kern.intr.affinity", NULL, NULL, &iset, sizeof(iset)); + cpuset_destroy(cpuset); + if (error < 0) + err(EXIT_FAILURE, "sysctl kern.intr.affinity"); +} + +static void +intrctl_intr(int argc, char **argv) +{ + struct intrio_set iset; + cpuset_t *cpuset; + unsigned long index; + int ch, error; + + index = ULONG_MAX; + + while ((ch = getopt(argc, argv, "c:")) != -1) { + switch (ch) { + case 'c': + index = strtoul(optarg, NULL, 10); + break; + default: + usage(); + } + } + + if (index == ULONG_MAX) + usage(); + + if (index >= (u_long)sysconf(_SC_NPROCESSORS_CONF)) + err(EXIT_FAILURE, "invalid cpu index"); + + cpuset = cpuset_create(); + if (cpuset == NULL) + err(EXIT_FAILURE, "create_cpuset()"); + + cpuset_zero(cpuset); + cpuset_set(index, cpuset); + iset.cpuset = cpuset; + iset.cpuset_size = cpuset_size(cpuset); + error = sysctlbyname("kern.intr.intr", NULL, NULL, &iset, sizeof(iset)); + cpuset_destroy(cpuset); + if (error < 0) + err(EXIT_FAILURE, "sysctl kern.intr.intr"); +} + +static void +intrctl_nointr(int argc, char **argv) +{ + struct intrio_set iset; + cpuset_t *cpuset; + unsigned long index; + int ch, error; + + index = ULONG_MAX; + + while ((ch = getopt(argc, argv, "c:")) != -1) { + switch (ch) { + case 'c': + index = strtoul(optarg, NULL, 10); + break; + default: + usage(); + } + } + + if (index == ULONG_MAX) + usage(); + + if (index >= (u_long)sysconf(_SC_NPROCESSORS_CONF)) + err(EXIT_FAILURE, "invalid cpu index"); + + cpuset = cpuset_create(); + if (cpuset == NULL) + err(EXIT_FAILURE, "create_cpuset()"); + + cpuset_zero(cpuset); + cpuset_set(index, cpuset); + iset.cpuset = cpuset; + iset.cpuset_size = cpuset_size(cpuset); + error = sysctlbyname("kern.intr.nointr", NULL, NULL, &iset, sizeof(iset)); + cpuset_destroy(cpuset); + if (error < 0) + err(EXIT_FAILURE, "sysctl kern.intr.nointr"); +} diff --git a/usr.sbin/intrctl/intrctl_io.c b/usr.sbin/intrctl/intrctl_io.c new file mode 100644 index 0000000..4913afb --- /dev/null +++ b/usr.sbin/intrctl/intrctl_io.c @@ -0,0 +1,131 @@ +/* $NetBSD$ */ + +/* + * 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 +__RCSID("$NetBSD$"); + +#include +#include + +#include +#include +#include + +#include "intrctl_io.h" + +/* + * To support increasing the number of interrupts (devices are dynamically + * attached), retry sysctl(3) "retry" times. + */ +void * +intrctl_io_alloc(int retry) +{ + size_t buf_size; + int i, error; + void *buf; + + error = sysctlbyname("kern.intr.list", NULL, &buf_size, NULL, 0); + if (error < 0) { + return NULL; + } + + buf = malloc(buf_size); + if (buf == NULL) { + return NULL; + } + + for (i = 0; i < retry; i++) { + error = sysctlbyname("kern.intr.list", buf, &buf_size, NULL, 0); + if (error >= 0) + return buf; + else if (error == -ENOMEM) { + void *temp; + + temp = realloc(buf, buf_size); + if (temp == NULL) { + free(buf); + return NULL; + } + buf = temp; + } else { + free(buf); + return NULL; + } + } + return NULL; +} + +void +intrctl_io_free(void *handle) +{ + + free(handle); +} + +int +intrctl_io_ncpus(void *handle) +{ + struct intrio_list *list = handle; + + return list->il_ncpus; +} + +int +intrctl_io_nintrs(void *handle) +{ + struct intrio_list *list = handle; + + return list->il_nintrs; +} + +struct intrio_list_line * +intrctl_io_firstline(void *handle) +{ + struct intrio_list *list = handle; + + return (struct intrio_list_line *)((char *)list + list->il_lineoffset); +} + +struct intrio_list_line * +intrctl_io_nextline(void *handle, struct intrio_list_line *cur) +{ + struct intrio_list *list; + struct intrio_list_line *next; + size_t line_size; + char *buf_end; + + list = handle; + buf_end = (char *)list + list->il_bufsize; + + line_size = list->il_linesize; + next = (struct intrio_list_line *)((char *)cur + line_size); + if ((char *)next >= buf_end) + return NULL; + + return next; +} diff --git a/usr.sbin/intrctl/intrctl_io.h b/usr.sbin/intrctl/intrctl_io.h new file mode 100644 index 0000000..b0bf303 --- /dev/null +++ b/usr.sbin/intrctl/intrctl_io.h @@ -0,0 +1,44 @@ +/* $NetBSD$ */ + +/* + * 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 _INTRCTL_INTRCTL_IO_H_ +#define _INTRCTL_INTRCTL_IO_H_ + +#include +__RCSID("$NetBSD$"); + +#include + +void *intrctl_io_alloc(int); +void intrctl_io_free(void *); +int intrctl_io_ncpus(void *); +int intrctl_io_nintrs(void *); +struct intrio_list_line *intrctl_io_firstline(void *); +struct intrio_list_line *intrctl_io_nextline(void *, struct intrio_list_line *); + +#endif /* !_INTRCTL_INTRCTL_IO_H_ */