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; +}