Module Name:    src
Committed By:   nonaka
Date:           Wed Oct 19 00:08:42 UTC 2016

Modified Files:
        src/sys/arch/bebox/pci: pci_machdep.c
        src/sys/arch/evbppc/pmppc/pci: pci_machdep.c
        src/sys/arch/ibmnws/pci: pci_machdep.c
        src/sys/arch/macppc/pci: pci_machdep.c
        src/sys/arch/mvmeppc/pci: pci_machdep.c
        src/sys/arch/ofppc/pci: ofwpci.c
        src/sys/arch/powerpc/booke: e500_intr.c
        src/sys/arch/powerpc/booke/pci: pq3pci.c
        src/sys/arch/powerpc/ibm4xx/dev: ibm405gp.c
        src/sys/arch/powerpc/include: cpu.h intr.h pci_machdep.h
        src/sys/arch/powerpc/include/booke: intr.h
        src/sys/arch/powerpc/marvell: pci_machdep.c
        src/sys/arch/powerpc/pci: pci_machdep_common.c
        src/sys/arch/powerpc/pic: intr.c
        src/sys/arch/powerpc/powerpc: intr_stubs.c
        src/sys/arch/prep/pci: pci_machdep.c prep_pciconf_direct.c
        src/sys/arch/sandpoint/include: pci_machdep.h
        src/sys/arch/sandpoint/pci: pci_machdep.c

Log Message:
Added MSI/MSI-X and interrupt_distribute(9) support for powerpc.


To generate a diff of this commit:
cvs rdiff -u -r1.21 -r1.22 src/sys/arch/bebox/pci/pci_machdep.c
cvs rdiff -u -r1.5 -r1.6 src/sys/arch/evbppc/pmppc/pci/pci_machdep.c
cvs rdiff -u -r1.9 -r1.10 src/sys/arch/ibmnws/pci/pci_machdep.c
cvs rdiff -u -r1.40 -r1.41 src/sys/arch/macppc/pci/pci_machdep.c
cvs rdiff -u -r1.10 -r1.11 src/sys/arch/mvmeppc/pci/pci_machdep.c
cvs rdiff -u -r1.12 -r1.13 src/sys/arch/ofppc/pci/ofwpci.c
cvs rdiff -u -r1.33 -r1.34 src/sys/arch/powerpc/booke/e500_intr.c
cvs rdiff -u -r1.21 -r1.22 src/sys/arch/powerpc/booke/pci/pq3pci.c
cvs rdiff -u -r1.7 -r1.8 src/sys/arch/powerpc/ibm4xx/dev/ibm405gp.c
cvs rdiff -u -r1.101 -r1.102 src/sys/arch/powerpc/include/cpu.h
cvs rdiff -u -r1.11 -r1.12 src/sys/arch/powerpc/include/intr.h
cvs rdiff -u -r1.13 -r1.14 src/sys/arch/powerpc/include/pci_machdep.h
cvs rdiff -u -r1.9 -r1.10 src/sys/arch/powerpc/include/booke/intr.h
cvs rdiff -u -r1.5 -r1.6 src/sys/arch/powerpc/marvell/pci_machdep.c
cvs rdiff -u -r1.20 -r1.21 src/sys/arch/powerpc/pci/pci_machdep_common.c
cvs rdiff -u -r1.24 -r1.25 src/sys/arch/powerpc/pic/intr.c
cvs rdiff -u -r1.4 -r1.5 src/sys/arch/powerpc/powerpc/intr_stubs.c
cvs rdiff -u -r1.41 -r1.42 src/sys/arch/prep/pci/pci_machdep.c
cvs rdiff -u -r1.9 -r1.10 src/sys/arch/prep/pci/prep_pciconf_direct.c
cvs rdiff -u -r1.9 -r1.10 src/sys/arch/sandpoint/include/pci_machdep.h
cvs rdiff -u -r1.34 -r1.35 src/sys/arch/sandpoint/pci/pci_machdep.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/bebox/pci/pci_machdep.c
diff -u src/sys/arch/bebox/pci/pci_machdep.c:1.21 src/sys/arch/bebox/pci/pci_machdep.c:1.22
--- src/sys/arch/bebox/pci/pci_machdep.c:1.21	Fri Jul  1 20:34:53 2011
+++ src/sys/arch/bebox/pci/pci_machdep.c	Wed Oct 19 00:08:41 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: pci_machdep.c,v 1.21 2011/07/01 20:34:53 dyoung Exp $	*/
+/*	$NetBSD: pci_machdep.c,v 1.22 2016/10/19 00:08:41 nonaka Exp $	*/
 
 /*
  * Copyright (c) 1996 Christopher G. Demetriou.  All rights reserved.
@@ -39,7 +39,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: pci_machdep.c,v 1.21 2011/07/01 20:34:53 dyoung Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pci_machdep.c,v 1.22 2016/10/19 00:08:41 nonaka Exp $");
 
 #include <sys/types.h>
 #include <sys/param.h>
@@ -87,6 +87,16 @@ bebox_pci_get_chipset_tag(pci_chipset_ta
 	pc->pc_intr_establish = genppc_pci_intr_establish;
 	pc->pc_intr_disestablish = genppc_pci_intr_disestablish;
 	pc->pc_intr_setattr = genppc_pci_intr_setattr;
+	pc->pc_intr_type = genppc_pci_intr_type;
+	pc->pc_intr_alloc = genppc_pci_intr_alloc;
+	pc->pc_intr_release = genppc_pci_intr_release;
+	pc->pc_intx_alloc = genppc_pci_intx_alloc;
+
+	pc->pc_msi_v = (void *)pc;
+	genppc_pci_chipset_msi_init(pc);
+
+	pc->pc_msix_v = (void *)pc;
+	genppc_pci_chipset_msix_init(pc);
 
 	pc->pc_conf_interrupt = bebox_pci_conf_interrupt;
 	pc->pc_decompose_tag = genppc_pci_indirect_decompose_tag;

Index: src/sys/arch/evbppc/pmppc/pci/pci_machdep.c
diff -u src/sys/arch/evbppc/pmppc/pci/pci_machdep.c:1.5 src/sys/arch/evbppc/pmppc/pci/pci_machdep.c:1.6
--- src/sys/arch/evbppc/pmppc/pci/pci_machdep.c:1.5	Thu Jun 30 00:52:56 2011
+++ src/sys/arch/evbppc/pmppc/pci/pci_machdep.c	Wed Oct 19 00:08:41 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: pci_machdep.c,v 1.5 2011/06/30 00:52:56 matt Exp $	*/
+/*	$NetBSD: pci_machdep.c,v 1.6 2016/10/19 00:08:41 nonaka Exp $	*/
 
 /*
  * Copyright (c) 1996 Christopher G. Demetriou.  All rights reserved.
@@ -43,7 +43,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: pci_machdep.c,v 1.5 2011/06/30 00:52:56 matt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pci_machdep.c,v 1.6 2016/10/19 00:08:41 nonaka Exp $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -104,6 +104,16 @@ pmppc_pci_get_chipset_tag(pci_chipset_ta
 	pc->pc_intr_establish = genppc_pci_intr_establish;
 	pc->pc_intr_disestablish = genppc_pci_intr_disestablish;
 	pc->pc_intr_setattr = genppc_pci_intr_setattr;
+	pc->pc_intr_type = genppc_pci_intr_type;
+	pc->pc_intr_alloc = genppc_pci_intr_alloc;
+	pc->pc_intr_release = genppc_pci_intr_release;
+	pc->pc_intx_alloc = genppc_pci_intx_alloc;
+
+	pc->pc_msi_v = (void *)pc;
+	genppc_pci_chipset_msi_init(pc);
+
+	pc->pc_msix_v = (void *)pc;
+	genppc_pci_chipset_msix_init(pc);
 
 	pc->pc_conf_interrupt = pmppc_pci_conf_interrupt;
 	pc->pc_decompose_tag = genppc_pci_indirect_decompose_tag;

Index: src/sys/arch/ibmnws/pci/pci_machdep.c
diff -u src/sys/arch/ibmnws/pci/pci_machdep.c:1.9 src/sys/arch/ibmnws/pci/pci_machdep.c:1.10
--- src/sys/arch/ibmnws/pci/pci_machdep.c:1.9	Fri Jul  1 20:47:43 2011
+++ src/sys/arch/ibmnws/pci/pci_machdep.c	Wed Oct 19 00:08:41 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: pci_machdep.c,v 1.9 2011/07/01 20:47:43 dyoung Exp $	*/
+/*	$NetBSD: pci_machdep.c,v 1.10 2016/10/19 00:08:41 nonaka Exp $	*/
 
 /*
  * Copyright (c) 1996 Christopher G. Demetriou.  All rights reserved.
@@ -79,6 +79,16 @@ ibmnws_pci_get_chipset_tag_indirect(pci_
 	pc->pc_intr_establish = genppc_pci_intr_establish;
 	pc->pc_intr_disestablish = genppc_pci_intr_disestablish;
 	pc->pc_intr_setattr = genppc_pci_intr_setattr;
+	pc->pc_intr_type = genppc_pci_intr_type;
+	pc->pc_intr_alloc = genppc_pci_intr_alloc;
+	pc->pc_intr_release = genppc_pci_intr_release;
+	pc->pc_intx_alloc = genppc_pci_intx_alloc;
+
+	pc->pc_msi_v = (void *)pc;
+	genppc_pci_chipset_msi_init(pc);
+
+	pc->pc_msix_v = (void *)pc;
+	genppc_pci_chipset_msix_init(pc);
 
 	pc->pc_conf_interrupt = genppc_pci_conf_interrupt;
 	pc->pc_decompose_tag = genppc_pci_indirect_decompose_tag;

Index: src/sys/arch/macppc/pci/pci_machdep.c
diff -u src/sys/arch/macppc/pci/pci_machdep.c:1.40 src/sys/arch/macppc/pci/pci_machdep.c:1.41
--- src/sys/arch/macppc/pci/pci_machdep.c:1.40	Fri Jul  1 18:43:05 2011
+++ src/sys/arch/macppc/pci/pci_machdep.c	Wed Oct 19 00:08:41 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: pci_machdep.c,v 1.40 2011/07/01 18:43:05 dyoung Exp $	*/
+/*	$NetBSD: pci_machdep.c,v 1.41 2016/10/19 00:08:41 nonaka Exp $	*/
 
 /*
  * Copyright (c) 1996 Christopher G. Demetriou.  All rights reserved.
@@ -43,7 +43,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: pci_machdep.c,v 1.40 2011/07/01 18:43:05 dyoung Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pci_machdep.c,v 1.41 2016/10/19 00:08:41 nonaka Exp $");
 
 #include <sys/types.h>
 #include <sys/param.h>
@@ -123,6 +123,17 @@ macppc_pci_get_chipset_tag(pci_chipset_t
 	pc->pc_intr_evcnt = genppc_pci_intr_evcnt;
 	pc->pc_intr_establish = genppc_pci_intr_establish;
 	pc->pc_intr_disestablish = genppc_pci_intr_disestablish;
+	pc->pc_intr_setattr = genppc_pci_intr_setattr;
+	pc->pc_intr_type = genppc_pci_intr_type;
+	pc->pc_intr_alloc = genppc_pci_intr_alloc;
+	pc->pc_intr_release = genppc_pci_intr_release;
+	pc->pc_intx_alloc = genppc_pci_intx_alloc;
+
+	pc->pc_msi_v = (void *)pc;
+	genppc_pci_chipset_msi_init(pc);
+
+	pc->pc_msix_v = (void *)pc;
+	genppc_pci_chipset_msix_init(pc);
 
 	pc->pc_conf_interrupt = genppc_pci_conf_interrupt;
 	pc->pc_conf_hook = genppc_pci_conf_hook;

Index: src/sys/arch/mvmeppc/pci/pci_machdep.c
diff -u src/sys/arch/mvmeppc/pci/pci_machdep.c:1.10 src/sys/arch/mvmeppc/pci/pci_machdep.c:1.11
--- src/sys/arch/mvmeppc/pci/pci_machdep.c:1.10	Fri Jul  1 20:49:38 2011
+++ src/sys/arch/mvmeppc/pci/pci_machdep.c	Wed Oct 19 00:08:41 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: pci_machdep.c,v 1.10 2011/07/01 20:49:38 dyoung Exp $	*/
+/*	$NetBSD: pci_machdep.c,v 1.11 2016/10/19 00:08:41 nonaka Exp $	*/
 
 /*
  * Copyright (c) 1996 Christopher G. Demetriou.  All rights reserved.
@@ -39,7 +39,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: pci_machdep.c,v 1.10 2011/07/01 20:49:38 dyoung Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pci_machdep.c,v 1.11 2016/10/19 00:08:41 nonaka Exp $");
 
 #include <sys/types.h>
 #include <sys/param.h>
@@ -88,6 +88,16 @@ mvmeppc_pci_get_chipset_tag(pci_chipset_
 	pc->pc_intr_establish = genppc_pci_intr_establish;
 	pc->pc_intr_disestablish = genppc_pci_intr_disestablish;
 	pc->pc_intr_setattr = genppc_pci_intr_setattr;
+	pc->pc_intr_type = genppc_pci_intr_type;
+	pc->pc_intr_alloc = genppc_pci_intr_alloc;
+	pc->pc_intr_release = genppc_pci_intr_release;
+	pc->pc_intx_alloc = genppc_pci_intx_alloc;
+
+	pc->pc_msi_v = (void *)pc;
+	genppc_pci_chipset_msi_init(pc);
+
+	pc->pc_msix_v = (void *)pc;
+	genppc_pci_chipset_msix_init(pc);
 
 	pc->pc_conf_interrupt = mvmeppc_pci_conf_interrupt;
 	pc->pc_decompose_tag = genppc_pci_indirect_decompose_tag;

Index: src/sys/arch/ofppc/pci/ofwpci.c
diff -u src/sys/arch/ofppc/pci/ofwpci.c:1.12 src/sys/arch/ofppc/pci/ofwpci.c:1.13
--- src/sys/arch/ofppc/pci/ofwpci.c:1.12	Fri Feb 28 05:50:27 2014
+++ src/sys/arch/ofppc/pci/ofwpci.c	Wed Oct 19 00:08:41 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: ofwpci.c,v 1.12 2014/02/28 05:50:27 matt Exp $ */
+/* $NetBSD: ofwpci.c,v 1.13 2016/10/19 00:08:41 nonaka Exp $ */
 
 /*-
  * Copyright (c) 2007 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ofwpci.c,v 1.12 2014/02/28 05:50:27 matt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ofwpci.c,v 1.13 2016/10/19 00:08:41 nonaka Exp $");
 
 #include "opt_pci.h"
 
@@ -83,6 +83,17 @@ ofwpci_get_chipset_tag(pci_chipset_tag_t
 	pc->pc_intr_evcnt = genppc_pci_intr_evcnt;
 	pc->pc_intr_establish = genppc_pci_intr_establish;
 	pc->pc_intr_disestablish = genppc_pci_intr_disestablish;
+	pc->pc_intr_setattr = genppc_pci_intr_setattr;
+	pc->pc_intr_type = genppc_pci_intr_type;
+	pc->pc_intr_alloc = genppc_pci_intr_alloc;
+	pc->pc_intr_release = genppc_pci_intr_release;
+	pc->pc_intx_alloc = genppc_pci_intx_alloc;
+
+	pc->pc_msi_v = (void *)pc;
+	genppc_pci_chipset_msi_init(pc);
+
+	pc->pc_msix_v = (void *)pc;
+	genppc_pci_chipset_msix_init(pc);
 
 	pc->pc_conf_interrupt = genppc_pci_conf_interrupt;
 	pc->pc_decompose_tag = genppc_pci_ofmethod_decompose_tag;

Index: src/sys/arch/powerpc/booke/e500_intr.c
diff -u src/sys/arch/powerpc/booke/e500_intr.c:1.33 src/sys/arch/powerpc/booke/e500_intr.c:1.34
--- src/sys/arch/powerpc/booke/e500_intr.c:1.33	Tue Apr 14 22:36:54 2015
+++ src/sys/arch/powerpc/booke/e500_intr.c	Wed Oct 19 00:08:41 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: e500_intr.c,v 1.33 2015/04/14 22:36:54 jmcneill Exp $	*/
+/*	$NetBSD: e500_intr.c,v 1.34 2016/10/19 00:08:41 nonaka Exp $	*/
 /*-
  * Copyright (c) 2010, 2011 The NetBSD Foundation, Inc.
  * All rights reserved.
@@ -41,7 +41,7 @@
 #define __INTR_PRIVATE
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: e500_intr.c,v 1.33 2015/04/14 22:36:54 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: e500_intr.c,v 1.34 2016/10/19 00:08:41 nonaka Exp $");
 
 #include <sys/param.h>
 #include <sys/proc.h>
@@ -53,6 +53,7 @@ __KERNEL_RCSID(0, "$NetBSD: e500_intr.c,
 #include <sys/xcall.h>
 #include <sys/ipi.h>
 #include <sys/bitops.h>
+#include <sys/interrupt.h>
 
 #include <uvm/uvm_extern.h>
 
@@ -88,11 +89,14 @@ struct intr_source {
 	uint8_t is_refcnt;
 	bus_size_t is_vpr;
 	bus_size_t is_dr;
+	char is_source[INTRIDBUF];
+	char is_xname[INTRDEVNAMEBUF];
 };
 
 #define	INTR_SOURCE_INITIALIZER \
 	{ .is_func = e500_intr_spurious, .is_arg = NULL, \
-	.is_irq = -1, .is_ipl = IPL_NONE, .is_ist = IST_NONE, }
+	.is_irq = -1, .is_ipl = IPL_NONE, .is_ist = IST_NONE, \
+	.is_source = "", .is_xname = "", }
 
 struct e500_intr_name {
 	uint8_t in_irq;
@@ -403,7 +407,8 @@ static const char ist_names[][12] = {
 static struct intr_source *e500_intr_sources;
 static const struct intr_source *e500_intr_last_source;
 
-static void 	*e500_intr_establish(int, int, int, int (*)(void *), void *);
+static void 	*e500_intr_establish(int, int, int, int (*)(void *), void *,
+		    const char *);
 static void 	e500_intr_disestablish(void *);
 static void 	e500_intr_cpu_attach(struct cpu_info *ci);
 static void 	e500_intr_cpu_hatch(struct cpu_info *ci);
@@ -420,6 +425,7 @@ static void 	e500_wdogintr(struct trapfr
 static void	e500_spl0(void);
 static int 	e500_splraise(int);
 static void 	e500_splx(int);
+static const char *e500_intr_all_name_lookup(int, int);
 
 const struct intrsw e500_intrsw = {
 	.intrsw_establish = e500_intr_establish,
@@ -724,7 +730,7 @@ e500_intr_typename(int ist)
 
 static void *
 e500_intr_cpu_establish(struct cpu_info *ci, int irq, int ipl, int ist,
-	int (*handler)(void *), void *arg)
+	int (*handler)(void *), void *arg, const char *xname)
 {
 	struct cpu_softc * const cpu = ci->ci_softc;
 	struct e500_intr_irq_info ii;
@@ -738,6 +744,12 @@ e500_intr_cpu_establish(struct cpu_info 
 		return NULL;
 	}
 
+	if (xname == NULL) {
+		xname = e500_intr_all_name_lookup(irq, ist);
+		if (xname == NULL)
+			xname = "unknown";
+	}
+
 	struct intr_source * const is = &e500_intr_sources[ii.irq_vector];
 	mutex_enter(&e500_intr_lock);
 	if (is->is_ipl != IPL_NONE) {
@@ -761,6 +773,34 @@ e500_intr_cpu_establish(struct cpu_info 
 	is->is_refcnt++;
 	is->is_vpr = ii.irq_vpr;
 	is->is_dr = ii.irq_dr;
+	switch (ist) {
+	case IST_EDGE:
+	case IST_LEVEL_LOW:
+	case IST_LEVEL_HIGH:
+		snprintf(is->is_source, sizeof(is->is_source), "extirq %d",
+		    irq);
+		break;
+	case IST_ONCHIP:
+		snprintf(is->is_source, sizeof(is->is_source), "irq %d", irq);
+		break;
+	case IST_MSIGROUP:
+		snprintf(is->is_source, sizeof(is->is_source), "msigroup %d",
+		    irq);
+		break;
+	case IST_TIMER:
+		snprintf(is->is_source, sizeof(is->is_source), "timer %d", irq);
+		break;
+	case IST_IPI:
+		snprintf(is->is_source, sizeof(is->is_source), "ipi %d", irq);
+		break;
+	case IST_MI:
+		snprintf(is->is_source, sizeof(is->is_source), "mi %d", irq);
+		break;
+	case IST_PULSE:
+	default:
+		panic("%s: invalid ist (%d)\n", __func__, ist);
+	}
+	strlcpy(is->is_xname, xname, sizeof(is->is_xname));
 
 	uint32_t vpr = VPR_PRIORITY_MAKE(IPL2CTPR(ipl))
 	    | VPR_VECTOR_MAKE(((ii.irq_vector + 1) << 4) | ipl)
@@ -801,10 +841,11 @@ e500_intr_cpu_establish(struct cpu_info 
 }
 
 static void *
-e500_intr_establish(int irq, int ipl, int ist,
-	int (*handler)(void *), void *arg)
+e500_intr_establish(int irq, int ipl, int ist, int (*handler)(void *),
+    void *arg, const char *xname)
 {
-	return e500_intr_cpu_establish(curcpu(), irq, ipl, ist, handler, arg);
+	return e500_intr_cpu_establish(curcpu(), irq, ipl, ist, handler, arg,
+	    xname);
 }
 
 static void
@@ -1329,6 +1370,7 @@ e500_ipi_intr(void *v)
 static void
 e500_intr_cpu_hatch(struct cpu_info *ci)
 {
+	char iname[INTRIDBUF];
 
 	/* Initialize percpu interupts. */
 	e500_intr_init_precpu();
