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

This commit is contained in:
nonaka 2016-10-19 00:08:41 +00:00
parent 5b48185605
commit e4a54b4193
21 changed files with 1412 additions and 399 deletions

View File

@ -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_tag_t pc)
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;

View File

@ -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_tag_t pc)
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;

View File

@ -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_chipset_tag_t pc)
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;

View File

@ -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_tag_t pc)
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;

View File

@ -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_tag_t pc)
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;

View File

@ -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->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;

View File

@ -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,v 1.33 2015/04/14 22:36:54 jmcneill Exp
#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 trapframe *tf);
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 *ci, int irq, int ipl, int ist,
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 *ci, int irq, int ipl, int ist,
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 *ci, int irq, int ipl, int ist,
}
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;
}

View File

@ -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.21 2015/10/02 05:22:51 msaitoh Exp $");
#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, cfdata_t, void *aux);
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 *sc, u_int winnum,
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->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 *sc,
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, device_t self, void *aux)
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, int reg, pcireg_t data)
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 dev, int func, pcireg_t id)
}
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_msigroup *msig, u_int group, int ipl)
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_softc *sc,
{
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;
if (PIH_IST(handle) == IST_MSI) {
struct pq3pci_msihand * const msih = pq3pci_msi_lookup(handle);
KASSERT(msih != NULL);
return &msih->msih_ev;
}
struct pq3pci_intrsource * const pis =
pq3pci_intr_source_lookup(sc, handle);
KASSERT(pis != NULL);
return &pis->pis_ev;
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_handle_t handle, int ipl,
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_handle_t handle, int ipl,
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_handle_t handle, int ipl,
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_intrhand * const pih =
kmem_zalloc(sizeof(*pih), KM_SLEEP);
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);
return pih;
}
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);
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);
return pih;
}
static void
@ -1494,19 +1558,20 @@ pq3pci_intr_disestablish(void *v, void *ih)
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 *ih)
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, int dev, int pin, int swiz, int *iline)
{
}
/* 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_softc *sc)
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_decompose_tag = pq3pci_decompose_tag;
pc->pc_conf_hook = pq3pci_conf_hook;
pc->pc_msix_v = sc;
genppc_pci_chipset_msix_init(pc);
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);

View File

@ -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_ibm4xx_chipset = {
.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,

View File

@ -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 *);

View File

@ -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

View File

@ -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.11 2013/08/23 06:18:14 matt Exp $");
#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);

View File

@ -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_attach_args_pc(
#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,6 +284,33 @@ pci_intr_setattr(pci_chipset_tag_t pc, pci_intr_handle_t *ihp, int attr,
return (*pc->pc_intr_setattr)(pc->pc_intr_v, ihp, attr, data);
}
__pci_inline pci_intr_type_t
pci_intr_type(pci_chipset_tag_t pc, pci_intr_handle_t ih)
{
return (*pc->pc_intr_type)(pc->pc_intr_v, ih);
}
__pci_inline int
pci_intr_alloc(const struct pci_attach_args *pa, pci_intr_handle_t **ihps,
int *count, pci_intr_type_t max_type)
{
pci_chipset_tag_t pc = pci_attach_args_pc(pa);
return (*pc->pc_intr_alloc)(pa, ihps, count, max_type);
}
__pci_inline void
pci_intr_release(pci_chipset_tag_t pc, pci_intr_handle_t *ihp, int count)
{
(*pc->pc_intr_release)(pc->pc_intr_v, ihp, count);
}
__pci_inline int
pci_intx_alloc(const struct pci_attach_args *pa, pci_intr_handle_t **ihps)
{
pci_chipset_tag_t pc = pci_attach_args_pc(pa);
return (*pc->pc_intx_alloc)(pa, ihps);
}
__pci_inline void
pci_conf_interrupt(pci_chipset_tag_t pc, int bus, int device, int pin,
@ -274,70 +326,47 @@ pci_conf_hook(pci_chipset_tag_t pc, int bus, int device, int function,
return (*pc->pc_conf_hook)(pc->pc_conf_v, bus, device, function, id);
}
/* experimental MSI support */
__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_msi_alloc(const struct pci_attach_args *pa, pci_intr_handle_t **ihps,
int *count)
{
return (*pci_attach_args_pc(pa)->pc_msi_request)(pa, msihp, nmsi,
ipl, capid);
pci_chipset_tag_t pc = pci_attach_args_pc(pa);
return (*pc->pc_msi_alloc)(pa, ihps, count, false);
}
__pci_inline int
pci_msi_type(pci_chipset_tag_t pc, pci_msi_handle_t msih)
pci_msi_alloc_exact(const struct pci_attach_args *pa, pci_intr_handle_t **ihps,
int count)
{
return (*pc->pc_msi_type)(pc->pc_msi_v, msih);
pci_chipset_tag_t pc = pci_attach_args_pc(pa);
return (*pc->pc_msi_alloc)(pa, ihps, &count, true);
}
__pci_inline size_t
pci_msi_available(pci_chipset_tag_t pc, pci_msi_handle_t msih)
/* experimental MSI-X support */
__pci_inline int
pci_msix_alloc(const struct pci_attach_args *pa, pci_intr_handle_t **ihps,
int *count)
{
return (*pc->pc_msi_available)(pc->pc_msi_v, msih);
pci_chipset_tag_t pc = pci_attach_args_pc(pa);
return (*pc->pc_msix_alloc)(pa, ihps, NULL, count, false);
}
__pci_inline const char *
pci_msi_string(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)
{
return (*pc->pc_msi_string)(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 const struct evcnt *
pci_msi_evcnt(pci_chipset_tag_t pc, pci_msi_handle_t msih, size_t msirq)
__pci_inline int
pci_msix_alloc_map(const struct pci_attach_args *pa, pci_intr_handle_t **ihps,
u_int *table_indexes, int count)
{
return (*pc->pc_msi_evcnt)(pc->pc_msi_v, msih, msirq);
}
__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)
{
return (*pc->pc_msi_establish)(pc->pc_msi_v, msih, msirq, ipl,
func, arg);
}
__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)
{
return (*pc->pc_msix_establish)(pc->pc_msi_v, msih, vec, msirq, ipl,
func, arg);
}
__pci_inline void
pci_msi_disestablish(pci_chipset_tag_t pc, void *ih)
{
(*pc->pc_msi_disestablish)(pc->pc_msi_v, ih);
}
__pci_inline void
pci_msi_free(pci_chipset_tag_t pc, pci_msi_handle_t msih, size_t msirq)
{
(*pc->pc_msi_free)(pc->pc_msi_v, msih, msirq);
}
__pci_inline void
pci_msi_release(pci_chipset_tag_t pc, pci_msi_handle_t msih)
{
(*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_attach_args *,
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 **);
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);
/* 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);
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);

View File

@ -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.c,v 1.5 2013/07/05 02:18:37 joerg Exp $"
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_chipset = {
.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_chipset = {
.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,

View File

@ -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_common.c,v 1.20 2014/03/29 19:28:29 chri
#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_handle_t ih)
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_intr_handle_t ih, int level,
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_intr_handle_t *ihp, int attr,
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__);
}
void
genppc_pci_msi_release(void *v, pci_msi_handle_t msih)
{
panic("%s", __func__);
return EOPNOTSUPP;
}
void
genppc_pci_chipset_msi_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_msi_alloc = genppc_pci_msi_alloc;
}
void
genppc_pci_chipset_msix_init(pci_chipset_tag_t pc)
{
pc->pc_msix_alloc = genppc_pci_msix_alloc;
}
#ifdef __HAVE_PCIIDE_MACHDEP_COMPAT_INTR_ESTABLISH

View File

@ -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.24 2016/05/26 17:38:05 macallan Exp $");
#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>
@ -131,6 +132,13 @@ fakeintr(void *arg)
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;
@ -147,7 +155,6 @@ intr_establish(int hwirq, int type, int ipl, int (*ih_fun)(void *),
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 ipl, int (*ih_fun)(void *),
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 ipl, int (*ih_fun)(void *),
*/
intr_calculatemasks();
return ih;
}
@ -718,3 +726,156 @@ genppc_isa_intr_alloc(isa_chipset_tag_t ic, struct pic_ops *pic,
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;
}

View File

@ -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 = &null_intrsw;
#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;

View File

@ -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_chipset_tag_t pc)
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;

View File

@ -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_chipset_tag_t pc)
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;

View File

@ -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_tag_t, pci_intr_handle_t,
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);

View File

@ -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.c,v 1.34 2015/10/02 05:22:52 msaitoh Exp
#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, pci_intr_handle_t ih, char *buf,
}
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, pci_intr_handle_t *ih,
}
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_handle_t ih, int level,
* 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, int bus, int dev,
}
}
#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;
}