add pci_intr_distribute(9) for x86.

This commit is contained in:
knakahara 2015-04-27 06:42:52 +00:00
parent 2373b55abc
commit c65d622dea
11 changed files with 666 additions and 35 deletions

View File

@ -1,4 +1,4 @@
# $NetBSD: mi,v 1.1954 2015/04/21 11:10:29 pooka Exp $
# $NetBSD: mi,v 1.1955 2015/04/27 06:42:52 knakahara Exp $
#
# Note: don't delete entries from here - mark them as "obsolete" instead.
#
@ -17131,6 +17131,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/pci_intr_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
@ -24063,6 +24064,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/pci_intr_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

View File

@ -1,4 +1,4 @@
# $NetBSD: Makefile,v 1.384 2015/04/21 11:10:29 pooka Exp $
# $NetBSD: Makefile,v 1.385 2015/04/27 06:42:52 knakahara Exp $
# Makefile for section 9 (kernel function and variable) manual pages.
@ -39,10 +39,11 @@ MAN= accept_filter.9 accf_data.9 accf_http.9 \
microseq.9 microtime.9 microuptime.9 mi_switch.9 module.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 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 \
panic.9 pathbuf.9 pci.9 pci_configure_bus.9 pci_intr.9 \
pci_intr_distribute.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 \
radio.9 ras.9 rasops.9 ratecheck.9 resettodr.9 rnd.9 rndsink.9 \
roundup.9 rssadapt.9 rt_timer.9 rwlock.9 RUN_ONCE.9 STACK.9 \
scanc.9 \

View File

@ -0,0 +1,53 @@
.\" $NetBSD: pci_intr_distribute.9,v 1.1 2015/04/27 06:42:52 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.
.\"
.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
functions exist to assing an interrupt to CPU.
.Pp
If a driver (or the other kernel component) wishes to assign an
interrupt to CPU, it should pass the return value of
.Fn pci_intr_establish
to the
.Ft ich .
And it should set kcpuset which want to assign to
.Ft newset .
If it want to get the assignment before changing, it should be
pass non-NULL value to
.Ft oldset .
If not, it should set NULL to
.Ft oldset .

View File

@ -1,4 +1,4 @@
/* $NetBSD: intr.h,v 1.45 2014/07/20 15:46:34 uebayasi Exp $ */
/* $NetBSD: intr.h,v 1.46 2015/04/27 06:42:52 knakahara Exp $ */
/*-
* Copyright (c) 1998, 2001, 2006, 2007, 2008 The NetBSD Foundation, Inc.
@ -42,6 +42,7 @@
#endif
#include <sys/evcnt.h>
#include <sys/queue.h>
#include <machine/intrdefs.h>
#ifndef _LOCORE
@ -71,6 +72,11 @@ struct intrstub {
void *ist_resume;
};
struct percpu_evcnt {
cpuid_t cpuid;
uint64_t count;
};
struct intrsource {
int is_maxlevel; /* max. IPL for this source */
int is_pin; /* IRQ for legacy; pin for IO APIC,
@ -86,6 +92,10 @@ struct intrsource {
int is_idtvec;
int is_minlevel;
char is_evname[32]; /* event counter name */
char is_intrid[INTRIDBUF]; /* intrid created by create_intrid() */
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 */
};
#define IS_LEGACY 0x0001 /* legacy ISA irq source */
@ -182,6 +192,9 @@ int intr_find_mpmapping(int, int, int *);
struct pic *intr_findpic(int);
void intr_printconfig(void);
struct intrsource *intr_allocate_io_intrsource(const char *);
void intr_free_io_intrsource(const char *);
int x86_send_ipi(struct cpu_info *, int);
void x86_broadcast_ipi(int);
void x86_ipi_handler(void);

View File