@@ -1336,15 +1378,16 @@ e500_intr_cpu_hatch(struct cpu_info *ci)
 	/*
 	 * Establish clock interrupt for this CPU.
 	 */
+	snprintf(iname, sizeof(iname), "%s clock", device_xname(ci->ci_dev));
 	if (e500_intr_cpu_establish(ci, E500_CLOCK_TIMER, IPL_CLOCK, IST_TIMER,
-	    e500_clock_intr, NULL) == NULL)
+	    e500_clock_intr, NULL, iname) == NULL)
 		panic("%s: failed to establish clock interrupt!", __func__);
 
 	/*
 	 * Establish the IPI interrupts for this CPU.
 	 */
 	if (e500_intr_cpu_establish(ci, 0, IPL_VM, IST_IPI, e500_ipi_intr,
-	    NULL) == NULL)
+	    NULL, "ipi") == NULL)
 		panic("%s: failed to establish ipi interrupt!", __func__);
 
 	/*
@@ -1354,3 +1397,352 @@ e500_intr_cpu_hatch(struct cpu_info *ci)
 	tcr |= TCR_WIE;
 	mtspr(SPR_TCR, tcr);
 }
+
+static const char *
+e500_intr_all_name_lookup(int irq, int ist)
+{
+	const struct e500_intr_info * const info = &e500_intr_info;
+
+	switch (ist) {
+	default:
+		if (irq < info->ii_external_sources &&
+		    (ist == IST_EDGE ||
+		     ist == IST_LEVEL_LOW ||
+		     ist == IST_LEVEL_HIGH))
+			return e500_intr_name_lookup(
+			    info->ii_external_intr_names, irq);
+		break;
+
+	case IST_PULSE:
+		break;
+
+	case IST_ONCHIP:
+		if (irq < info->ii_onchip_sources)
+			return e500_intr_onchip_name_lookup(irq);
+		break;
+
+	case IST_MSIGROUP:
+		if (irq < info->ii_msigroup_sources)
+			return e500_intr_name_lookup(e500_msigroup_intr_names,
+			    irq);
+		break;
+
+	case IST_TIMER:
+		if (irq < info->ii_timer_sources)
+			return e500_intr_name_lookup(e500_timer_intr_names,
+			    irq);
+		break;
+
+	case IST_IPI:
+		if (irq < info->ii_ipi_sources)
+			return e500_intr_name_lookup(e500_ipi_intr_names, irq);
+		break;
+
+	case IST_MI:
+		if (irq < info->ii_mi_sources)
+			return e500_intr_name_lookup(e500_mi_intr_names, irq);
+		break;
+	}
+
+	return NULL;
+}
+
+static void
+e500_intr_get_affinity(struct intr_source *is, kcpuset_t *cpuset)
+{
+	struct cpu_info * const ci = curcpu();
+	struct cpu_softc * const cpu = ci->ci_softc;
+	struct e500_intr_irq_info ii;
+
+	kcpuset_zero(cpuset);
+
+	if (is->is_ipl != IPL_NONE && !IST_PERCPU_P(is->is_ist)) {
+		if (e500_intr_irq_info_get(ci, is->is_irq, is->is_ipl,
+		    is->is_ist, &ii)) {
+			uint32_t dr = openpic_read(cpu, ii.irq_dr);
+			while (dr != 0) {
+				u_int n = ffs(dr);
+				if (n-- == 0)
+					break;
+				dr &= ~(1 << n);
+				kcpuset_set(cpuset, n);
+			}
+		}
+	}
+}
+
+static int
+e500_intr_set_affinity(struct intr_source *is, const kcpuset_t *cpuset)
+{
+	struct cpu_info * const ci = curcpu();
+	struct cpu_softc * const cpu = ci->ci_softc;
+	struct e500_intr_irq_info ii;
+	uint32_t ecpuset, tcpuset;
+
+	KASSERT(mutex_owned(&cpu_lock));
+	KASSERT(mutex_owned(&e500_intr_lock));
+	KASSERT(!kcpuset_iszero(cpuset));
+
+	kcpuset_export_u32(cpuset, &ecpuset, sizeof(ecpuset));
+	tcpuset = ecpuset;
+	while (tcpuset != 0) {
+		u_int cpu_idx = ffs(tcpuset);
+		if (cpu_idx-- == 0)
+			break;
+
+		tcpuset &= ~(1 << cpu_idx);
+		struct cpu_info * const newci = cpu_lookup(cpu_idx);
+		if (newci == NULL)
+			return EINVAL;
+		if ((newci->ci_schedstate.spc_flags & SPCF_NOINTR) != 0)
+			return EINVAL;
+	}
+
+	if (!e500_intr_irq_info_get(ci, is->is_irq, is->is_ipl, is->is_ist,
+	    &ii))
+		return ENXIO;
+
+	/*
+	 * Update the vector/priority and destination registers keeping the
+	 * interrupt masked.
+	 */
+	const register_t msr = wrtee(0);	/* disable interrupts */
+
+	uint32_t vpr = openpic_read(cpu, ii.irq_vpr);
+	openpic_write(cpu, ii.irq_vpr, vpr | VPR_MSK);
+
+	/*
+	 * Wait for the Activity (A) bit for the source to be cleared.
+	 */
+	while (openpic_read(cpu, ii.irq_vpr) & VPR_A)
+		continue;
+
+	/*
+	 * Update destination register
+	 */
+	openpic_write(cpu, ii.irq_dr, ecpuset);
+
+	/*
+	 * Now unmask the interrupt.
+	 */
+	openpic_write(cpu, ii.irq_vpr, vpr);
+
+	wrtee(msr);				/* re-enable interrupts */
+
+	return 0;
+}
+
+static bool
+e500_intr_is_affinity_intrsource(struct intr_source *is,
+    const kcpuset_t *cpuset)
+{
+	struct cpu_info * const ci = curcpu();
+	struct cpu_softc * const cpu = ci->ci_softc;
+	struct e500_intr_irq_info ii;
+	bool result = false;
+
+	if (is->is_ipl != IPL_NONE && !IST_PERCPU_P(is->is_ist)) {
+		if (e500_intr_irq_info_get(ci, is->is_irq, is->is_ipl,
+		    is->is_ist, &ii)) {
+			uint32_t dr = openpic_read(cpu, ii.irq_dr);
+			while (dr != 0 && !result) {
+				u_int n = ffs(dr);
+				if (n-- == 0)
+					break;
+				dr &= ~(1 << n);
+				result = kcpuset_isset(cpuset, n);
+			}
+		}
+	}
+	return result;
+}
+
+static struct intr_source *
+e500_intr_get_source(const char *intrid)
+{
+	struct intr_source *is;
+
+	mutex_enter(&e500_intr_lock);
+	for (is = e500_intr_sources; is < e500_intr_last_source; ++is) {
+		if (is->is_source[0] == '\0')
+			continue;
+
+		if (!strncmp(intrid, is->is_source, sizeof(is->is_source) - 1))
+			break;
+	}
+	if (is == e500_intr_last_source)
+		is = NULL;
+	mutex_exit(&e500_intr_lock);
+	return is;
+}
+
+uint64_t
+interrupt_get_count(const char *intrid, u_int cpu_idx)
+{
+	struct cpu_info * const ci = cpu_lookup(cpu_idx);
+	struct cpu_softc * const cpu = ci->ci_softc;
+	struct intr_source *is;
+	struct e500_intr_irq_info ii;
+
+	is = e500_intr_get_source(intrid);
+	if (is == NULL)
+		return 0;
+
+	if (e500_intr_irq_info_get(ci, is->is_irq, is->is_ipl, is->is_ist, &ii))
+		return cpu->cpu_evcnt_intrs[ii.irq_vector].ev_count;
+	return 0;
+}
+
+void
+interrupt_get_assigned(const char *intrid, kcpuset_t *cpuset)
+{
+	struct intr_source *is;
+
+	kcpuset_zero(cpuset);
+
+	is = e500_intr_get_source(intrid);
+	if (is == NULL)
+		return;
+
+	mutex_enter(&e500_intr_lock);
+	e500_intr_get_affinity(is, cpuset);
+	mutex_exit(&e500_intr_lock);
+}
+
+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);
+}
+
+void
+interrupt_get_devname(const char *intrid, char *buf, size_t len)
+{
+	struct intr_source *is;
+
+	if (len == 0)
+		return;
+
+	buf[0] = '\0';
+
+	is = e500_intr_get_source(intrid);
+	if (is != NULL)
+		strlcpy(buf, is->is_xname, len);
+}
+
+struct intrids_handler *
+interrupt_construct_intrids(const kcpuset_t *cpuset)
+{
+	struct intr_source *is;
+	struct intrids_handler *ii_handler;
+	intrid_t *ids;
+	int i, n;
+
+	if (kcpuset_iszero(cpuset))
+		return NULL;
+
+	n = 0;
+	mutex_enter(&e500_intr_lock);
+	for (is = e500_intr_sources; is < e500_intr_last_source; ++is) {
+		if (e500_intr_is_affinity_intrsource(is, cpuset))
+			++n;
+	}
+	mutex_exit(&e500_intr_lock);
+
+	const size_t alloc_size = sizeof(int) + sizeof(intrid_t) * n;
+	ii_handler = kmem_zalloc(alloc_size, KM_SLEEP);
+	if (ii_handler == NULL)
+		return NULL;
+	ii_handler->iih_nids = n;
+	if (n == 0)
+		return ii_handler;
+
+	ids = ii_handler->iih_intrids;
+	mutex_enter(&e500_intr_lock);
+	for (i = 0, is = e500_intr_sources;
+	     i < n && is < e500_intr_last_source;
+	     ++is) {
+		if (!e500_intr_is_affinity_intrsource(is, cpuset))
+			continue;
+
+		if (is->is_source[0] != '\0') {
+			strlcpy(ids[i], is->is_source, sizeof(ids[0]));
+			++i;
+		}
+	}
+	mutex_exit(&e500_intr_lock);
+
+	return ii_handler;
+}
+
+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);
+}
+
+static int
+interrupt_distribute_locked(struct intr_source *is, const kcpuset_t *newset,
+    kcpuset_t *oldset)
+{
+	int error;
+
+	KASSERT(mutex_owned(&cpu_lock));
+
+	if (is->is_ipl == IPL_NONE || IST_PERCPU_P(is->is_ist))
+		return EINVAL;
+
+	mutex_enter(&e500_intr_lock);
+	if (oldset != NULL)
+		e500_intr_get_affinity(is, oldset);
+	error = e500_intr_set_affinity(is, newset);
+	mutex_exit(&e500_intr_lock);
+
+	return error;
+}
+
+int
+interrupt_distribute(void *ich, const kcpuset_t *newset, kcpuset_t *oldset)
+{
+	int error;
+
+	mutex_enter(&cpu_lock);
+	error = interrupt_distribute_locked(ich, newset, oldset);
+	mutex_exit(&cpu_lock);
+
+	return error;
+}
+
+int
+interrupt_distribute_handler(const char *intrid, const kcpuset_t *newset,
+    kcpuset_t *oldset)
+{
+	struct intr_source *is;
+	int error;
+
+	is = e500_intr_get_source(intrid);
+	if (is != NULL) {
+		mutex_enter(&cpu_lock);
+		error = interrupt_distribute_locked(is, newset, oldset);
+		mutex_exit(&cpu_lock);
+	} else
+		error = ENOENT;
+
+	return error;
+}

Index: src/sys/arch/powerpc/booke/pci/pq3pci.c
diff -u src/sys/arch/powerpc/booke/pci/pq3pci.c:1.21 src/sys/arch/powerpc/booke/pci/pq3pci.c:1.22
--- src/sys/arch/powerpc/booke/pci/pq3pci.c:1.21	Fri Oct  2 05:22:51 2015
+++ src/sys/arch/powerpc/booke/pci/pq3pci.c	Wed Oct 19 00:08:41 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: pq3pci.c,v 1.21 2015/10/02 05:22:51 msaitoh Exp $	*/
+/*	$NetBSD: pq3pci.c,v 1.22 2016/10/19 00:08:41 nonaka Exp $	*/
 /*-
  * Copyright (c) 2010, 2011 The NetBSD Foundation, Inc.
  * All rights reserved.
@@ -44,7 +44,7 @@
 
 #include <sys/cdefs.h>
 
-__KERNEL_RCSID(0, "$NetBSD: pq3pci.c,v 1.21 2015/10/02 05:22:51 msaitoh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pq3pci.c,v 1.22 2016/10/19 00:08:41 nonaka Exp $");
 
 #include <sys/param.h>
 #include <sys/device.h>
@@ -55,6 +55,7 @@ __KERNEL_RCSID(0, "$NetBSD: pq3pci.c,v 1
 #include <sys/bitops.h>
 #include <sys/kmem.h>
 #include <sys/malloc.h>	/* for extent */
+#include <sys/once.h>
 
 #include <dev/pci/pcireg.h>
 #include <dev/pci/pcivar.h>
@@ -254,8 +255,9 @@ struct pq3pci_intrsource {
 	SIMPLEQ_HEAD(,pq3pci_intrhand) pis_ihands;
 	struct evcnt pis_ev;
 	struct evcnt pis_ev_spurious;
-	kmutex_t *pis_lock;
+	kmutex_t pis_lock;
 	pci_intr_handle_t pis_handle;
+	char pis_intrname[PCI_INTRSTR_LEN];
 	void *pis_ih;
 };
 