@ -0,0 +1,40 @@
/* $NetBSD: intr_distribute.h,v 1.1 2015/04/27 06:42:52 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 _X86_INTR_DISTRIBUTE_H_
#define _X86_INTR_DISTRIBUTE_H_
#ifdef _KERNEL
#include <sys/kcpuset.h>
int intr_distribute(struct intrhand *, const kcpuset_t *, kcpuset_t *);
#endif /* _KERNEL */
#endif /* !_X86_INTR_DISTRIBUTE_H_ */

View File

@ -1,4 +1,4 @@
/* $NetBSD: pci_machdep.h,v 1.15 2015/03/04 05:35:50 knakahara Exp $ */
/* $NetBSD: pci_machdep.h,v 1.16 2015/04/27 06:42:52 knakahara Exp $ */
/*
* Copyright (c) 1996 Christopher G. Demetriou. All rights reserved.
@ -33,6 +33,8 @@
#ifndef _X86_PCI_MACHDEP_H_
#define _X86_PCI_MACHDEP_H_
#include <x86/intr_distribute.h>
/*
* Types provided to machine-independent PCI code
* See also i82093var.h to find out pci_intr_handle_t's bitfield.

View File

@ -1,4 +1,4 @@
/* $NetBSD: pci_machdep_common.h,v 1.13 2014/03/29 19:28:30 christos Exp $ */
/* $NetBSD: pci_machdep_common.h,v 1.14 2015/04/27 06:42:52 knakahara Exp $ */
/*
* Copyright (c) 1996 Christopher G. Demetriou. All rights reserved.
@ -41,6 +41,8 @@
#define __HAVE_PCIIDE_MACHDEP_COMPAT_INTR_DISESTABLISH
#endif
#include <sys/kcpuset.h>
/*
* x86-specific PCI structure and type definitions.
* NOT TO BE USED DIRECTLY BY MACHINE INDEPENDENT CODE.
@ -116,6 +118,7 @@ const struct evcnt *pci_intr_evcnt(pci_chipset_tag_t, pci_intr_handle_t);
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 *);
/* experimental MSI support */
void *pci_msi_establish(struct pci_attach_args *, int, int (*)(void *), void *);

View File