@@ -269,7 +271,7 @@ struct pq3pci_msihand {
 };
 
 struct pq3pci_msigroup {
-	kmutex_t *msig_lock;
+	kmutex_t msig_lock;
 	void *msig_ih;
 	uint32_t msig_free_mask;
 	int msig_ipl;
@@ -299,12 +301,15 @@ static int pq3pci_cpunode_match(device_t
 static void pq3pci_cpunode_attach(device_t, device_t, void *aux);
 static pci_chipset_tag_t pq3pci_pci_chipset_init(struct pq3pci_softc *);
 
+static ONCE_DECL(pq3pci_init_once);
+static kmutex_t pq3pci_intrsources_lock;
+static kmutex_t pq3pci_msigroups_lock;
 static SIMPLEQ_HEAD(,pq3pci_intrsource) pq3pci_intrsources
     = SIMPLEQ_HEAD_INITIALIZER(pq3pci_intrsources);
 static struct pq3pci_msigroup *pq3pci_msigroups[8];
 
 static struct pq3pci_intrsource *
-	pq3pci_intr_source_lookup(struct pq3pci_softc *, pci_intr_handle_t);
+    pq3pci_intr_source_lookup(struct pq3pci_softc *, pci_intr_handle_t);
 
 static const char msi_intr_names[8][32][8] = {
     {
@@ -557,17 +562,6 @@ pq3pci_iwin_setup(struct pq3pci_softc *s
 	return true;
 }
 
-static void
-pq3pci_pch_callout(void *v)
-{
-	struct pq3pci_callhand * const pch = v;
-
-	int s = splraise(pch->pch_ipl);
-	(*pch->pch_ih.ih_func)(pch->pch_ih.ih_arg);
-	splx(s);
-	callout_schedule(&pch->pch_callout, 1);
-}
-
 static int
 pq3pci_msi_spurious_intr(void *v)
 {
@@ -581,14 +575,14 @@ pq3pci_msi_intr(void *v)
 {
 	struct pq3pci_msigroup * const msig = v;
 
-	mutex_spin_enter(msig->msig_lock);
+	mutex_spin_enter(&msig->msig_lock);
 	KASSERT(curcpu()->ci_cpl == msig->msig_ipl);
 	//KASSERT(curcpu()->ci_idepth == 0);
 	uint32_t matches = 0;
 	for (int rv = 0;;) {
 		uint32_t group = cpu_read_4(msig->msig_msir);
 		if (group == 0) {
-			mutex_spin_exit(msig->msig_lock);
+			mutex_spin_exit(&msig->msig_lock);
 			return rv;
 		}
 
@@ -653,7 +647,7 @@ pq3pci_pis_intr(void *v)
 	struct pq3pci_intrhand *pih;
 	int rv = 0;
 
-	mutex_spin_enter(pis->pis_lock);
+	mutex_spin_enter(&pis->pis_lock);
 	pis->pis_ev.ev_count++;
 	SIMPLEQ_FOREACH(pih, &pis->pis_ihands, pih_link) {
 		struct pq3pci_softc * const sc = pih->pih_ih.ih_sc;
@@ -675,26 +669,27 @@ pq3pci_pis_intr(void *v)
 	}
 	if (rv == 0)
 		pis->pis_ev_spurious.ev_count++;
-	mutex_spin_exit(pis->pis_lock);
+	mutex_spin_exit(&pis->pis_lock);
 	return rv;
 }
 
 static void
-pq3pci_intr_source_setup(struct pq3pci_softc *sc,
-	struct pq3pci_intrsource *pis, pci_intr_handle_t handle)
+pq3pci_intr_source_setup(struct pq3pci_softc *sc, struct pq3pci_intrsource *pis,
+    pci_intr_handle_t handle)
 {
-	char buf[PCI_INTRSTR_LEN];
 	SIMPLEQ_INIT(&pis->pis_ihands);
 	pis->pis_handle = handle;
 	pis->pis_ih = intr_establish(PIH_IRQ(handle), IPL_VM, PIH_IST(handle),
 	    pq3pci_pis_intr, pis);
-	pis->pis_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_VM);
+	mutex_init(&pis->pis_lock, MUTEX_DEFAULT, IPL_VM);
 	const char * const intrstr
-	    = intr_string(PIH_IRQ(handle), PIH_IST(handle), buf, sizeof(buf));
-	evcnt_attach_dynamic(&pis->pis_ev, EVCNT_TYPE_INTR,
-	    NULL, intrstr, "intr");
+	    = intr_string(PIH_IRQ(handle), PIH_IST(handle), pis->pis_intrname,
+		sizeof(pis->pis_intrname));
+	evcnt_attach_dynamic(&pis->pis_ev, EVCNT_TYPE_INTR, NULL, intrstr,
+	    "intr");
 	evcnt_attach_dynamic(&pis->pis_ev_spurious, EVCNT_TYPE_INTR,
 	    &pis->pis_ev, intrstr, "spurious intr");
+	KASSERT(mutex_owned(&pq3pci_intrsources_lock));
 	SIMPLEQ_INSERT_TAIL(&pq3pci_intrsources, pis, pis_link);
 }
 
@@ -717,8 +712,8 @@ pq3pci_intrmap_setup(struct pq3pci_softc
 
 	sc->sc_intrmask = prop_number_unsigned_integer_value(pn);
 
-	sc->sc_ih = intr_establish(cnl->cnl_intrs[0], IPL_VM, IST_ONCHIP,
-	    pq3pci_onchip_intr, sc);
+	sc->sc_ih = intr_establish_xname(cnl->cnl_intrs[0], IPL_VM, IST_ONCHIP,
+	    pq3pci_onchip_intr, sc, device_xname(sc->sc_dev));
 	if (sc->sc_ih == NULL)
 		panic("%s: failed to establish interrupt %d\n",
 		    device_xname(sc->sc_dev), cnl->cnl_intrs[0]);
@@ -726,6 +721,16 @@ pq3pci_intrmap_setup(struct pq3pci_softc
 	return true;
 }
 
+static int
+pq3pci_once_init(void)
+{
+
+	mutex_init(&pq3pci_intrsources_lock, MUTEX_DEFAULT, IPL_VM);
+	mutex_init(&pq3pci_msigroups_lock, MUTEX_DEFAULT, IPL_VM);
+
+	return 0;
+}
+
 void
 pq3pci_cpunode_attach(device_t parent, device_t self, void *aux)
 {
@@ -740,6 +745,8 @@ pq3pci_cpunode_attach(device_t parent, d
 	psc->sc_children |= cna->cna_childmask;
 	sc->sc_pcie = strcmp(cnl->cnl_name, "pcie") == 0;
 
+	RUN_ONCE(&pq3pci_init_once, pq3pci_once_init);
+
 	const uint32_t pordevsr = cpu_read_4(GLOBAL_BASE + PORDEVSR);
 	if (sc->sc_pcie) {
 		u_int lanes = e500_truth_decode(cnl->cnl_instance, pordevsr,
@@ -1118,6 +1125,7 @@ pq3pci_conf_write(void *v, pcitag_t tag,
 	mutex_spin_exit(sc->sc_conf_lock);
 }
 
+#ifdef PCI_NETBSD_CONFIGURE
 static int
 pq3pci_conf_hook(void *v, int bus, int dev, int func, pcireg_t id)
 {
@@ -1132,21 +1140,24 @@ pq3pci_conf_hook(void *v, int bus, int d
 	}
 	return PCI_CONF_DEFAULT;
 }
+#endif
 
 static void
 pq3pci_msi_group_setup(struct pq3pci_msigroup *msig, u_int group, int ipl)
 {
+	char buf[12];
 	const char (*intr_names)[8] = msi_intr_names[group];
 
 	KASSERT(ipl == IPL_VM);
+	KASSERT(mutex_owned(&pq3pci_msigroups_lock));
 
-	pq3pci_msigroups[group] = msig;
 	msig->msig_group = group;
 	msig->msig_free_mask = ~0 << (group == 0);
 	msig->msig_ipl = ipl;
-	msig->msig_lock = mutex_obj_alloc(MUTEX_DEFAULT, ipl);
-	msig->msig_ih = intr_establish(msig->msig_group, ipl, IST_MSIGROUP,
-	    pq3pci_msi_intr, msig);
+	mutex_init(&msig->msig_lock, MUTEX_DEFAULT, ipl);
+	snprintf(buf, sizeof(buf), "msi %d-%d", group * 32, group * 32 + 31);
+	msig->msig_ih = intr_establish_xname(msig->msig_group, ipl,
+	    IST_MSIGROUP, pq3pci_msi_intr, msig, buf);
 	msig->msig_msir = OPENPIC_BASE + OPENPIC_MSIR(msig->msig_group);
 	for (u_int i = 0; i < __arraycount(msig->msig_ihands); i++) {
 		struct pq3pci_msihand * const msih = msig->msig_ihands + i;
@@ -1159,16 +1170,44 @@ pq3pci_msi_group_setup(struct pq3pci_msi
 		evcnt_attach_dynamic(&msih->msih_ev_spurious, EVCNT_TYPE_INTR,
 		    &msih->msih_ev, intr_names[i], "spurious intr");
 	}
+	pq3pci_msigroups[group] = msig;
+}
+
+static struct pq3pci_msihand *
+pq3pci_msi_lookup(pci_intr_handle_t handle)
+{
+	const int irq = PIH_IRQ(handle);
+	KASSERT(irq < 256);
+	struct pq3pci_msigroup * const msig = pq3pci_msigroups[irq / 32];
+	KASSERT(msig != NULL);
+	return &msig->msig_ihands[irq & 31];
+}
+
+static struct pq3pci_msihand *
+pq3pci_msi_claim(pci_intr_handle_t handle)
+{
+	const int irq = PIH_IRQ(handle);
+	uint32_t irq_mask = __BIT(irq & 31);
+	KASSERT(irq < 256);
+	struct pq3pci_msigroup * const msig = pq3pci_msigroups[irq / 32];
+	KASSERT(msig != NULL);
+	struct pq3pci_msihand * const msih = &msig->msig_ihands[irq & 31];
+	mutex_spin_enter(&msig->msig_lock);
+	KASSERT(msig->msig_free_mask & irq_mask);
+	msig->msig_free_mask ^= irq_mask;
+	mutex_spin_exit(&msig->msig_lock);
+	return msih;
 }
 
 static pci_intr_handle_t
-pq3pci_msi_alloc(int ipl, u_int rmsi)
+pq3pci_msi_alloc_one(int ipl)
 {
 	size_t freegroup = 0;
-	size_t maplen = __arraycount(pq3pci_msigroups);
-	KASSERT(rmsi <= 5);
+	const size_t maplen = __arraycount(pq3pci_msigroups);
 	uint32_t bitmap[maplen];
+	pci_intr_handle_t handle;
 
+	mutex_spin_enter(&pq3pci_msigroups_lock);
 	for (u_int i = 0; i < maplen; i++) {
 		struct pq3pci_msigroup * const msig = pq3pci_msigroups[i];
 		if (msig == NULL) {
@@ -1192,57 +1231,113 @@ pq3pci_msi_alloc(int ipl, u_int rmsi)
 		uint32_t mapbits = bitmap[i];
 		u_int n = ffs(mapbits);
 		if (n--) {
-			return PIH_MAKE(i * 32 + n, IST_MSI, 0);
+			handle = PIH_MAKE(i * 32 + n, IST_MSI, 0);
+			struct pq3pci_msihand * const msih __diagused =
+			    pq3pci_msi_claim(handle);
+			KASSERT(msih != NULL);
+			mutex_spin_exit(&pq3pci_msigroups_lock);
+			return handle;
 		}
 	}
 
-	if (freegroup-- == 0)
+	if (freegroup-- == 0) {
+		mutex_spin_exit(&pq3pci_msigroups_lock);
 		return 0;
+	}
 
 	struct pq3pci_msigroup * const msig =
-	    kmem_zalloc(sizeof(*msig), KM_SLEEP);
-	KASSERT(msig != NULL);
+	    kmem_zalloc(sizeof(*msig), KM_NOSLEEP);
+	if (msig == NULL) {
+		mutex_spin_exit(&pq3pci_msigroups_lock);
+		return 0;
+	}
 	pq3pci_msi_group_setup(msig, freegroup, ipl);
 	u_int n = ffs(msig->msig_free_mask) - 1;
-	return PIH_MAKE(freegroup * 32 + n, IST_MSI, 0);
+	handle = PIH_MAKE(freegroup * 32 + n, IST_MSI, 0);
+	struct pq3pci_msihand * const msih __diagused =
+	    pq3pci_msi_claim(handle);
+	KASSERT(msih != NULL);
+	mutex_spin_exit(&pq3pci_msigroups_lock);
+	return handle;
 }
 
-static struct pq3pci_msihand *
-pq3pci_msi_lookup(pci_intr_handle_t handle)
+static int
+pq3pci_msi_alloc_vectors(struct pq3pci_softc *sc,
+    const struct pci_attach_args *pa, pci_intr_handle_t **ihps, int count)
 {
-	const int irq = PIH_IRQ(handle);
-	KASSERT(irq < 256);
-	struct pq3pci_msigroup * const msig = pq3pci_msigroups[irq / 32];
-	KASSERT(msig != NULL);
-	return &msig->msig_ihands[irq & 31];
+	pci_intr_handle_t *vectors;
+	struct pq3pci_msihand * msih;
+	pcireg_t msictl;
+	int msioff;
+
+	*ihps = NULL;
+
+	if (!pci_get_capability(pa->pa_pc, pa->pa_tag, PCI_CAP_MSI, &msioff,
+	    NULL))
+		return ENODEV;
+
+	msictl = pci_conf_read(pa->pa_pc, pa->pa_tag, msioff);
+	msictl &= ~PCI_MSI_CTL_MSI_ENABLE;
+	msictl &= ~PCI_MSI_CTL_MME_MASK;
+	pci_conf_write(pa->pa_pc, pa->pa_tag, msioff, msictl);
+
+	const size_t alloc_size = sizeof(*vectors) * count;
+	vectors = kmem_zalloc(alloc_size, KM_SLEEP);
+	if (vectors == NULL)
+		return ENOMEM;
+
+	for (int i = 0; i < count; ++i) {
+		pci_intr_handle_t handle = pq3pci_msi_alloc_one(IPL_VM);
+		if (handle == 0) {
+			for (int j = i - 1; j >= 0; j--) {
+				msih = pq3pci_msi_claim(vectors[j]);
+				msih->msih_tag = 0;
+				msih->msih_msioff = 0;
+			}
+			kmem_free(vectors, alloc_size);
+			return EBUSY;
+		}
+		vectors[i] = handle;
+
+		msih = pq3pci_msi_lookup(handle);
+		msih->msih_tag = pa->pa_tag;
+		msih->msih_msioff = msioff;
+	}
+
+	*ihps = vectors;
+	return 0;
 }
 
-static struct pq3pci_msihand *
-pq3pci_msi_claim(pci_intr_handle_t handle)
+static void
+pq3pci_msi_free_vectors(struct pq3pci_softc *sc, pci_intr_handle_t *ihp,
+    int count)
 {
-	const int irq = PIH_IRQ(handle);
-	uint32_t irq_mask = __BIT(irq & 31);
-	KASSERT(irq < 256);
-	struct pq3pci_msigroup * const msig = pq3pci_msigroups[irq / 32];
-	KASSERT(msig != NULL);
-	struct pq3pci_msihand * const msih = &msig->msig_ihands[irq & 31];
-	mutex_spin_enter(msig->msig_lock);
-	KASSERT(msig->msig_free_mask & irq_mask);
-	msig->msig_free_mask ^= irq_mask;
-	mutex_spin_exit(msig->msig_lock);
-	return msih;
+
+	KASSERT(count > 0);
+
+	for (int i = 0; i < count; ++i) {
+		struct pq3pci_msihand * const msih __diagused =
+		    pq3pci_msi_claim(ihp[i]);
+		KASSERT(msih != NULL);
+	}
+	kmem_free(ihp, sizeof(*ihp) * count);
 }
 
 static struct pq3pci_intrsource *
 pq3pci_intr_source_lookup(struct pq3pci_softc *sc, pci_intr_handle_t handle)
 {
 	struct pq3pci_intrsource *pis;
+	mutex_spin_enter(&pq3pci_intrsources_lock);
 	SIMPLEQ_FOREACH(pis, &pq3pci_intrsources, pis_link) {
-		if (pis->pis_handle == handle)
+		if (pis->pis_handle == handle) {
+			mutex_spin_exit(&pq3pci_intrsources_lock);
 			return pis;
+		}
 	}
-	pis = kmem_zalloc(sizeof(*pis), KM_SLEEP);
-	pq3pci_intr_source_setup(sc, pis, handle);
+	pis = kmem_zalloc(sizeof(*pis), KM_NOSLEEP);
+	if (pis != NULL)
+		pq3pci_intr_source_setup(sc, pis, handle);
+	mutex_spin_exit(&pq3pci_intrsources_lock);
 	return pis;
 }
 
@@ -1252,24 +1347,24 @@ pq3pci_intr_handle_lookup(struct pq3pci_
 {
 	prop_dictionary_t entry;
 
+#ifndef PQ3PCI_INTR_MAP_NO_USE_MSI
 	if (sc->sc_pcie) do {
 		pcireg_t msictl;
 		int msioff;
 		if (!pci_get_capability(pa->pa_pc, pa->pa_tag, PCI_CAP_MSI,
-					&msioff, &msictl))
+					&msioff, NULL))
 			break;
 		msictl = pci_conf_read(pa->pa_pc, pa->pa_tag, msioff);
 		msictl &= ~PCI_MSI_CTL_MSI_ENABLE;
 		msictl &= ~PCI_MSI_CTL_MME_MASK;
-		int rmsi = __SHIFTOUT(msictl, PCI_MSI_CTL_MMC_MASK);
 		pci_conf_write(pa->pa_pc, pa->pa_tag, msioff, msictl);
-		pci_intr_handle_t handle = pq3pci_msi_alloc(IPL_VM, rmsi);
+		pci_intr_handle_t handle = pq3pci_msi_alloc_one(IPL_VM);
 		struct pq3pci_msihand * const msih = pq3pci_msi_lookup(handle);
 		msih->msih_tag = pa->pa_tag;
 		msih->msih_msioff = msioff;
 		return handle;
 	} while (false);
-
+#endif
 
 	if (sc->sc_intrmask == 0) {
 		entry = prop_dictionary_get(sc->sc_intrmap, "000000");
@@ -1333,40 +1428,30 @@ static const struct evcnt *
 pq3pci_intr_evcnt(void *v, pci_intr_handle_t handle)
 {
 	struct pq3pci_softc * const sc = v;
-	struct pq3pci_intrsource * const pis =
-	    pq3pci_intr_source_lookup(sc, handle);
+	if (PIH_IST(handle) == IST_MSI) {
+		struct pq3pci_msihand * const msih = pq3pci_msi_lookup(handle);
 
-	KASSERT(pis != NULL);
+		KASSERT(msih != NULL);
 
-	return &pis->pis_ev;
+		return &msih->msih_ev;
+	}
+	struct pq3pci_intrsource * const pis =
+	    pq3pci_intr_source_lookup(sc, handle);
+	if (pis != NULL)
+		return &pis->pis_ev;
+	return NULL;
 }
 
 static void *
 pq3pci_intr_establish(void *v, pci_intr_handle_t handle, int ipl,
-	int (*func)(void *), void *arg)
+	int (*func)(void *), void *arg, const char *xname)
 {
 	struct pq3pci_softc * const sc = v;
-
-	if (0) {
-		struct pq3pci_callhand * const pch =
-		    kmem_zalloc(sizeof(*pch), KM_SLEEP);
-		KASSERT(pch);
-		pch->pch_ih.ih_arg = arg;
-		pch->pch_ih.ih_func = func;
-		pch->pch_ih.ih_sc = sc;
-		pch->pch_ipl = ipl;
-
-		callout_init(&pch->pch_callout, 0);
-		callout_reset(&pch->pch_callout, 1, pq3pci_pch_callout, pch);
-
-		return pch;
-	}
-
 	const int ist = PIH_IST(handle);
 
 	if (ist == IST_MSI) {
 		pci_chipset_tag_t pc = &sc->sc_pc;
-		struct pq3pci_msihand * const msih = pq3pci_msi_claim(handle);
+		struct pq3pci_msihand * const msih = pq3pci_msi_lookup(handle);
 		pcireg_t cmdsts, msictl;
 
 		if (msih == NULL)
@@ -1375,7 +1460,7 @@ pq3pci_intr_establish(void *v, pci_intr_
 		struct pq3pci_msigroup * const msig = msih->msih_group;
 		const pcitag_t tag = msih->msih_tag;
 
-		mutex_spin_enter(msig->msig_lock);
+		mutex_spin_enter(&msig->msig_lock);
 		msih->msih_ih.ih_class = IH_MSI;
 		msih->msih_ih.ih_arg = arg;
 		msih->msih_ih.ih_func = func;
@@ -1416,7 +1501,7 @@ pq3pci_intr_establish(void *v, pci_intr_
 			off += 4;
 			pci_conf_write(pc, tag, off, 0);
 		}
-		
+
 		/*
 		 * Let's make sure he won't raise any INTx.  Technically
 		 * setting MSI enable will prevent that as well but might
@@ -1434,55 +1519,34 @@ pq3pci_intr_establish(void *v, pci_intr_
 		pci_conf_write(pc, tag, msih->msih_msioff, msictl);
 #endif
 
-		mutex_spin_exit(msig->msig_lock);
-
-#if 0
-		struct pq3pci_callhand * const pch =
-		    kmem_zalloc(sizeof(*pch), KM_SLEEP);
-		KASSERT(pch);
-
-		pch->pch_ih.ih_arg = msig;
-		pch->pch_ih.ih_func = pq3pci_msi_intr;
-#if 1
-		pch->pch_ih.ih_arg = arg;
-		pch->pch_ih.ih_func = func;
-#endif
-		pch->pch_ih.ih_sc = sc;
-		pch->pch_ipl = ipl;
-
-		callout_init(&pch->pch_callout, 0);
-		callout_reset(&pch->pch_callout, 1, pq3pci_pch_callout, pch);
-
-#if 1
-		return pch;
-#endif
-#endif
+		mutex_spin_exit(&msig->msig_lock);
 
 		return msih;
-	} else {
-		struct pq3pci_intrsource * const pis =
-		    pq3pci_intr_source_lookup(sc, handle);
-		KASSERT(pis != NULL);
+	}
+
+	struct pq3pci_intrsource * const pis =
+	    pq3pci_intr_source_lookup(sc, handle);
+	if (pis == NULL)
+		return NULL;
 
-		struct pq3pci_intrhand * const pih =
-		    kmem_zalloc(sizeof(*pih), KM_SLEEP);
+	struct pq3pci_intrhand * const pih =
+	    kmem_zalloc(sizeof(*pih), KM_SLEEP);
 
-		if (pih == NULL)
-			return NULL;
+	if (pih == NULL)
+		return NULL;
 
-		pih->pih_ih.ih_class = IH_INTX;
-		pih->pih_ih.ih_func = func;
-		pih->pih_ih.ih_arg = arg;
-		pih->pih_ih.ih_sc = sc;
-		pih->pih_ipl = ipl;
-		pih->pih_source = pis;
-
-		mutex_spin_enter(pis->pis_lock);
-		SIMPLEQ_INSERT_TAIL(&pis->pis_ihands, pih, pih_link);
-		mutex_spin_exit(pis->pis_lock);
+	pih->pih_ih.ih_class = IH_INTX;
+	pih->pih_ih.ih_func = func;
+	pih->pih_ih.ih_arg = arg;
+	pih->pih_ih.ih_sc = sc;
+	pih->pih_ipl = ipl;
+	pih->pih_source = pis;
+
+	mutex_spin_enter(&pis->pis_lock);
+	SIMPLEQ_INSERT_TAIL(&pis->pis_ihands, pih, pih_link);
+	mutex_spin_exit(&pis->pis_lock);
 
-		return pih;
-	}
+	return pih;
 }
 
 static void
@@ -1494,19 +1558,20 @@ pq3pci_intr_disestablish(void *v, void *
 		struct pq3pci_intrhand * const pih = ih;
 		struct pq3pci_intrsource * const pis = pih->pih_source;
 
-		mutex_spin_enter(pis->pis_lock);
+		mutex_spin_enter(&pis->pis_lock);
 		SIMPLEQ_REMOVE(&pis->pis_ihands, pih, pq3pci_intrhand, pih_link);
-		mutex_spin_exit(pis->pis_lock);
+		mutex_spin_exit(&pis->pis_lock);
 
 		kmem_free(pih, sizeof(*pih));
 		return;
 	}
+
 	struct pq3pci_msihand * const msih = ih;
 	struct pq3pci_msigroup * const msig = msih->msih_group;
 	struct genppc_pci_chipset * const pc = &msih->msih_ih.ih_sc->sc_pc;
 	const pcitag_t tag = msih->msih_tag;
 
-	mutex_spin_enter(msig->msig_lock);
+	mutex_spin_enter(&msig->msig_lock);
 
 	/*
 	 * disable the MSI
@@ -1520,7 +1585,102 @@ pq3pci_intr_disestablish(void *v, void *
 	msih->msih_ih.ih_sc = NULL;
 	msih->msih_tag = 0;
 	msih->msih_msioff = 0;
-	mutex_spin_exit(msig->msig_lock);
+	mutex_spin_exit(&msig->msig_lock);
+}
+
+static pci_intr_type_t
+pq3pci_intr_type(void *v, pci_intr_handle_t handle)
+{
+	const int ist = PIH_IST(handle);
+
+	if (ist == IST_MSI)
+		return PCI_INTR_TYPE_MSI;
+	return PCI_INTR_TYPE_INTX;
+}
+
+static int
+pq3pci_intr_alloc(const struct pci_attach_args *pa, pci_intr_handle_t **ihps,
+    int *counts, pci_intr_type_t max_type)
+{
+	int cnt[PCI_INTR_TYPE_SIZE];
+	int error;
+
+	memset(cnt, 0, sizeof(cnt));
+	if (counts == NULL) {
+		/* simple pattern */
+		cnt[PCI_INTR_TYPE_INTX] = 1;
+		cnt[PCI_INTR_TYPE_MSI] = 1;
+	} else {
+		switch (max_type) {
+		case PCI_INTR_TYPE_MSIX:
+			cnt[PCI_INTR_TYPE_MSIX] = counts[PCI_INTR_TYPE_MSIX];
+			/*FALLTHROUGH*/
+		case PCI_INTR_TYPE_MSI:
+			cnt[PCI_INTR_TYPE_MSI] = counts[PCI_INTR_TYPE_MSI];
+			/*FALLTHROUGH*/
+		case PCI_INTR_TYPE_INTX:
+			cnt[PCI_INTR_TYPE_INTX] = counts[PCI_INTR_TYPE_INTX];
+			break;
+		default:
+			return EINVAL;
+		}
+	}
+
+	if (counts != NULL)
+		memset(counts, 0, sizeof(counts[0]) * (max_type + 1));
+	error = EINVAL;
+
+	/* try MSI-X */
+	if (cnt[PCI_INTR_TYPE_MSIX] == -1) /* use hardware max */
+		cnt[PCI_INTR_TYPE_MSIX] = pci_msix_count(pa->pa_pc, pa->pa_tag);
+	if (cnt[PCI_INTR_TYPE_MSIX] > 0) {
+		error = pci_msix_alloc_exact(pa, ihps, cnt[PCI_INTR_TYPE_MSIX]);
+		if (error == 0) {
+			KASSERTMSG(counts != NULL,
+			    "If MSI-X is used, counts must not be NULL.");
+			counts[PCI_INTR_TYPE_MSIX] = cnt[PCI_INTR_TYPE_MSIX];
+			goto out;
+		}
+	}
+
+	/* try MSI */
+	if (cnt[PCI_INTR_TYPE_MSI] == -1) /* use hardware max */
+		cnt[PCI_INTR_TYPE_MSI] = pci_msi_count(pa->pa_pc, pa->pa_tag);
+	if (cnt[PCI_INTR_TYPE_MSI] > 0) {
+		error = pci_msi_alloc_exact(pa, ihps, cnt[PCI_INTR_TYPE_MSI]);
+		if (error == 0) {
+			if (counts != NULL) {
+				counts[PCI_INTR_TYPE_MSI] =
+				    cnt[PCI_INTR_TYPE_MSI];
+			}
+			goto out;
+		}
+	}
+
+	/* try INTx */
+	if (cnt[PCI_INTR_TYPE_INTX] > 0) {
+		error = pci_intx_alloc(pa, ihps);
+		if (error == 0 && counts != NULL) {
+			counts[PCI_INTR_TYPE_INTX] = 1;
+		}
+	}
+
+ out:
+	return error;
+}
+
+static void
+pq3pci_intr_release(void *v, pci_intr_handle_t *ihps, int count)
+{
+
+	if (ihps == NULL)
+		return;
+
+	const int ist = PIH_IST(*ihps);
+	if (ist == IST_MSI)
+		pq3pci_msi_free_vectors(v, ihps, count);
+	else
+		genppc_pci_intr_release(v, ihps, count);
 }
 
 static void
@@ -1528,6 +1688,50 @@ pq3pci_conf_interrupt(void *v, int bus, 
 {
 }
 
+/* experimental MSI support */
+
+/*
+ * This function is used by device drivers like pci_intr_map().
+ *
+ * "ihps" is the array of vector numbers which MSI used instead of IRQ number.
+ * "count" must be powr of 2.
+ * "count" can decrease if sturct intrsource cannot be allocated.
+ * if count == 0, return non-zero value.
+ */
+static int
+pq3pci_msi_alloc(const struct pci_attach_args *pa, pci_intr_handle_t **ihps,
+    int *count, bool exact)
+{
+	struct pq3pci_softc * const sc = pa->pa_pc->pc_msi_v;
+	int hw_max;
+	int error;
+
+	if (*count < 1)
+		return EINVAL;
+	if (((*count - 1) & *count) != 0)
+		return EINVAL;
+
+	hw_max = pci_msi_count(pa->pa_pc, pa->pa_tag);
+	if (hw_max == 0)
+		return ENODEV;
+
+	if (*count > hw_max)
+		*count = hw_max;
+
+	*ihps = NULL;
+	for (; *count > 0; (*count) >>= 1) {
+		error = pq3pci_msi_alloc_vectors(sc, pa, ihps, *count);
+		if (error == 0)
+			break;
+		if (exact)
+			return error;
+	}
+	if (*ihps == NULL)
+		return ENXIO;
+
+	return 0;
+}
+
 static pci_chipset_tag_t
 pq3pci_pci_chipset_init(struct pq3pci_softc *sc)
 {
@@ -1535,48 +1739,42 @@ pq3pci_pci_chipset_init(struct pq3pci_so
 
 	pc->pc_conf_v = sc;
 	pc->pc_attach_hook = pq3pci_attach_hook;
-        pc->pc_bus_maxdevs = pq3pci_bus_maxdevs;
-        pc->pc_make_tag = pq3pci_make_tag;
-        pc->pc_conf_read = pq3pci_conf_read;
-        pc->pc_conf_write = pq3pci_conf_write;
+	pc->pc_bus_maxdevs = pq3pci_bus_maxdevs;
+	pc->pc_make_tag = pq3pci_make_tag;
+	pc->pc_conf_read = pq3pci_conf_read;
+	pc->pc_conf_write = pq3pci_conf_write;
 #ifdef PCI_NETBSD_CONFIGURE
-        pc->pc_conf_hook = pq3pci_conf_hook;
+	pc->pc_conf_hook = pq3pci_conf_hook;
 #endif
 
-        pc->pc_intr_v = sc;
-        pc->pc_intr_map = pq3pci_intr_map;
-        pc->pc_intr_string = pq3pci_intr_string;
-        pc->pc_intr_evcnt = pq3pci_intr_evcnt;
-        pc->pc_intr_establish = pq3pci_intr_establish;
-        pc->pc_intr_disestablish = pq3pci_intr_disestablish;
-        pc->pc_conf_interrupt = pq3pci_conf_interrupt;
+	pc->pc_intr_v = sc;
+	pc->pc_intr_map = pq3pci_intr_map;
+	pc->pc_intr_string = pq3pci_intr_string;
+	pc->pc_intr_evcnt = pq3pci_intr_evcnt;
+	pc->pc_intr_establish = pq3pci_intr_establish;
+	pc->pc_intr_disestablish = pq3pci_intr_disestablish;
+	pc->pc_intr_type = pq3pci_intr_type;
+	pc->pc_intr_alloc = pq3pci_intr_alloc;
+	pc->pc_intr_release = pq3pci_intr_release;
+	pc->pc_intx_alloc = genppc_pci_intx_alloc;
 
 	pc->pc_msi_v = sc;
-	genppc_pci_chipset_msi_init(pc);
-#if 0
-	pc->pc_msi_request = pq3pci_msi_request;
-	pc->pc_msi_available = pq3pci_msi_available;
-	pc->pc_msi_type = pq3pci_msi_type;
-	pc->pc_msi_string = pq3pci_msi_string;
-	pc->pc_msi_evcnt = genppc_pci_msi_evcnt;
-	pc->pc_msi_establish = pq3pci_msi_establish;
-	pc->pc_msix_establish = pq3pci_msix_establish;
-	pc->pc_msi_disestablish = pq3pci_msi_disestablish;
-	pc->pc_msi_release = pq3pci_msi_release;
-	pc->pc_msi_free = pq3pci_msi_free;
-#endif
+	pc->pc_msi_alloc = pq3pci_msi_alloc;
+
+	pc->pc_msix_v = sc;
+	genppc_pci_chipset_msix_init(pc);
 
-        pc->pc_decompose_tag = pq3pci_decompose_tag;
-        pc->pc_conf_hook = pq3pci_conf_hook;
+	pc->pc_conf_interrupt = pq3pci_conf_interrupt;
+	pc->pc_decompose_tag = pq3pci_decompose_tag;
 
 	/*
 	 * This is a horrible kludge but it makes life easier.
 	 */
-        pc->pc_addr = (void *)(sc->sc_bsh + PEX_CONFIG_ADDR);
-        pc->pc_data = (void *)(sc->sc_bsh + PEX_CONFIG_DATA);
-        pc->pc_bus = 0;
-        pc->pc_memt = &sc->sc_pci_mem_bst.bs_tag;
-        pc->pc_iot = &sc->sc_pci_io_bst.bs_tag;
+	pc->pc_addr = (void *)(sc->sc_bsh + PEX_CONFIG_ADDR);
+	pc->pc_data = (void *)(sc->sc_bsh + PEX_CONFIG_DATA);
+	pc->pc_bus = 0;
+	pc->pc_memt = &sc->sc_pci_mem_bst.bs_tag;
+	pc->pc_iot = &sc->sc_pci_io_bst.bs_tag;
 
 	SIMPLEQ_INIT(&pc->pc_pbi);
 

Index: src/sys/arch/powerpc/ibm4xx/dev/ibm405gp.c
diff -u src/sys/arch/powerpc/ibm4xx/dev/ibm405gp.c:1.7 src/sys/arch/powerpc/ibm4xx/dev/ibm405gp.c:1.8
--- src/sys/arch/powerpc/ibm4xx/dev/ibm405gp.c:1.7	Wed Aug 17 18:52:01 2011
+++ src/sys/arch/powerpc/ibm4xx/dev/ibm405gp.c	Wed Oct 19 00:08:42 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: ibm405gp.c,v 1.7 2011/08/17 18:52:01 matt Exp $	*/
+/*	$NetBSD: ibm405gp.c,v 1.8 2016/10/19 00:08:42 nonaka Exp $	*/
 
 /*
  * Copyright 2001 Wasabi Systems, Inc.
@@ -36,7 +36,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ibm405gp.c,v 1.7 2011/08/17 18:52:01 matt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ibm405gp.c,v 1.8 2016/10/19 00:08:42 nonaka Exp $");
 
 #include <sys/param.h>
 #include <sys/device.h>
@@ -76,10 +76,17 @@ static struct genppc_pci_chipset genppc_
 	.pc_intr_establish =	genppc_pci_intr_establish,
 	.pc_intr_disestablish =	genppc_pci_intr_disestablish,
 	.pc_intr_setattr =	ibm4xx_pci_intr_setattr,
+	.pc_intr_type =		genppc_pci_intr_type,
+	.pc_intr_alloc =	genppc_pci_intr_alloc,
+	.pc_intr_release =	genppc_pci_intr_release,
+	.pc_intx_alloc =	genppc_pci_intx_alloc,
 
 	.pc_msi_v =		&genppc_ibm4xx_chipset,
 	GENPPC_PCI_MSI_INITIALIZER,
 
+	.pc_msix_v =		&genppc_ibm4xx_chipset,
+	GENPPC_PCI_MSIX_INITIALIZER,
+
 	.pc_conf_interrupt =	ibm4xx_pci_conf_interrupt,
 	.pc_decompose_tag =	ibm4xx_pci_decompose_tag,
 	.pc_conf_hook =		ibm4xx_pci_conf_hook,

Index: src/sys/arch/powerpc/include/cpu.h
diff -u src/sys/arch/powerpc/include/cpu.h:1.101 src/sys/arch/powerpc/include/cpu.h:1.102
--- src/sys/arch/powerpc/include/cpu.h:1.101	Fri Jan 23 07:27:05 2015
+++ src/sys/arch/powerpc/include/cpu.h	Wed Oct 19 00:08:42 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: cpu.h,v 1.101 2015/01/23 07:27:05 nonaka Exp $	*/
+/*	$NetBSD: cpu.h,v 1.102 2016/10/19 00:08:42 nonaka Exp $	*/
 
 /*
  * Copyright (C) 1999 Wolfgang Solfrank.
@@ -51,7 +51,7 @@ struct cache_info {
 #endif
 
 #ifdef _KERNEL
-#include <machine/intr.h>
+#include <sys/intr.h>
 #include <sys/device_if.h>
 #include <sys/evcnt.h>
 #endif

Index: src/sys/arch/powerpc/include/intr.h
diff -u src/sys/arch/powerpc/include/intr.h:1.11 src/sys/arch/powerpc/include/intr.h:1.12
--- src/sys/arch/powerpc/include/intr.h:1.11	Fri Aug 23 06:18:14 2013
+++ src/sys/arch/powerpc/include/intr.h	Wed Oct 19 00:08:42 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: intr.h,v 1.11 2013/08/23 06:18:14 matt Exp $ */
+/*	$NetBSD: intr.h,v 1.12 2016/10/19 00:08:42 nonaka Exp $ */
 
 /*-
  * Copyright (c) 2007 Michael Lorenz
@@ -28,7 +28,7 @@
 
 #ifndef _LOCORE
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: intr.h,v 1.11 2013/08/23 06:18:14 matt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: intr.h,v 1.12 2016/10/19 00:08:42 nonaka Exp $");
 #endif
 
 #ifndef _POWERPC_INTR_MACHDEP_H_
@@ -61,6 +61,8 @@ __KERNEL_RCSID(0, "$NetBSD: intr.h,v 1.1
 
 #if !defined(_LOCORE)
 void *	intr_establish(int, int, int, int (*)(void *), void *);
+void *	intr_establish_xname(int, int, int, int (*)(void *), void *,
+	    const char *);
 void	intr_disestablish(void *);
 const char *
 	intr_typename(int);
@@ -85,6 +87,7 @@ struct intrhand {
 	struct	intrhand *ih_next;
 	int	ih_ipl;
 	int	ih_virq;
+	char	ih_xname[INTRDEVNAMEBUF];
 };
 
 void softint_fast_dispatch(struct lwp *, int);

Index: src/sys/arch/powerpc/include/pci_machdep.h
diff -u src/sys/arch/powerpc/include/pci_machdep.h:1.13 src/sys/arch/powerpc/include/pci_machdep.h:1.14
--- src/sys/arch/powerpc/include/pci_machdep.h:1.13	Sat Mar 29 19:28:29 2014
+++ src/sys/arch/powerpc/include/pci_machdep.h	Wed Oct 19 00:08:42 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: pci_machdep.h,v 1.13 2014/03/29 19:28:29 christos Exp $ */
+/* $NetBSD: pci_machdep.h,v 1.14 2016/10/19 00:08:42 nonaka Exp $ */
 
 /*-
  * Copyright (c) 2002,2007 The NetBSD Foundation, Inc.
@@ -39,12 +39,12 @@
  */
 
 #define __HAVE_PCI_CONF_HOOK
+#define __HAVE_PCI_MSI_MSIX
 
 /*
  * Types provided to machine-independent PCI code
  */
 typedef struct genppc_pci_chipset *pci_chipset_tag_t;
-typedef void *pci_msi_handle_t;
 typedef int pcitag_t;
 typedef int pci_intr_handle_t;
 
@@ -63,6 +63,13 @@ static inline pci_chipset_tag_t pci_atta
 
 #ifdef _KERNEL
 extern struct powerpc_bus_dma_tag pci_bus_dma_tag;
+
+typedef enum {
+	PCI_INTR_TYPE_INTX = 0,
+	PCI_INTR_TYPE_MSI,
+	PCI_INTR_TYPE_MSIX,
+	PCI_INTR_TYPE_SIZE,
+} pci_intr_type_t;
 #endif
 
 
@@ -83,26 +90,34 @@ 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_establish_xname(pci_chipset_tag_t, pci_intr_handle_t,
+		    int, int (*)(void *), void *, const char *);
 void		pci_intr_disestablish(pci_chipset_tag_t, void *);
 int		pci_intr_map(const struct pci_attach_args *,
 		    pci_intr_handle_t *ihp);
 int		pci_intr_setattr(pci_chipset_tag_t, pci_intr_handle_t *,
 		    int, uint64_t);
 
-int		pci_msi_request(const struct pci_attach_args *,
-		    pci_msi_handle_t *, size_t, int, int);
-int		pci_msi_type(pci_chipset_tag_t, pci_msi_handle_t);
-size_t		pci_msi_available(pci_chipset_tag_t, pci_msi_handle_t);
-const char *	pci_msi_string(pci_chipset_tag_t, pci_msi_handle_t, size_t);
-const struct evcnt *
-		pci_msi_evcnt(pci_chipset_tag_t, pci_msi_handle_t, size_t);
-void *		pci_msi_establish(pci_chipset_tag_t, pci_msi_handle_t, size_t,
-		    int, int (*)(void *), void *);
-void *		pci_msix_establish(pci_chipset_tag_t, pci_msi_handle_t, size_t,
-		    size_t, int, int (*)(void *), void *);
-void		pci_msi_disestablish(pci_chipset_tag_t, void *);
-void		pci_msi_free(pci_chipset_tag_t, pci_msi_handle_t, size_t);
-void		pci_msi_release(pci_chipset_tag_t, pci_msi_handle_t);
+pci_intr_type_t	pci_intr_type(pci_chipset_tag_t, pci_intr_handle_t);
+int		pci_intr_alloc(const struct pci_attach_args *,
+		    pci_intr_handle_t **, int *, pci_intr_type_t);
+void		pci_intr_release(pci_chipset_tag_t, pci_intr_handle_t *, int);
+int		pci_intx_alloc(const struct pci_attach_args *,
+		    pci_intr_handle_t **);
+
+/* experimental MSI support */
+int		pci_msi_alloc(const struct pci_attach_args *,
+		    pci_intr_handle_t **, int *);
+int		pci_msi_alloc_exact(const struct pci_attach_args *,
+		    pci_intr_handle_t **, int);
+
+/* experimental MSI-X support */
+int		pci_msix_alloc(const struct pci_attach_args *,
+		    pci_intr_handle_t **, int *);
+int		pci_msix_alloc_exact(const struct pci_attach_args *,
+		    pci_intr_handle_t **, int);
+int		pci_msix_alloc_map(const struct pci_attach_args *,
+		    pci_intr_handle_t **, u_int *, int);
 
 void		pci_conf_interrupt(pci_chipset_tag_t, int, int, int,
 		    int, int *);
@@ -136,26 +151,27 @@ struct genppc_pci_chipset {
 			    size_t);
 	const struct evcnt *(*pc_intr_evcnt)(void *, pci_intr_handle_t);
 	void		*(*pc_intr_establish)(void *, pci_intr_handle_t,
-			    int, int (*)(void *), void *);
+			    int, int (*)(void *), void *, const char *);
 	void		(*pc_intr_disestablish)(void *, void *);
 	int		(*pc_intr_setattr)(void *, pci_intr_handle_t *,
 			    int, uint64_t);
 
+	pci_intr_type_t	(*pc_intr_type)(void *, pci_intr_handle_t);
+	int		(*pc_intr_alloc)(const struct pci_attach_args *,
+			    pci_intr_handle_t **, int *, pci_intr_type_t);
+	void		(*pc_intr_release)(void *, pci_intr_handle_t *, int);
+	int		(*pc_intx_alloc)(const struct pci_attach_args *,
+			    pci_intr_handle_t **);
+
+	/* experimental MSI support */
 	void		*pc_msi_v;
-	int		(*pc_msi_request)(const struct pci_attach_args *,
-			    pci_msi_handle_t *, size_t, int, int);
-	int		(*pc_msi_type)(void *, pci_msi_handle_t);
-	size_t		(*pc_msi_available)(void *, pci_msi_handle_t);
-	const char *	(*pc_msi_string)(void *, pci_msi_handle_t, size_t);
-	const struct evcnt *
-			(*pc_msi_evcnt)(void *, pci_msi_handle_t, size_t);
-	void *		(*pc_msi_establish)(void *, pci_msi_handle_t, size_t,
-			    int, int (*)(void *), void *);
-	void *		(*pc_msix_establish)(void *, pci_msi_handle_t, size_t,
-			    size_t, int, int (*)(void *), void *);
-	void		(*pc_msi_disestablish)(void *, void *);
-	void		(*pc_msi_free)(void *, pci_msi_handle_t, size_t);
-	void		(*pc_msi_release)(void *, pci_msi_handle_t);
+	int		(*pc_msi_alloc)(const struct pci_attach_args *,
+			    pci_intr_handle_t **, int *, bool);
+
+	/* experimental MSI-X support */
+	void		*pc_msix_v;
+	int		(*pc_msix_alloc)(const struct pci_attach_args *,
+			    pci_intr_handle_t **, u_int *, int *, bool);
 
 	void		(*pc_conf_interrupt)(void *, int, int, int, int, int *);
 	void		(*pc_decompose_tag)(void *, pcitag_t, int *,
@@ -243,7 +259,16 @@ __pci_inline void *
 pci_intr_establish(pci_chipset_tag_t pc, pci_intr_handle_t ih, int ipl,
     int (*handler)(void *), void *arg)
 {
-	return (*pc->pc_intr_establish)(pc->pc_intr_v, ih, ipl, handler, arg);
+	return (*pc->pc_intr_establish)(pc->pc_intr_v, ih, ipl, handler, arg,
+	    NULL);
+}
+
+__pci_inline void *
+pci_intr_establish_xname(pci_chipset_tag_t pc, pci_intr_handle_t ih, int ipl,
+    int (*handler)(void *), void *arg, const char *xname)
+{
+	return (*pc->pc_intr_establish)(pc->pc_intr_v, ih, ipl, handler, arg,
+	    xname);
 }
 
 __pci_inline void
@@ -259,85 +284,89 @@ pci_intr_setattr(pci_chipset_tag_t pc, p
 	return (*pc->pc_intr_setattr)(pc->pc_intr_v, ihp, attr, data);
 }
 
-
-__pci_inline void
-pci_conf_interrupt(pci_chipset_tag_t pc, int bus, int device, int pin,
-    int swiz, int *iline)
+__pci_inline pci_intr_type_t
+pci_intr_type(pci_chipset_tag_t pc, pci_intr_handle_t ih)
 {
-	(*pc->pc_conf_interrupt)(pc->pc_conf_v, bus, device, pin, swiz, iline);
+	return (*pc->pc_intr_type)(pc->pc_intr_v, ih);
 }
 
 __pci_inline int
-pci_conf_hook(pci_chipset_tag_t pc, int bus, int device, int function,
-    pcireg_t id)
+pci_intr_alloc(const struct pci_attach_args *pa, pci_intr_handle_t **ihps,
+    int *count, pci_intr_type_t max_type)
 {
-	return (*pc->pc_conf_hook)(pc->pc_conf_v, bus, device, function, id);
+	pci_chipset_tag_t pc = pci_attach_args_pc(pa);
+	return (*pc->pc_intr_alloc)(pa, ihps, count, max_type);
 }
 
-__pci_inline int
-pci_msi_request(const struct pci_attach_args *pa, pci_msi_handle_t *msihp,
-    size_t nmsi, int ipl, int capid)
+__pci_inline void
+pci_intr_release(pci_chipset_tag_t pc, pci_intr_handle_t *ihp, int count)
 {
-	return (*pci_attach_args_pc(pa)->pc_msi_request)(pa, msihp, nmsi,
-	    ipl, capid);
+	(*pc->pc_intr_release)(pc->pc_intr_v, ihp, count);
 }
 
 __pci_inline int
-pci_msi_type(pci_chipset_tag_t pc, pci_msi_handle_t msih)
+pci_intx_alloc(const struct pci_attach_args *pa, pci_intr_handle_t **ihps)
 {
-	return (*pc->pc_msi_type)(pc->pc_msi_v, msih);
+	pci_chipset_tag_t pc = pci_attach_args_pc(pa);
+	return (*pc->pc_intx_alloc)(pa, ihps);
 }
 
-__pci_inline size_t
-pci_msi_available(pci_chipset_tag_t pc, pci_msi_handle_t msih)
-{
-	return (*pc->pc_msi_available)(pc->pc_msi_v, msih);
-}
 
-__pci_inline const char *
-pci_msi_string(pci_chipset_tag_t pc, pci_msi_handle_t msih, size_t msirq)
+__pci_inline void
+pci_conf_interrupt(pci_chipset_tag_t pc, int bus, int device, int pin,
+    int swiz, int *iline)
 {
-	return (*pc->pc_msi_string)(pc->pc_msi_v, msih, msirq);
+	(*pc->pc_conf_interrupt)(pc->pc_conf_v, bus, device, pin, swiz, iline);
 }
 
-__pci_inline const struct evcnt *
-pci_msi_evcnt(pci_chipset_tag_t pc, pci_msi_handle_t msih, size_t msirq)
+__pci_inline int
+pci_conf_hook(pci_chipset_tag_t pc, int bus, int device, int function,
+    pcireg_t id)
 {
-	return (*pc->pc_msi_evcnt)(pc->pc_msi_v, msih, msirq);
+	return (*pc->pc_conf_hook)(pc->pc_conf_v, bus, device, function, id);
 }
 
-__pci_inline void *
-pci_msi_establish(pci_chipset_tag_t pc, pci_msi_handle_t msih, size_t msirq,
-	int ipl, int (*func)(void *), void *arg)
+
+/* experimental MSI support */
+__pci_inline int
+pci_msi_alloc(const struct pci_attach_args *pa, pci_intr_handle_t **ihps,
+    int *count)
 {
-	return (*pc->pc_msi_establish)(pc->pc_msi_v, msih, msirq, ipl,
-	    func, arg);
+	pci_chipset_tag_t pc = pci_attach_args_pc(pa);
+	return (*pc->pc_msi_alloc)(pa, ihps, count, false);
 }
 
-__pci_inline void *
-pci_msix_establish(pci_chipset_tag_t pc, pci_msi_handle_t msih, size_t vec,
-	size_t msirq, int ipl, int (*func)(void *), void *arg)
+__pci_inline int
+pci_msi_alloc_exact(const struct pci_attach_args *pa, pci_intr_handle_t **ihps,
+    int count)
 {
-	return (*pc->pc_msix_establish)(pc->pc_msi_v, msih, vec, msirq, ipl,
-	    func, arg);
+	pci_chipset_tag_t pc = pci_attach_args_pc(pa);
+	return (*pc->pc_msi_alloc)(pa, ihps, &count, true);
 }
 
-__pci_inline void
-pci_msi_disestablish(pci_chipset_tag_t pc, void *ih)
+/* experimental MSI-X support */
+__pci_inline int
+pci_msix_alloc(const struct pci_attach_args *pa, pci_intr_handle_t **ihps,
+    int *count)
 {
-	(*pc->pc_msi_disestablish)(pc->pc_msi_v, ih);
+	pci_chipset_tag_t pc = pci_attach_args_pc(pa);
+	return (*pc->pc_msix_alloc)(pa, ihps, NULL, count, false);
 }
 
-__pci_inline void
-pci_msi_free(pci_chipset_tag_t pc, pci_msi_handle_t msih, size_t msirq)
+__pci_inline int
+pci_msix_alloc_exact(const struct pci_attach_args *pa, pci_intr_handle_t **ihps,
+    int count)
 {
-	(*pc->pc_msi_free)(pc->pc_msi_v, msih, msirq);
+	pci_chipset_tag_t pc = pci_attach_args_pc(pa);
+	return (*pc->pc_msix_alloc)(pa, ihps, NULL, &count, true);
 }
 
-__pci_inline void
-pci_msi_release(pci_chipset_tag_t pc, pci_msi_handle_t msih)
+__pci_inline int
+pci_msix_alloc_map(const struct pci_attach_args *pa, pci_intr_handle_t **ihps,
+    u_int *table_indexes, int count)
 {
-	(*pc->pc_msi_release)(pc->pc_msi_v, msih);
+	pci_chipset_tag_t pc = pci_attach_args_pc(pa);
+	return (*pc->pc_msix_alloc)(pa, ihps, table_indexes, &count, true);
 }
 
 #undef	__pci_inline
@@ -353,36 +382,31 @@ int genppc_pci_intr_map(const struct pci
 const char *genppc_pci_intr_string(void *, pci_intr_handle_t, char *, size_t);
 const struct evcnt *genppc_pci_intr_evcnt(void *, pci_intr_handle_t);
 void *genppc_pci_intr_establish(void *, pci_intr_handle_t, int, int (*)(void *),
-    void *);
+    void *, const char *);
 void genppc_pci_intr_disestablish(void *, void *);
 int genppc_pci_intr_setattr(void *, pci_intr_handle_t *, int, uint64_t);
+pci_intr_type_t genppc_pci_intr_type(void *, pci_intr_handle_t);
+int genppc_pci_intr_alloc(const struct pci_attach_args *, pci_intr_handle_t **,
+    int *, pci_intr_type_t);
+void genppc_pci_intr_release(void *, pci_intr_handle_t *, int);
+int genppc_pci_intx_alloc(const struct pci_attach_args *, pci_intr_handle_t **);
+
+/* experimental MSI support */
+int genppc_pci_msi_alloc(const struct pci_attach_args *, pci_intr_handle_t **,
+    int *, bool);
+
+/* experimental MSI-X support */
+int genppc_pci_msix_alloc(const struct pci_attach_args *, pci_intr_handle_t **,
+    u_int *, int *, bool);
 
-int genppc_pci_msi_request(const struct pci_attach_args *, pci_msi_handle_t *,
-    size_t, int, int);
-int genppc_pci_msi_type(void *, pci_msi_handle_t);
-size_t genppc_pci_msi_available(void *, pci_msi_handle_t);
-const struct evcnt *genppc_pci_msi_evcnt(void *, pci_msi_handle_t, size_t);
-const char *genppc_pci_msi_string(void *, pci_msi_handle_t, size_t);
-void *genppc_pci_msi_establish(void *, pci_msi_handle_t, size_t,
-    int, int (*)(void *), void *);
-void *genppc_pci_msix_establish(void *, pci_msi_handle_t, size_t,
-    size_t, int, int (*)(void *), void *);
-void genppc_pci_msi_disestablish(void *, void *);
-void genppc_pci_msi_free(void *, pci_msi_handle_t, size_t);
-void genppc_pci_msi_release(void *, pci_msi_handle_t);
-void genppc_pci_chipset_msi_init(pci_chipset_tag_t);
+void genppc_pci_chipset_msi_init(pci_chipset_tag_t pc);
+void genppc_pci_chipset_msix_init(pci_chipset_tag_t pc);
 
 #define GENPPC_PCI_MSI_INITIALIZER \
-	.pc_msi_request = genppc_pci_msi_request, \
-	.pc_msi_type = genppc_pci_msi_type, \
-	.pc_msi_available = genppc_pci_msi_available, \
-	.pc_msi_evcnt = genppc_pci_msi_evcnt, \
-	.pc_msi_string = genppc_pci_msi_string, \
-	.pc_msi_establish = genppc_pci_msi_establish, \
-	.pc_msix_establish = genppc_pci_msix_establish, \
-	.pc_msi_disestablish = genppc_pci_msi_disestablish, \
-	.pc_msi_free = genppc_pci_msi_free, \
-	.pc_msi_release = genppc_pci_msi_release
+	.pc_msi_alloc = genppc_pci_msi_alloc
+
+#define GENPPC_PCI_MSIX_INITIALIZER \
+	.pc_msix_alloc = genppc_pci_msix_alloc
 
 void genppc_pci_conf_interrupt(void *, int, int, int, int, int *);
 int genppc_pci_conf_hook(void *, int, int, int, pcireg_t);

Index: src/sys/arch/powerpc/include/booke/intr.h
diff -u src/sys/arch/powerpc/include/booke/intr.h:1.9 src/sys/arch/powerpc/include/booke/intr.h:1.10
--- src/sys/arch/powerpc/include/booke/intr.h:1.9	Fri Jan 23 07:27:05 2015
+++ src/sys/arch/powerpc/include/booke/intr.h	Wed Oct 19 00:08:42 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: intr.h,v 1.9 2015/01/23 07:27:05 nonaka Exp $	*/
+/*	$NetBSD: intr.h,v 1.10 2016/10/19 00:08:42 nonaka Exp $	*/
 /*-
  * Copyright (c) 2010, 2011 The NetBSD Foundation, Inc.
  * All rights reserved.
@@ -84,6 +84,8 @@
 struct cpu_info;
 
 void 	*intr_establish(int, int, int, int (*)(void *), void *);
+void 	*intr_establish_xname(int, int, int, int (*)(void *), void *,
+	    const char *);
 void 	intr_disestablish(void *);
 void	intr_cpu_attach(struct cpu_info *);
 void	intr_cpu_hatch(struct cpu_info *);
@@ -118,7 +120,8 @@ typedef struct {
 struct trapframe;
 
 struct intrsw {
-	void *(*intrsw_establish)(int, int, int, int (*)(void *), void *);
+	void *(*intrsw_establish)(int, int, int, int (*)(void *), void *,
+	    const char *);
 	void (*intrsw_disestablish)(void *);
 	void (*intrsw_cpu_attach)(struct cpu_info *);
 	void (*intrsw_cpu_hatch)(struct cpu_info *);

Index: src/sys/arch/powerpc/marvell/pci_machdep.c
diff -u src/sys/arch/powerpc/marvell/pci_machdep.c:1.5 src/sys/arch/powerpc/marvell/pci_machdep.c:1.6
--- src/sys/arch/powerpc/marvell/pci_machdep.c:1.5	Fri Jul  5 02:18:37 2013
+++ src/sys/arch/powerpc/marvell/pci_machdep.c	Wed Oct 19 00:08:42 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: pci_machdep.c,v 1.5 2013/07/05 02:18:37 joerg Exp $	*/
+/*	$NetBSD: pci_machdep.c,v 1.6 2016/10/19 00:08:42 nonaka Exp $	*/
 /*
  * Copyright (c) 2009 KIYOHARA Takashi
  * All rights reserved.
@@ -26,7 +26,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: pci_machdep.c,v 1.5 2013/07/05 02:18:37 joerg Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pci_machdep.c,v 1.6 2016/10/19 00:08:42 nonaka Exp $");
 
 #include "gtpci.h"
 #include "pci.h"
@@ -51,7 +51,6 @@ __KERNEL_RCSID(0, "$NetBSD: pci_machdep.
 void gtpci_md_conf_interrupt(void *, int, int, int, int, int *);
 int gtpci_md_conf_hook(void *, int, int, int, pcireg_t);
 
-
 struct genppc_pci_chipset genppc_gtpci0_chipset = {
 	.pc_conf_v = NULL,
 	.pc_attach_hook = gtpci_attach_hook,
@@ -67,14 +66,22 @@ struct genppc_pci_chipset genppc_gtpci0_
 	.pc_intr_establish = genppc_pci_intr_establish,
 	.pc_intr_disestablish = genppc_pci_intr_disestablish,
 	.pc_intr_setattr = genppc_pci_intr_setattr,
+	.pc_intr_type = genppc_pci_intr_type,
+	.pc_intr_alloc = genppc_pci_intr_alloc,
+	.pc_intr_release = genppc_pci_intr_release,
+	.pc_intx_alloc = genppc_pci_intx_alloc,
 
 	.pc_msi_v = &genppc_gtpci0_chipset,
 	GENPPC_PCI_MSI_INITIALIZER,
 
+	.pc_msix_v = &genppc_gtpci0_chipset,
+	GENPPC_PCI_MSIX_INITIALIZER,
+
 	.pc_conf_interrupt = gtpci_md_conf_interrupt,
 	.pc_decompose_tag = gtpci_decompose_tag,
 	.pc_conf_hook = gtpci_md_conf_hook,
 };
+
 struct genppc_pci_chipset genppc_gtpci1_chipset = {
 	.pc_conf_v = NULL,
 	.pc_attach_hook = gtpci_attach_hook,
@@ -90,10 +97,17 @@ struct genppc_pci_chipset genppc_gtpci1_
 	.pc_intr_establish = genppc_pci_intr_establish,
 	.pc_intr_disestablish = genppc_pci_intr_disestablish,
 	.pc_intr_setattr = genppc_pci_intr_setattr,
+	.pc_intr_type = genppc_pci_intr_type,
+	.pc_intr_alloc = genppc_pci_intr_alloc,
+	.pc_intr_release = genppc_pci_intr_release,
+	.pc_intx_alloc = genppc_pci_intx_alloc,
 
 	.pc_msi_v = &genppc_gtpci1_chipset,
 	GENPPC_PCI_MSI_INITIALIZER,
 
+	.pc_msix_v = &genppc_gtpci1_chipset,
+	GENPPC_PCI_MSIX_INITIALIZER,
+
 	.pc_conf_interrupt = gtpci_md_conf_interrupt,
 	.pc_decompose_tag = gtpci_decompose_tag,
 	.pc_conf_hook = gtpci_md_conf_hook,

Index: src/sys/arch/powerpc/pci/pci_machdep_common.c
diff -u src/sys/arch/powerpc/pci/pci_machdep_common.c:1.20 src/sys/arch/powerpc/pci/pci_machdep_common.c:1.21
--- src/sys/arch/powerpc/pci/pci_machdep_common.c:1.20	Sat Mar 29 19:28:29 2014
+++ src/sys/arch/powerpc/pci/pci_machdep_common.c	Wed Oct 19 00:08:42 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: pci_machdep_common.c,v 1.20 2014/03/29 19:28:29 christos Exp $ */
+/* $NetBSD: pci_machdep_common.c,v 1.21 2016/10/19 00:08:42 nonaka Exp $ */
 
 /*-
  * Copyright (c) 2007 The NetBSD Foundation, Inc.
@@ -37,7 +37,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: pci_machdep_common.c,v 1.20 2014/03/29 19:28:29 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pci_machdep_common.c,v 1.21 2016/10/19 00:08:42 nonaka Exp $");
 
 #define _POWERPC_BUS_DMA_PRIVATE
 
@@ -47,6 +47,7 @@ __KERNEL_RCSID(0, "$NetBSD: pci_machdep_
 #include <sys/errno.h>
 #include <sys/extent.h>
 #include <sys/intr.h>
+#include <sys/kmem.h>
 #include <sys/systm.h>
 #include <sys/time.h>
 
@@ -112,7 +113,7 @@ genppc_pci_intr_evcnt(void *v, pci_intr_
 
 void *
 genppc_pci_intr_establish(void *v, pci_intr_handle_t ih, int level,
-    int (*func)(void *), void *arg)
+    int (*func)(void *), void *arg, const char *xname)
 {
 
 #ifdef ICU_LEN
@@ -124,7 +125,7 @@ genppc_pci_intr_establish(void *v, pci_i
 		panic("pci_intr_establish: bogus handle 0x%x", ih);
 #endif
 
-	return intr_establish(ih, IST_LEVEL, level, func, arg);
+	return intr_establish_xname(ih, IST_LEVEL, level, func, arg, xname);
 }
 
 void
@@ -142,6 +143,67 @@ genppc_pci_intr_setattr(void *v, pci_int
 	return ENODEV;
 }
 
+pci_intr_type_t
+genppc_pci_intr_type(void *v, pci_intr_handle_t ih)
+{
+
+	return PCI_INTR_TYPE_INTX;
+}
+
+int
+genppc_pci_intr_alloc(const struct pci_attach_args *pa,
+    pci_intr_handle_t **ihps, int *counts, pci_intr_type_t max_type)
+{
+	pci_intr_handle_t *ihp;
+
+	if (counts != NULL && counts[PCI_INTR_TYPE_INTX] == 0)
+		return EINVAL;
+
+	ihp = kmem_alloc(sizeof(*ihp), KM_SLEEP);
+	if (ihp == NULL)
+		return ENOMEM;
+
+	if (pci_intr_map(pa, ihp)) {
+		kmem_free(ihp, sizeof(*ihp));
+		return EINVAL;
+	}
+
+	*ihps = ihp;
+	return 0;
+}
+
+void
+genppc_pci_intr_release(void *v, pci_intr_handle_t *pih, int count)
+{
+
+	if (pih == NULL)
+		return;
+
+	KASSERT(count == 1);
+	kmem_free(pih, sizeof(*pih));
+}
+
+int
+genppc_pci_intx_alloc(const struct pci_attach_args *pa,
+    pci_intr_handle_t **ihps)
+{
+	pci_intr_handle_t *handle;
+	int error;
+
+	handle = kmem_zalloc(sizeof(*handle), KM_SLEEP);
+	if (handle == NULL)
+		return ENOMEM;
+
+	error = pci_intr_map(pa, handle);
+	if (error != 0) {
+		kmem_free(handle, sizeof(*handle));
+		return error;
+	}
+
+	*ihps = handle;
+	return 0;
+}
+
 void
 genppc_pci_conf_interrupt(void *v, int bus, int dev, int pin,
     int swiz, int *iline)
@@ -210,82 +272,34 @@ bad:
 	return 1;
 }
 
+/* experimental MSI support */
 int
-genppc_pci_msi_request(const struct pci_attach_args *pa,
-    pci_msi_handle_t *msihp, size_t nmsirq, int ipl, int capid)
+genppc_pci_msi_alloc(const struct pci_attach_args *pa, pci_intr_handle_t **ihps,
+    int *count, bool exact)
 {
+
 	return EOPNOTSUPP;
 }
 
+/* experimental MSI-X support */
 int
-genppc_pci_msi_type(void *v, pci_msi_handle_t msih)
+genppc_pci_msix_alloc(const struct pci_attach_args *pa,
+    pci_intr_handle_t **ihps, u_int *table_indexes, int *count, bool exact)
 {
-	panic("%s", __func__);
-}
-
-size_t
-genppc_pci_msi_available(void *v, pci_msi_handle_t msih)
-{
-	panic("%s", __func__);
-}
-
-const char *
-genppc_pci_msi_string(void *v, pci_msi_handle_t msih, size_t msirq)
-{
-	panic("%s", __func__);
-}
 
-const struct evcnt *
-genppc_pci_msi_evcnt(void *v, pci_msi_handle_t msih, size_t msirq)
-{
-	panic("%s", __func__);
-}
-
-void *
-genppc_pci_msi_establish(void *v, pci_msi_handle_t msih, size_t msirq,
-		    int ipl, int (*func)(void *), void *arg)
-{
-	panic("%s", __func__);
-}
-
-void *
-genppc_pci_msix_establish(void *v, pci_msi_handle_t msih, size_t vec,
-    size_t msirq, int ipl, int (*func)(void *), void *arg)
-{
-	panic("%s", __func__);
-}
-
-void
-genppc_pci_msi_disestablish(void *v, void *ih)
-{
-	panic("%s", __func__);
-}
-
-void
-genppc_pci_msi_free(void *v, pci_msi_handle_t msih, size_t msirq)
-{
-	panic("%s", __func__);
+	return EOPNOTSUPP;
 }
 
 void
-genppc_pci_msi_release(void *v, pci_msi_handle_t msih)
+genppc_pci_chipset_msi_init(pci_chipset_tag_t pc)
 {
-	panic("%s", __func__);
+	pc->pc_msi_alloc = genppc_pci_msi_alloc;
 }
 
 void
-genppc_pci_chipset_msi_init(pci_chipset_tag_t pc)
+genppc_pci_chipset_msix_init(pci_chipset_tag_t pc)
 {
-	pc->pc_msi_request = genppc_pci_msi_request;
-	pc->pc_msi_type = genppc_pci_msi_type;
-	pc->pc_msi_available = genppc_pci_msi_available;
-	pc->pc_msi_evcnt = genppc_pci_msi_evcnt;
-	pc->pc_msi_string = genppc_pci_msi_string;
-	pc->pc_msi_establish = genppc_pci_msi_establish;
-	pc->pc_msix_establish = genppc_pci_msix_establish;
-	pc->pc_msi_disestablish = genppc_pci_msi_disestablish;
-	pc->pc_msi_free = genppc_pci_msi_free;
-	pc->pc_msi_release = genppc_pci_msi_release;
+	pc->pc_msix_alloc = genppc_pci_msix_alloc;
 }
 
 #ifdef __HAVE_PCIIDE_MACHDEP_COMPAT_INTR_ESTABLISH

Index: src/sys/arch/powerpc/pic/intr.c
diff -u src/sys/arch/powerpc/pic/intr.c:1.24 src/sys/arch/powerpc/pic/intr.c:1.25
--- src/sys/arch/powerpc/pic/intr.c:1.24	Thu May 26 17:38:05 2016
+++ src/sys/arch/powerpc/pic/intr.c	Wed Oct 19 00:08:42 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: intr.c,v 1.24 2016/05/26 17:38:05 macallan Exp $ */
+/*	$NetBSD: intr.c,v 1.25 2016/10/19 00:08:42 nonaka Exp $ */
 
 /*-
  * Copyright (c) 2007 Michael Lorenz
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: intr.c,v 1.24 2016/05/26 17:38:05 macallan Exp $");
+__KERNEL_RCSID(0, "$NetBSD: intr.c,v 1.25 2016/10/19 00:08:42 nonaka Exp $");
 
 #include "opt_interrupt.h"
 #include "opt_multiprocessor.h"
@@ -39,6 +39,7 @@ __KERNEL_RCSID(0, "$NetBSD: intr.c,v 1.2
 #include <sys/cpu.h>
 #include <sys/kernel.h>
 #include <sys/kmem.h>
+#include <sys/interrupt.h>
 
 #include <powerpc/psl.h>
 #include <powerpc/pic/picvar.h>
@@ -132,6 +133,13 @@ void *
 intr_establish(int hwirq, int type, int ipl, int (*ih_fun)(void *),
     void *ih_arg)
 {
+	return intr_establish_xname(hwirq, type, ipl, ih_fun, ih_arg, NULL);
+}
+
+void *
+intr_establish_xname(int hwirq, int type, int ipl, int (*ih_fun)(void *),
+    void *ih_arg, const char *xname)
+{
 	struct intrhand **p, *q, *ih;
 	struct pic_ops *pic;
 	static struct intrhand fakehand;
@@ -147,7 +155,6 @@ intr_establish(int hwirq, int type, int 
 
 	pic = find_pic_by_hwirq(hwirq);
 	if (pic == NULL) {
-
 		panic("%s: cannot find a pic for IRQ %d", __func__, hwirq);
 	}
 
@@ -215,6 +222,8 @@ intr_establish(int hwirq, int type, int 
 	ih->ih_next = NULL;
 	ih->ih_ipl = ipl;
 	ih->ih_virq = virq;
+	strlcpy(ih->ih_xname, xname != NULL ? xname : "unknown",
+	    sizeof(ih->ih_xname));
 	*p = ih;
 
 	if (pic->pic_establish_irq != NULL)
@@ -232,7 +241,6 @@ intr_establish(int hwirq, int type, int 
 	 */
 	intr_calculatemasks();
 
-
 	return ih;
 }
 
@@ -718,3 +726,156 @@ genppc_isa_intr_alloc(isa_chipset_tag_t 
 	return 1;
 }
 #endif
+
+static struct intr_source *
+intr_get_source(const char *intrid)
+{
+	struct intr_source *is;
+	int irq;
+
+	for (irq = 0, is = intrsources; irq < NVIRQ; irq++, is++) {
+		if (strcmp(intrid, is->is_source) == 0)
+			return is;
+	}
+	return NULL;
+}
+
+static struct intrhand *
+intr_get_handler(const char *intrid)
+{
+	struct intr_source *is;
+
+	is = intr_get_source(intrid);
+	if (is != NULL)
+		return is->is_hand;
+	return NULL;
+}
+
+uint64_t
+interrupt_get_count(const char *intrid, u_int cpu_idx)
+{
+	struct intr_source *is;
+
+	/* XXX interrupt is always generated by CPU 0 */
+	if (cpu_idx != 0)
+		return 0;
+
+	is = intr_get_source(intrid);
+	if (is != NULL)
+		return is->is_ev.ev_count;
+	return 0;
+}
+
+void
+interrupt_get_assigned(const char *intrid, kcpuset_t *cpuset)
+{
+	struct intr_source *is;
+
+	kcpuset_zero(cpuset);
+
+	is = intr_get_source(intrid);
+	if (is != NULL)
+		kcpuset_set(cpuset, 0);	/* XXX */
+}
+
+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);
+}
+
+void
+interrupt_get_devname(const char *intrid, char *buf, size_t len)
+{
+	struct intrhand *ih;
+
+	if (len == 0)
+		return;
+
+	buf[0] = '\0';
+
+	for (ih = intr_get_handler(intrid); ih != NULL; ih = ih->ih_next) {
+		if (buf[0] != '\0')
+			strlcat(buf, ", ", len);
+		strlcat(buf, ih->ih_xname, len);
+	}
+}
+
+struct intrids_handler *
+interrupt_construct_intrids(const kcpuset_t *cpuset)
+{
+	struct intr_source *is;
+	struct intrids_handler *ii_handler;
+	intrid_t *ids;
+	int i, irq, count;
+
+	if (kcpuset_iszero(cpuset))
+		return NULL;
+	if (!kcpuset_isset(cpuset, 0))	/* XXX */
+		return NULL;
+
+	count = 0;
+	for (irq = 0, is = intrsources; irq < NVIRQ; irq++, is++) {
+		if (is->is_hand != NULL)
+			count++;
+	}
+
+	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;
+	for (irq = 0, is = intrsources; irq < NVIRQ; irq++, is++) {
+		/* Ignore devices attached after counting "count". */
+		if (i >= count)
+			break;
+
+		if (is->is_hand == NULL)
+			continue;
+
+		strncpy(ids[i], is->is_source, sizeof(intrid_t));
+		i++;
+	}
+
+	return ii_handler;
+}
+
+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);
+}
+
+int
+interrupt_distribute(void *ich, const kcpuset_t *newset, kcpuset_t *oldset)
+{
+	return EOPNOTSUPP;
+}
+
+int
+interrupt_distribute_handler(const char *intrid, const kcpuset_t *newset,
+    kcpuset_t *oldset)
+{
+	return EOPNOTSUPP;
+}

Index: src/sys/arch/powerpc/powerpc/intr_stubs.c
diff -u src/sys/arch/powerpc/powerpc/intr_stubs.c:1.4 src/sys/arch/powerpc/powerpc/intr_stubs.c:1.5
--- src/sys/arch/powerpc/powerpc/intr_stubs.c:1.4	Sat Mar 29 19:28:29 2014
+++ src/sys/arch/powerpc/powerpc/intr_stubs.c	Wed Oct 19 00:08:42 2016
@@ -38,7 +38,7 @@
 
 #include <sys/cdefs.h>
 
-__KERNEL_RCSID(0, "$NetBSD: intr_stubs.c,v 1.4 2014/03/29 19:28:29 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: intr_stubs.c,v 1.5 2016/10/19 00:08:42 nonaka Exp $");
 
 #include <sys/param.h>
 #include <sys/cpu.h>
@@ -67,12 +67,24 @@ const struct intrsw *powerpc_intrsw = &n
 
 #define	__stub	__section(".stub") __noprofile
 
-void *intr_establish(int, int, int, int (*)(void *), void *) __stub;
+void *intr_establish(int, int, int, int (*)(void *), void *) __noprofile;
 
 void *
 intr_establish(int irq, int ipl, int ist, int (*func)(void *), void *arg)
 {
-	return (*powerpc_intrsw->intrsw_establish)(irq, ipl, ist, func, arg);
+	return (*powerpc_intrsw->intrsw_establish)(irq, ipl, ist, func, arg,
+	    NULL);
+}
+
+void *intr_establish_xname(int, int, int, int (*)(void *), void *,
+    const char *) __stub;
+
+void *
+intr_establish_xname(int irq, int ipl, int ist, int (*func)(void *), void *arg,
+    const char *xname)
+{
+	return (*powerpc_intrsw->intrsw_establish)(irq, ipl, ist, func, arg,
+	    xname);
 }
 
 void intr_disestablish(void *) __stub;

Index: src/sys/arch/prep/pci/pci_machdep.c
diff -u src/sys/arch/prep/pci/pci_machdep.c:1.41 src/sys/arch/prep/pci/pci_machdep.c:1.42
--- src/sys/arch/prep/pci/pci_machdep.c:1.41	Sat Oct 18 08:33:26 2014
+++ src/sys/arch/prep/pci/pci_machdep.c	Wed Oct 19 00:08:42 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: pci_machdep.c,v 1.41 2014/10/18 08:33:26 snj Exp $	*/
+/*	$NetBSD: pci_machdep.c,v 1.42 2016/10/19 00:08:42 nonaka Exp $	*/
 
 /*
  * Copyright (c) 1996 Christopher G. Demetriou.  All rights reserved.
@@ -39,7 +39,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: pci_machdep.c,v 1.41 2014/10/18 08:33:26 snj Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pci_machdep.c,v 1.42 2016/10/19 00:08:42 nonaka Exp $");
 
 #include <sys/types.h>
 #include <sys/param.h>
@@ -91,10 +91,17 @@ prep_pci_get_chipset_tag_indirect(pci_ch
 	pc->pc_intr_establish = genppc_pci_intr_establish;
 	pc->pc_intr_disestablish = genppc_pci_intr_disestablish;
 	pc->pc_intr_setattr = genppc_pci_intr_setattr;
+	pc->pc_intr_type = genppc_pci_intr_type;
+	pc->pc_intr_alloc = genppc_pci_intr_alloc;
+	pc->pc_intr_release = genppc_pci_intr_release;
+	pc->pc_intx_alloc = genppc_pci_intx_alloc;
 
 	pc->pc_msi_v = (void *)pc;
 	genppc_pci_chipset_msi_init(pc);
 
+	pc->pc_msix_v = (void *)pc;
+	genppc_pci_chipset_msix_init(pc);
+
 	pc->pc_conf_interrupt = genppc_pci_conf_interrupt;
 	pc->pc_decompose_tag = genppc_pci_indirect_decompose_tag;
 	pc->pc_conf_hook = prep_pci_conf_hook;

Index: src/sys/arch/prep/pci/prep_pciconf_direct.c
diff -u src/sys/arch/prep/pci/prep_pciconf_direct.c:1.9 src/sys/arch/prep/pci/prep_pciconf_direct.c:1.10
--- src/sys/arch/prep/pci/prep_pciconf_direct.c:1.9	Fri Oct  2 05:22:52 2015
+++ src/sys/arch/prep/pci/prep_pciconf_direct.c	Wed Oct 19 00:08:42 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: prep_pciconf_direct.c,v 1.9 2015/10/02 05:22:52 msaitoh Exp $	*/
+/*	$NetBSD: prep_pciconf_direct.c,v 1.10 2016/10/19 00:08:42 nonaka Exp $	*/
 
 /*
  * Copyright (c) 2002 Klaus J. Klein.  All rights reserved.
@@ -39,7 +39,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: prep_pciconf_direct.c,v 1.9 2015/10/02 05:22:52 msaitoh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: prep_pciconf_direct.c,v 1.10 2016/10/19 00:08:42 nonaka Exp $");
 
 #include <sys/types.h>
 #include <sys/param.h>
@@ -109,6 +109,17 @@ prep_pci_get_chipset_tag_direct(pci_chip
 	pc->pc_intr_evcnt = genppc_pci_intr_evcnt;
 	pc->pc_intr_establish = genppc_pci_intr_establish;
 	pc->pc_intr_disestablish = genppc_pci_intr_disestablish;
+	pc->pc_intr_setattr = genppc_pci_intr_setattr;
+	pc->pc_intr_type = genppc_pci_intr_type;
+	pc->pc_intr_alloc = genppc_pci_intr_alloc;
+	pc->pc_intr_release = genppc_pci_intr_release;
+	pc->pc_intx_alloc = genppc_pci_intx_alloc;
+
+	pc->pc_msi_v = NULL;
+	genppc_pci_chipset_msi_init(pc);
+
+	pc->pc_msix_v = NULL;
+	genppc_pci_chipset_msix_init(pc);
 
 	pc->pc_conf_interrupt = genppc_pci_conf_interrupt;
 	pc->pc_decompose_tag = prep_pci_direct_decompose_tag;

Index: src/sys/arch/sandpoint/include/pci_machdep.h
diff -u src/sys/arch/sandpoint/include/pci_machdep.h:1.9 src/sys/arch/sandpoint/include/pci_machdep.h:1.10
--- src/sys/arch/sandpoint/include/pci_machdep.h:1.9	Sat Mar 29 19:28:29 2014
+++ src/sys/arch/sandpoint/include/pci_machdep.h	Wed Oct 19 00:08:42 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: pci_machdep.h,v 1.9 2014/03/29 19:28:29 christos Exp $	*/
+/*	$NetBSD: pci_machdep.h,v 1.10 2016/10/19 00:08:42 nonaka Exp $	*/
 
 /*
  * Copyright (c) 1996 Christopher G. Demetriou.  All rights reserved.
@@ -35,6 +35,7 @@
  */
 
 #define	__HAVE_PCIIDE_MACHDEP_COMPAT_INTR_ESTABLISH
+#define	__HAVE_PCI_MSI_MSIX
 
 /*
  * be-specific PCI structure and type definitions.
@@ -56,6 +57,13 @@ typedef int pcitag_t;
 typedef int pci_intr_handle_t;
 extern struct powerpc_bus_dma_tag pci_bus_dma_tag;
 
+typedef enum {
+	PCI_INTR_TYPE_INTX = 0,
+	PCI_INTR_TYPE_MSI,
+	PCI_INTR_TYPE_MSIX,
+	PCI_INTR_TYPE_SIZE,
+} pci_intr_type_t;
+
 /*
  * Functions provided to machine-independent PCI code.
  */
@@ -75,4 +83,31 @@ const char	*pci_intr_string(pci_chipset_
 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_establish_xname(pci_chipset_tag_t, pci_intr_handle_t,
+		    int, int (*)(void *), void *, const char *);
 void		pci_intr_disestablish(pci_chipset_tag_t, void *);
+
+pci_intr_type_t	pci_intr_type(pci_chipset_tag_t, pci_intr_handle_t);
+int		pci_intr_alloc(const struct pci_attach_args *,
+		    pci_intr_handle_t **, int *, pci_intr_type_t);
+void		pci_intr_release(pci_chipset_tag_t, pci_intr_handle_t *, int);
+int		pci_intx_alloc(const struct pci_attach_args *,
+		    pci_intr_handle_t **);
+
+/* experimental MSI support */
+int		pci_msi_alloc(const struct pci_attach_args *,
+		    pci_intr_handle_t **, int *);
+int		pci_msi_alloc_exact(const struct pci_attach_args *,
+		    pci_intr_handle_t **, int);
+
+/* experimental MSI-X support */
+int		pci_msix_alloc(const struct pci_attach_args *,
+		    pci_intr_handle_t **, int *);
+int		pci_msix_alloc_exact(const struct pci_attach_args *,
+		    pci_intr_handle_t **, int);
+int		pci_msix_alloc_map(const struct pci_attach_args *,
+		    pci_intr_handle_t **, u_int *, int);
+
+void		pci_conf_interrupt(pci_chipset_tag_t, int, int, int,
+		    int, int *);
+int		pci_conf_hook(pci_chipset_tag_t, int, int, int, pcireg_t);

Index: src/sys/arch/sandpoint/pci/pci_machdep.c
diff -u src/sys/arch/sandpoint/pci/pci_machdep.c:1.34 src/sys/arch/sandpoint/pci/pci_machdep.c:1.35
--- src/sys/arch/sandpoint/pci/pci_machdep.c:1.34	Fri Oct  2 05:22:52 2015
+++ src/sys/arch/sandpoint/pci/pci_machdep.c	Wed Oct 19 00:08:42 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: pci_machdep.c,v 1.34 2015/10/02 05:22:52 msaitoh Exp $	*/
+/*	$NetBSD: pci_machdep.c,v 1.35 2016/10/19 00:08:42 nonaka Exp $	*/
 
 /*
  * Copyright (c) 1996 Christopher G. Demetriou.  All rights reserved.
@@ -43,7 +43,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: pci_machdep.c,v 1.34 2015/10/02 05:22:52 msaitoh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pci_machdep.c,v 1.35 2016/10/19 00:08:42 nonaka Exp $");
 
 #include "opt_pci.h"
 
@@ -52,6 +52,7 @@ __KERNEL_RCSID(0, "$NetBSD: pci_machdep.
 #include <sys/device.h>
 #include <sys/errno.h>
 #include <sys/extent.h>
+#include <sys/kmem.h>
 #include <sys/malloc.h>
 #include <sys/queue.h>
 #include <sys/systm.h>
@@ -404,7 +405,7 @@ pci_intr_string(pci_chipset_tag_t pc, pc
 }
 
 const struct evcnt *
-pci_intr_evcnt(void *v, pci_intr_handle_t ih)
+pci_intr_evcnt(pci_chipset_tag_t pc, pci_intr_handle_t ih)
 {
 
 	/* XXX for now, no evcnt parent reported */
@@ -425,9 +426,17 @@ pci_intr_setattr(pci_chipset_tag_t pc, p
 }
 
 void *
-pci_intr_establish(void *v, pci_intr_handle_t ih, int level,
+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, NULL);
+}
+
+void *
+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 type;
 
 	if (brdtype == BRD_STORCENTER && ih == 1) {
@@ -439,19 +448,20 @@ pci_intr_establish(void *v, pci_intr_han
 		 * Using an edge-trigger fixes that and triggers the
 		 * interrupt only once during probing.
 		 */
-		 type = IST_EDGE;
+		type = IST_EDGE;
 	} else
 		type = IST_LEVEL;
-	
+
 	/*
 	 * ih is the value assigned in pci_intr_map(), above.
 	 * It's the EPIC IRQ #.
 	 */
-	return intr_establish(ih + I8259_ICU, type, level, func, arg);
+	return intr_establish_xname(ih + I8259_ICU, type, level, func, arg,
+	    xname);
 }
 
 void
-pci_intr_disestablish(void *v, void *cookie)
+pci_intr_disestablish(pci_chipset_tag_t pc, void *cookie)
 {
 
 	intr_disestablish(cookie);
@@ -486,3 +496,63 @@ pci_conf_interrupt(pci_chipset_tag_t pc,
 	}
 }
 #endif
+
+int
+pci_intx_alloc(const struct pci_attach_args *pa, pci_intr_handle_t **ihpp)
+{
+	pci_intr_handle_t *ihp;
+
+	ihp = kmem_alloc(sizeof(*ihp), KM_SLEEP);
+	if (ihp == NULL)
+		return ENOMEM;
+
+	if (pci_intr_map(pa, ihp)) {
+		kmem_free(ihp, sizeof(*ihp));
+		return EINVAL;
+	}
+
+	*ihpp = ihp;
+	return 0;
+}
+
+/* experimental MSI support */
+int
+pci_msi_alloc(const struct pci_attach_args *pa, pci_intr_handle_t **ihps,
+    int *count)
+{
+
+	return EOPNOTSUPP;
+}
+
+int
+pci_msi_alloc_exact(const struct pci_attach_args *pa, pci_intr_handle_t **ihps,
+    int count)
+{
+
+	return EOPNOTSUPP;
+}
+
+/* experimental MSI-X support */
+int
+pci_msix_alloc(const struct pci_attach_args *pa, pci_intr_handle_t **ihps,
+    int *count)
+{
+
+	return EOPNOTSUPP;
+}
+
+int
+pci_msix_alloc_exact(const struct pci_attach_args *pa, pci_intr_handle_t **ihps,
+    int count)
+{
+
+	return EOPNOTSUPP;
+}
+
+int
+pci_msix_alloc_map(const struct pci_attach_args *pa, pci_intr_handle_t **ihps,
+    u_int *table_indexes, int count)
+{
+
+	return EOPNOTSUPP;
+}

Reply via email to