@ -1,4 +1,4 @@
/* $NetBSD: pci_intr_machdep.c,v 1.27 2014/03/29 19:28:30 christos Exp $ */
/* $NetBSD: pci_intr_machdep.c,v 1.28 2015/04/27 06:42:52 knakahara Exp $ */
/*-
* Copyright (c) 1997, 1998, 2009 The NetBSD Foundation, Inc.
@ -73,15 +73,17 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: pci_intr_machdep.c,v 1.27 2014/03/29 19:28:30 christos Exp $");
__KERNEL_RCSID(0, "$NetBSD: pci_intr_machdep.c,v 1.28 2015/04/27 06:42:52 knakahara Exp $");
#include <sys/types.h>
#include <sys/param.h>
#include <sys/time.h>
#include <sys/systm.h>
#include <sys/cpu.h>
#include <sys/errno.h>
#include <sys/device.h>
#include <sys/intr.h>
#include <sys/kmem.h>
#include <sys/malloc.h>
#include <dev/pci/pcivar.h>
@ -328,6 +330,15 @@ 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
/*
* experimental support for MSI, does support a single vector,

View File

@ -1,4 +1,4 @@
/* $NetBSD: intr.c,v 1.78 2015/04/08 05:52:41 knakahara Exp $ */
/* $NetBSD: intr.c,v 1.79 2015/04/27 06:42:52 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.78 2015/04/08 05:52:41 knakahara Exp $");
__KERNEL_RCSID(0, "$NetBSD: intr.c,v 1.79 2015/04/27 06:42:52 knakahara Exp $");
#include "opt_intrdebug.h"
#include "opt_multiprocessor.h"
@ -180,6 +180,12 @@ __KERNEL_RCSID(0, "$NetBSD: intr.c,v 1.78 2015/04/08 05:52:41 knakahara Exp $");
#include <ddb/db_output.h>
#endif
#ifdef INTRDEBUG
#define DPRINTF(msg) printf msg
#else
#define DPRINTF(msg)
#endif
struct pic softintr_pic = {
.pic_name = "softintr_fakepic",
.pic_type = PIC_SOFT,
@ -190,6 +196,9 @@ struct pic softintr_pic = {
static void intr_calculatemasks(struct cpu_info *);
static SIMPLEQ_HEAD(, intrsource) io_interrupt_sources =
SIMPLEQ_HEAD_INITIALIZER(io_interrupt_sources);
#if NIOAPIC > 0 || NACPICA > 0
static int intr_scan_bus(int, int, int *);
#if NPCI > 0
@ -197,9 +206,11 @@ static int intr_find_pcibridge(int, pcitag_t *, pci_chipset_tag_t *);
#endif
#endif
static int intr_allocate_slot_cpu(struct cpu_info *, struct pic *, int, int *);
static int intr_allocate_slot_cpu(struct cpu_info *, struct pic *, int, int *,
struct intrsource *);
static int __noinline intr_allocate_slot(struct pic *, int, int,
struct cpu_info **, int *, int *);
struct cpu_info **, int *, int *,
struct intrsource *);
static void intr_source_free(struct cpu_info *, int, struct pic *, int);
@ -214,6 +225,14 @@ static void intr_redistribute_xc_s1(void *, void *);
static void intr_redistribute_xc_s2(void *, void *);
static bool intr_redistribute(struct cpu_info *);
static const char *legacy_intr_string(int, char *, size_t, struct pic *);
static int intr_find_unused_slot(struct cpu_info *, int *);
static void intr_activate_xcall(void *, void *);
static void intr_deactivate_xcall(void *, void *);
static void intr_get_affinity(struct intrsource *, kcpuset_t *);
static int intr_set_affinity(struct intrsource *, const kcpuset_t *);
/*
* Fill in default interrupt table (in case of spurious interrupt
* during configuration of kernel), setup interrupt control unit
@ -432,9 +451,135 @@ intr_scan_bus(int bus, int pin, int *handle)
}
#endif
/*
* Create an interrupt id such as "ioapic0 pin 9". This interrupt id is used
* by MI code and intrctl(8).
*/
static const char *
create_intrid(int legacy_irq, struct pic *pic, int pin, char *buf, size_t len)
{
int ih;
/*
* If the device is pci, "legacy_irq" is alway -1. Least 8 bit of "ih"
* is only used in intr_string() to show the irq number.
* If the device is "legacy"(such as floppy), it should not use
* intr_string().
*/
if (pic->pic_type == PIC_I8259) {
ih = legacy_irq;
return legacy_intr_string(ih, buf, len, pic);
} else {
ih = ((pic->pic_apicid << APIC_INT_APIC_SHIFT) & APIC_INT_APIC_MASK) |
((pin << APIC_INT_PIN_SHIFT) & APIC_INT_PIN_MASK);
if (pic->pic_type == PIC_IOAPIC) {
ih |= APIC_INT_VIA_APIC;
}
ih |= pin;
return intr_string(ih, buf, len);
}
}
/*
* Find intrsource from io_interrupt_sources list.
*/
static struct intrsource *
intr_get_io_intrsource(const char *intrid)
{
struct intrsource *isp;
KASSERT(mutex_owned(&cpu_lock));
SIMPLEQ_FOREACH(isp, &io_interrupt_sources, is_list) {
KASSERT(isp->is_intrid != NULL);
if (strncmp(intrid, isp->is_intrid, INTRIDBUF - 1) == 0) {
return isp;
}
}
return NULL;
}
/*
* Allocate intrsource and add to io_interrupt_sources list.
*/
struct intrsource *
intr_allocate_io_intrsource(const char *intrid)
{
CPU_INFO_ITERATOR cii;
struct cpu_info *ci;
struct intrsource *isp;
struct percpu_evcnt *pep;
KASSERT(mutex_owned(&cpu_lock));
if (intrid == NULL)
return NULL;
isp = kmem_zalloc(sizeof(*isp), KM_SLEEP);
if (isp == NULL) {
return NULL;
}
pep = kmem_zalloc(sizeof(*pep) * ncpu, KM_SLEEP);
if (pep == NULL) {
kmem_free(isp, sizeof(*isp));
return NULL;
}
isp->is_saved_evcnt = pep;
for (CPU_INFO_FOREACH(cii, ci)) {
pep->cpuid = ci->ci_cpuid;
pep++;
}
strncpy(isp->is_intrid, intrid, sizeof(isp->is_intrid));
SIMPLEQ_INSERT_TAIL(&io_interrupt_sources, isp, is_list);
return isp;
}
/*
* Remove from io_interrupt_sources list and free by the intrsource pointer.
*/
static void
intr_free_io_intrsource_direct(struct intrsource *isp)
{
KASSERT(mutex_owned(&cpu_lock));
SIMPLEQ_REMOVE(&io_interrupt_sources, isp, intrsource, is_list);
/* Is this interrupt established? */
if (isp->is_evname != '\0')
evcnt_detach(&isp->is_evcnt);
kmem_free(isp->is_saved_evcnt,
sizeof(*(isp->is_saved_evcnt)) * ncpu);
kmem_free(isp, sizeof(*isp));
}
/*
* Remove from io_interrupt_sources list and free by the interrupt id.
* This function can be used by MI code.
*/
void
intr_free_io_intrsource(const char *intrid)
{
struct intrsource *isp;
KASSERT(mutex_owned(&cpu_lock));
if (intrid == NULL)
return;
if ((isp = intr_get_io_intrsource(intrid)) == NULL) {
return;
}
intr_free_io_intrsource_direct(isp);
}
static int
intr_allocate_slot_cpu(struct cpu_info *ci, struct pic *pic, int pin,
int *index)
int *index, struct intrsource *chained)
{
int slot, i;
struct intrsource *isp;
@ -464,14 +609,13 @@ intr_allocate_slot_cpu(struct cpu_info *ci, struct pic *pic, int pin,
isp = ci->ci_isources[slot];
if (isp == NULL) {
isp = kmem_zalloc(sizeof(*isp), KM_SLEEP);
if (isp == NULL) {
return ENOMEM;
}
isp = chained;
KASSERT(isp != NULL);
snprintf(isp->is_evname, sizeof (isp->is_evname),
"pin %d", pin);
evcnt_attach_dynamic(&isp->is_evcnt, EVCNT_TYPE_INTR, NULL,
pic->pic_name, isp->is_evname);
isp->is_active_cpu = ci->ci_cpuid;
ci->ci_isources[slot] = isp;
}
@ -484,7 +628,8 @@ intr_allocate_slot_cpu(struct cpu_info *ci, struct pic *pic, int pin,
*/
static int __noinline
intr_allocate_slot(struct pic *pic, int pin, int level,
struct cpu_info **cip, int *index, int *idt_slot)
struct cpu_info **cip, int *index, int *idt_slot,
struct intrsource *chained)
{
CPU_INFO_ITERATOR cii;
struct cpu_info *ci, *lci;
@ -523,7 +668,7 @@ intr_allocate_slot(struct pic *pic, int pin, int level,
* Must be directed to BP.
*/
ci = &cpu_info_primary;
error = intr_allocate_slot_cpu(ci, pic, pin, &slot);
error = intr_allocate_slot_cpu(ci, pic, pin, &slot, chained);
} else {
/*
* Find least loaded AP/BP and try to allocate there.
@ -543,7 +688,7 @@ intr_allocate_slot(struct pic *pic, int pin, int level,
#endif
}
KASSERT(ci != NULL);
error = intr_allocate_slot_cpu(ci, pic, pin, &slot);
error = intr_allocate_slot_cpu(ci, pic, pin, &slot, chained);
/*
* If that did not work, allocate anywhere.
@ -555,7 +700,7 @@ intr_allocate_slot(struct pic *pic, int pin, int level,
continue;
}
error = intr_allocate_slot_cpu(ci, pic,
pin, &slot);
pin, &slot, chained);
if (error == 0) {
break;
}
@ -578,7 +723,6 @@ intr_allocate_slot(struct pic *pic, int pin, int level,
}
if (idtvec == 0) {
evcnt_detach(&ci->ci_isources[slot]->is_evcnt);
kmem_free(ci->ci_isources[slot], sizeof(*(ci->ci_isources[slot])));
ci->ci_isources[slot] = NULL;
return EBUSY;
}
@ -599,9 +743,6 @@ intr_source_free(struct cpu_info *ci, int slot, struct pic *pic, int idtvec)
if (isp->is_handlers != NULL)
return;
ci->ci_isources[slot] = NULL;
evcnt_detach(&isp->is_evcnt);
kmem_free(isp, sizeof(*isp));
ci->ci_isources[slot] = NULL;
if (pic != &i8259_pic)
idt_vec_free(idtvec);
}
@ -705,11 +846,13 @@ intr_establish(int legacy_irq, struct pic *pic, int pin, int type, int level,
struct intrhand **p, *q, *ih;
struct cpu_info *ci;
int slot, error, idt_vec;
struct intrsource *source;
struct intrsource *chained, *source;
#ifdef MULTIPROCESSOR
bool mpsafe = (known_mpsafe || level != IPL_VM);
#endif /* MULTIPROCESSOR */
uint64_t where;
const char *intrstr;
char intrstr_buf[INTRIDBUF];
#ifdef DIAGNOSTIC
if (legacy_irq != -1 && (legacy_irq < 0 || legacy_irq > 15))
@ -725,9 +868,27 @@ intr_establish(int legacy_irq, struct pic *pic, int pin, int type, int level,
return NULL;
}
intrstr = create_intrid(legacy_irq, pic, pin, intrstr_buf,
sizeof(intrstr_buf));
KASSERT(intrstr != NULL);
mutex_enter(&cpu_lock);
error = intr_allocate_slot(pic, pin, level, &ci, &slot, &idt_vec);
/* allocate intrsource pool, if not yet. */
chained = intr_get_io_intrsource(intrstr);
if (chained == NULL) {
chained = intr_allocate_io_intrsource(intrstr);
if (chained == NULL) {
mutex_exit(&cpu_lock);
printf("%s: can't allocate io_intersource\n", __func__);
return NULL;
}
}
error = intr_allocate_slot(pic, pin, level, &ci, &slot, &idt_vec,
chained);
if (error != 0) {
intr_free_io_intrsource_direct(chained);
mutex_exit(&cpu_lock);
kmem_free(ih, sizeof(*ih));
printf("failed to allocate interrupt slot for PIC %s pin %d\n",
@ -739,6 +900,7 @@ intr_establish(int legacy_irq, struct pic *pic, int pin, int type, int level,
if (source->is_handlers != NULL &&
source->is_pic->pic_type != pic->pic_type) {
intr_free_io_intrsource_direct(chained);
mutex_exit(&cpu_lock);
kmem_free(ih, sizeof(*ih));
printf("%s: can't share intr source between "
@ -761,9 +923,10 @@ intr_establish(int legacy_irq, struct pic *pic, int pin, int type, int level,
/* FALLTHROUGH */
case IST_PULSE:
if (type != IST_NONE) {
intr_source_free(ci, slot, pic, idt_vec);
intr_free_io_intrsource_direct(chained);
mutex_exit(&cpu_lock);
kmem_free(ih, sizeof(*ih));
intr_source_free(ci, slot, pic, idt_vec);
printf("%s: pic %s pin %d: can't share "
"type %d with %d\n",
__func__, pic->pic_name, pin,
@ -902,6 +1065,19 @@ intr_disestablish_xcall(void *arg1, void *arg2)
#endif
}
static int
intr_num_handlers(struct intrsource *isp)
{
struct intrhand *ih;
int num;
num = 0;
for (ih = isp->is_handlers; ih != NULL; ih = ih->ih_next)
num++;
return num;
}
/*
* Deregister an interrupt handler.
*/
@ -909,6 +1085,7 @@ void
intr_disestablish(struct intrhand *ih)
{
struct cpu_info *ci;
struct intrsource *isp;
uint64_t where;
/*
@ -920,16 +1097,39 @@ intr_disestablish(struct intrhand *ih)
ci = ih->ih_cpu;
(ci->ci_nintrhand)--;
KASSERT(ci->ci_nintrhand >= 0);
isp = ci->ci_isources[ih->ih_slot];
if (ci == curcpu() || !mp_online) {
intr_disestablish_xcall(ih, NULL);
} else {
where = xc_unicast(0, intr_disestablish_xcall, ih, NULL, ci);
xc_wait(where);
}
if (intr_num_handlers(isp) < 1) {
intr_free_io_intrsource_direct(isp);
}
mutex_exit(&cpu_lock);
kmem_free(ih, sizeof(*ih));
}
static const char *
legacy_intr_string(int ih, char *buf, size_t len, struct pic *pic)
{
int legacy_irq;
KASSERT(pic->pic_type == PIC_I8259);
KASSERT(APIC_IRQ_ISLEGACY(ih));
legacy_irq = APIC_IRQ_LEGACY_IRQ(ih);
KASSERT(legacy_irq >= 0 && legacy_irq < 16);
snprintf(buf, len, "%s pin %d", pic->pic_name, legacy_irq);
return buf;
}
const char *
intr_string(int ih, char *buf, size_t len)
{
@ -940,7 +1140,6 @@ intr_string(int ih, char *buf, size_t len)
if (ih == 0)
panic("%s: bogus handle 0x%x", __func__, ih);
#if NIOAPIC > 0
if (ih & APIC_INT_VIA_APIC) {
pic = ioapic_find(APIC_IRQ_APIC(ih));
@ -1179,6 +1378,46 @@ softint_init_md(lwp_t *l, u_int level, uintptr_t *machdep)
intr_calculatemasks(ci);
}
/*
* Save current affinitied cpu's interrupt count.
*/
static void
intr_save_evcnt(struct intrsource *source, cpuid_t cpuid)
{
struct percpu_evcnt *pep;
uint64_t curcnt;
int i;
curcnt = source->is_evcnt.ev_count;
pep = source->is_saved_evcnt;
for (i = 0; i < ncpu; i++) {
if (pep[i].cpuid == cpuid) {
pep[i].count = curcnt;
break;
}
}
}
/*
* Restore current affinitied cpu's interrupt count.
*/
static void
intr_restore_evcnt(struct intrsource *source, cpuid_t cpuid)
{
struct percpu_evcnt *pep;
int i;
pep = source->is_saved_evcnt;
for (i = 0; i < ncpu; i++) {
if (pep[i].cpuid == cpuid) {
source->is_evcnt.ev_count = pep[i].count;
break;
}
}
}
static void
intr_redistribute_xc_t(void *arg1, void *arg2)
{
@ -1352,6 +1591,9 @@ intr_redistribute(struct cpu_info *oci)
nci->ci_nintrhand++;
ih->ih_cpu = nci;
}
intr_save_evcnt(isp, oci->ci_cpuid);
intr_restore_evcnt(isp, nci->ci_cpuid);
isp->is_active_cpu = nci->ci_cpuid;
return true;
}
@ -1386,3 +1628,263 @@ cpu_intr_count(struct cpu_info *ci)
return ci->ci_nintrhand;
}
static int
intr_find_unused_slot(struct cpu_info *ci, int *index)
{
int slot, i;
KASSERT(mutex_owned(&cpu_lock));
slot = -1;
for (i = 0; i < MAX_INTR_SOURCES ; i++) {
if (ci->ci_isources[i] == NULL) {
slot = i;
break;
}
}
if (slot == -1) {
DPRINTF(("cannot allocate ci_isources\n"));
return EBUSY;
}
*index = slot;
return 0;
}
/*
* Let cpu_info ready to accept the interrupt.
*/
static void
intr_activate_xcall(void *arg1, void *arg2)
{
struct cpu_info *ci;
struct intrsource *source;
struct intrstub *stubp;
struct intrhand *ih;
u_long psl;
int idt_vec;
int slot;
ih = arg1;
kpreempt_disable();
KASSERT(ih->ih_cpu == curcpu() || !mp_online);
ci = ih->ih_cpu;
slot = ih->ih_slot;
source = ci->ci_isources[slot];
idt_vec = source->is_idtvec;
psl = x86_read_psl();
x86_disable_intr();
intr_calculatemasks(ci);
if (source->is_type == IST_LEVEL) {
stubp = &source->is_pic->pic_level_stubs[slot];
} else {
stubp = &source->is_pic->pic_edge_stubs[slot];
}
source->is_resume = stubp->ist_resume;
source->is_recurse = stubp->ist_recurse;
setgate(&idt[idt_vec], stubp->ist_entry, 0, SDT_SYS386IGT,
SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
x86_write_psl(psl);
kpreempt_enable();
}
/*
* Let cpu_info not accept the interrupt.
*/
static void
intr_deactivate_xcall(void *arg1, void *arg2)
{
struct cpu_info *ci;
struct intrhand *ih, *lih;
u_long psl;
int slot;
ih = arg1;
kpreempt_disable();
KASSERT(ih->ih_cpu == curcpu() || !mp_online);
ci = ih->ih_cpu;
slot = ih->ih_slot;
psl = x86_read_psl();
x86_disable_intr();
/* Move all devices sharing IRQ number. */
ci->ci_isources[slot] = NULL;
for (lih = ih; lih != NULL; lih = lih->ih_next) {
ci->ci_nintrhand--;
}
intr_calculatemasks(ci);
/*
* Skip unsetgate(), because the same itd[] entry is overwritten in
* intr_activate_xcall().
*/
x86_write_psl(psl);
kpreempt_enable();
}
static void
intr_get_affinity(struct intrsource *isp, kcpuset_t *cpuset)
{
struct cpu_info *ci;
KASSERT(mutex_owned(&cpu_lock));
if (isp == NULL) {
kcpuset_zero(cpuset);
return;
}
ci = isp->is_handlers->ih_cpu;
if (ci == NULL) {
kcpuset_zero(cpuset);
return;
}
kcpuset_set(cpuset, cpu_index(ci));
return;
}
static int
intr_set_affinity(struct intrsource *isp, const kcpuset_t *cpuset)
{
struct cpu_info *oldci, *newci;
struct intrhand *ih, *lih;
struct pic *pic;
u_int cpu_idx;
int idt_vec;
int oldslot, newslot;
int err;
int pin;
KASSERT(mutex_owned(&cpu_lock));
/* XXX
* logical destination mode is not supported, use lowest index cpu.
*/
cpu_idx = kcpuset_ffs(cpuset) - 1;
newci = cpu_lookup(cpu_idx);
if (newci == NULL) {
DPRINTF(("invalid cpu index: %u\n", cpu_idx));
return EINVAL;
}
if ((newci->ci_schedstate.spc_flags & SPCF_NOINTR) != 0) {
DPRINTF(("the cpu is set nointr shield. index:%u\n", cpu_idx));
return EINVAL;
}
if (isp == NULL) {
DPRINTF(("invalid intrctl handler\n"));
return EINVAL;
}
/* i8259_pic supports only primary cpu, see i8259.c. */
pic = isp->is_pic;
if (pic == &i8259_pic) {
DPRINTF(("i8259 pic does not support set_affinity\n"));
return ENOTSUP;
}
ih = isp->is_handlers;
oldci = ih->ih_cpu;
if (newci == oldci) /* nothing to do */
return 0;
oldslot = ih->ih_slot;
idt_vec = isp->is_idtvec;
err = intr_find_unused_slot(newci, &newslot);
if (err) {
DPRINTF(("failed to allocate interrupt slot for PIC %s intrid %s\n",
isp->is_pic->pic_name, isp->is_intrid));
return err;
}
pin = isp->is_pin;
(*pic->pic_hwmask)(pic, pin); /* for ci_ipending check */
if (oldci->ci_ipending & (1 << oldslot)) {
(*pic->pic_hwunmask)(pic, pin);
DPRINTF(("pin %d on cpuid %ld has pending interrupts.\n",
pin, oldci->ci_cpuid));
return EBUSY;
}
kpreempt_disable();
/* deactivate old interrupt setting */
if (oldci == curcpu() || !mp_online) {
intr_deactivate_xcall(ih, NULL);
} else {
uint64_t where;
where = xc_unicast(0, intr_deactivate_xcall, ih,
NULL, oldci);
xc_wait(where);
}
intr_save_evcnt(isp, oldci->ci_cpuid);
(*pic->pic_delroute)(pic, oldci, pin, idt_vec, isp->is_type);
/* activate new interrupt setting */
newci->ci_isources[newslot] = isp;
for (lih = ih; lih != NULL; lih = lih->ih_next) {
newci->ci_nintrhand++;
lih->ih_cpu = newci;
lih->ih_slot = newslot;
}
if (newci == curcpu() || !mp_online) {
intr_activate_xcall(ih, NULL);
} else {
uint64_t where;
where = xc_unicast(0, intr_activate_xcall, ih,
NULL, newci);
xc_wait(where);
}
intr_restore_evcnt(isp, newci->ci_cpuid);
isp->is_active_cpu = newci->ci_cpuid;
(*pic->pic_addroute)(pic, newci, pin, idt_vec, isp->is_type);
kpreempt_enable();
(*pic->pic_hwunmask)(pic, pin);
return err;
}
int
intr_distribute(struct intrhand *ih, const kcpuset_t *newset, kcpuset_t *oldset)
{
struct intrsource *isp;
int ret, slot;
if (ih == NULL)
return EINVAL;
mutex_enter(&cpu_lock);
slot = ih->ih_slot;
isp = ih->ih_cpu->ci_isources[slot];
KASSERT(isp != NULL);
if (oldset != NULL)
intr_get_affinity(isp, oldset);
ret = intr_set_affinity(isp, newset);
mutex_exit(&cpu_lock);
return ret;
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: kern_stub.c,v 1.38 2013/12/09 18:06:27 pooka Exp $ */
/* $NetBSD: kern_stub.c,v 1.39 2015/04/27 06:42:53 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.38 2013/12/09 18:06:27 pooka Exp $");
__KERNEL_RCSID(0, "$NetBSD: kern_stub.c,v 1.39 2015/04/27 06:42:53 knakahara Exp $");
#include "opt_ptrace.h"
#include "opt_ktrace.h"
@ -147,6 +147,8 @@ __weak_alias(userconf_prompt, voidop);
__weak_alias(kobj_renamespace, nullop);
__weak_alias(pci_intr_distribute, eopnotsupp);
/*
* Scheduler activations system calls. These need to remain until libc's
* major version is bumped.

View File

@ -1,4 +1,4 @@
/* $NetBSD: intr.h,v 1.17 2014/05/25 15:42:01 rmind Exp $ */
/* $NetBSD: intr.h,v 1.18 2015/04/27 06:42:53 knakahara Exp $ */
/*-
* Copyright (c) 2007 The NetBSD Foundation, Inc.
@ -32,6 +32,8 @@
#ifndef _SYS_INTR_H_
#define _SYS_INTR_H_
#define INTRIDBUF 64
#ifdef _KERNEL
#include <sys/types.h>