Remove the old pre-INTRNG arm64 interrupt framework. GENERIC was switched

to INTRNG in r301565 with the old code no longer being built by default with
no reports of issues on any supported hardware.

Approved by:	re (gjb)
Obtained from:	ABT Systems Ltd
Sponsored by:	The FreeBSD Foundation
This commit is contained in:
Andrew Turner 2016-07-06 16:20:10 +00:00
parent 24b9bb5614
commit b760df65c8
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=302375
7 changed files with 0 additions and 3560 deletions

View File

@ -1,496 +0,0 @@
/*-
* Copyright (c) 2011 The FreeBSD Foundation
* Copyright (c) 2014 Andrew Turner
* All rights reserved.
*
* Developed by Damjan Marion <damjan.marion@gmail.com>
*
* Based on OMAP4 GIC code by Ben Gray
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the company nor the name of the author may be used to
* endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/kernel.h>
#include <sys/ktr.h>
#include <sys/module.h>
#include <sys/rman.h>
#include <sys/pcpu.h>
#include <sys/proc.h>
#include <sys/cpuset.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <machine/bus.h>
#include <machine/intr.h>
#include <machine/smp.h>
#include <vm/vm.h>
#include <vm/pmap.h>
#include <arm64/arm64/gic.h>
#include "pic_if.h"
/* We are using GICv2 register naming */
/* Distributor Registers */
#define GICD_CTLR 0x000 /* v1 ICDDCR */
#define GICD_TYPER 0x004 /* v1 ICDICTR */
#define GICD_IIDR 0x008 /* v1 ICDIIDR */
#define GICD_IGROUPR(n) (0x0080 + ((n) * 4)) /* v1 ICDISER */
#define GICD_ISENABLER(n) (0x0100 + ((n) * 4)) /* v1 ICDISER */
#define GICD_ICENABLER(n) (0x0180 + ((n) * 4)) /* v1 ICDICER */
#define GICD_ISPENDR(n) (0x0200 + ((n) * 4)) /* v1 ICDISPR */
#define GICD_ICPENDR(n) (0x0280 + ((n) * 4)) /* v1 ICDICPR */
#define GICD_ICACTIVER(n) (0x0380 + ((n) * 4)) /* v1 ICDABR */
#define GICD_IPRIORITYR(n) (0x0400 + ((n) * 4)) /* v1 ICDIPR */
#define GICD_ITARGETSR(n) (0x0800 + ((n) * 4)) /* v1 ICDIPTR */
#define GICD_ICFGR(n) (0x0C00 + ((n) * 4)) /* v1 ICDICFR */
#define GICD_SGIR(n) (0x0F00 + ((n) * 4)) /* v1 ICDSGIR */
#define GICD_SGI_TARGET_SHIFT 16
/* CPU Registers */
#define GICC_CTLR 0x0000 /* v1 ICCICR */
#define GICC_PMR 0x0004 /* v1 ICCPMR */
#define GICC_BPR 0x0008 /* v1 ICCBPR */
#define GICC_IAR 0x000C /* v1 ICCIAR */
#define GICC_EOIR 0x0010 /* v1 ICCEOIR */
#define GICC_RPR 0x0014 /* v1 ICCRPR */
#define GICC_HPPIR 0x0018 /* v1 ICCHPIR */
#define GICC_ABPR 0x001C /* v1 ICCABPR */
#define GICC_IIDR 0x00FC /* v1 ICCIIDR*/
#define GIC_FIRST_IPI 0 /* Irqs 0-15 are SGIs/IPIs. */
#define GIC_LAST_IPI 15
#define GIC_FIRST_PPI 16 /* Irqs 16-31 are private (per */
#define GIC_LAST_PPI 31 /* core) peripheral interrupts. */
#define GIC_FIRST_SPI 32 /* Irqs 32+ are shared peripherals. */
/* TYPER Registers */
#define GICD_TYPER_SECURITYEXT 0x400
#define GIC_SUPPORT_SECEXT(_sc) \
((_sc->typer & GICD_TYPER_SECURITYEXT) == GICD_TYPER_SECURITYEXT)
/* First bit is a polarity bit (0 - low, 1 - high) */
#define GICD_ICFGR_POL_LOW (0 << 0)
#define GICD_ICFGR_POL_HIGH (1 << 0)
#define GICD_ICFGR_POL_MASK 0x1
/* Second bit is a trigger bit (0 - level, 1 - edge) */
#define GICD_ICFGR_TRIG_LVL (0 << 1)
#define GICD_ICFGR_TRIG_EDGE (1 << 1)
#define GICD_ICFGR_TRIG_MASK 0x2
static struct resource_spec arm_gic_spec[] = {
{ SYS_RES_MEMORY, 0, RF_ACTIVE }, /* Distributor registers */
{ SYS_RES_MEMORY, 1, RF_ACTIVE }, /* CPU Interrupt Intf. registers */
{ -1, 0 }
};
static u_int arm_gic_map[MAXCPU];
static struct arm_gic_softc *arm_gic_sc = NULL;
#define gic_c_read_4(_sc, _reg) \
bus_space_read_4((_sc)->gic_c_bst, (_sc)->gic_c_bsh, (_reg))
#define gic_c_write_4(_sc, _reg, _val) \
bus_space_write_4((_sc)->gic_c_bst, (_sc)->gic_c_bsh, (_reg), (_val))
#define gic_d_read_4(_sc, _reg) \
bus_space_read_4((_sc)->gic_d_bst, (_sc)->gic_d_bsh, (_reg))
#define gic_d_write_4(_sc, _reg, _val) \
bus_space_write_4((_sc)->gic_d_bst, (_sc)->gic_d_bsh, (_reg), (_val))
static pic_dispatch_t gic_dispatch;
static pic_eoi_t gic_eoi;
static pic_mask_t gic_mask_irq;
static pic_unmask_t gic_unmask_irq;
static uint8_t
gic_cpu_mask(struct arm_gic_softc *sc)
{
uint32_t mask;
int i;
/* Read the current cpuid mask by reading ITARGETSR{0..7} */
for (i = 0; i < 8; i++) {
mask = gic_d_read_4(sc, GICD_ITARGETSR(i));
if (mask != 0)
break;
}
/* No mask found, assume we are on CPU interface 0 */
if (mask == 0)
return (1);
/* Collect the mask in the lower byte */
mask |= mask >> 16;
mask |= mask >> 8;
return (mask);
}
#ifdef SMP
static void
gic_init_secondary(device_t dev)
{
struct arm_gic_softc *sc = device_get_softc(dev);
int i;
/* Set the mask so we can find this CPU to send it IPIs */
arm_gic_map[PCPU_GET(cpuid)] = gic_cpu_mask(sc);
for (i = 0; i < sc->nirqs; i += 4)
gic_d_write_4(sc, GICD_IPRIORITYR(i >> 2), 0);
/* Set all the interrupts to be in Group 0 (secure) */
for (i = 0; GIC_SUPPORT_SECEXT(sc) && i < sc->nirqs; i += 32) {
gic_d_write_4(sc, GICD_IGROUPR(i >> 5), 0);
}
/* Enable CPU interface */
gic_c_write_4(sc, GICC_CTLR, 1);
/* Set priority mask register. */
gic_c_write_4(sc, GICC_PMR, 0xff);
/* Enable interrupt distribution */
gic_d_write_4(sc, GICD_CTLR, 0x01);
/*
* Activate the timer interrupts: virtual, secure, and non-secure.
*/
gic_d_write_4(sc, GICD_ISENABLER(27 >> 5), (1UL << (27 & 0x1F)));
gic_d_write_4(sc, GICD_ISENABLER(29 >> 5), (1UL << (29 & 0x1F)));
gic_d_write_4(sc, GICD_ISENABLER(30 >> 5), (1UL << (30 & 0x1F)));
}
#endif
int
arm_gic_attach(device_t dev)
{
struct arm_gic_softc *sc;
int i;
uint32_t icciidr, mask;
if (arm_gic_sc)
return (ENXIO);
sc = device_get_softc(dev);
if (bus_alloc_resources(dev, arm_gic_spec, sc->gic_res)) {
device_printf(dev, "could not allocate resources\n");
return (ENXIO);
}
sc->gic_dev = dev;
arm_gic_sc = sc;
/* Initialize mutex */
mtx_init(&sc->mutex, "GIC lock", "", MTX_SPIN);
/* Distributor Interface */
sc->gic_d_bst = rman_get_bustag(sc->gic_res[0]);
sc->gic_d_bsh = rman_get_bushandle(sc->gic_res[0]);
/* CPU Interface */
sc->gic_c_bst = rman_get_bustag(sc->gic_res[1]);
sc->gic_c_bsh = rman_get_bushandle(sc->gic_res[1]);
/* Disable interrupt forwarding to the CPU interface */
gic_d_write_4(sc, GICD_CTLR, 0x00);
/* Get the number of interrupts */
sc->typer = gic_d_read_4(sc, GICD_TYPER);
sc->nirqs = 32 * ((sc->typer & 0x1f) + 1);
arm_register_root_pic(dev, sc->nirqs);
icciidr = gic_c_read_4(sc, GICC_IIDR);
device_printf(dev,"pn 0x%x, arch 0x%x, rev 0x%x, implementer 0x%x irqs %u\n",
icciidr>>20, (icciidr>>16) & 0xF, (icciidr>>12) & 0xf,
(icciidr & 0xfff), sc->nirqs);
/* Set all global interrupts to be level triggered, active low. */
for (i = 32; i < sc->nirqs; i += 16) {
gic_d_write_4(sc, GICD_ICFGR(i >> 4), 0x00000000);
}
/* Disable all interrupts. */
for (i = 32; i < sc->nirqs; i += 32) {
gic_d_write_4(sc, GICD_ICENABLER(i >> 5), 0xFFFFFFFF);
}
/* Find the current cpu mask */
mask = gic_cpu_mask(sc);
/* Set the mask so we can find this CPU to send it IPIs */
arm_gic_map[PCPU_GET(cpuid)] = mask;
/* Set all four targets to this cpu */
mask |= mask << 8;
mask |= mask << 16;
for (i = 0; i < sc->nirqs; i += 4) {
gic_d_write_4(sc, GICD_IPRIORITYR(i >> 2), 0);
if (i > 32) {
gic_d_write_4(sc, GICD_ITARGETSR(i >> 2), mask);
}
}
/* Set all the interrupts to be in Group 0 (secure) */
for (i = 0; GIC_SUPPORT_SECEXT(sc) && i < sc->nirqs; i += 32) {
gic_d_write_4(sc, GICD_IGROUPR(i >> 5), 0);
}
/* Enable CPU interface */
gic_c_write_4(sc, GICC_CTLR, 1);
/* Set priority mask register. */
gic_c_write_4(sc, GICC_PMR, 0xff);
/* Enable interrupt distribution */
gic_d_write_4(sc, GICD_CTLR, 0x01);
return (0);
}
static void gic_dispatch(device_t dev, struct trapframe *frame)
{
struct arm_gic_softc *sc = device_get_softc(dev);
uint32_t active_irq;
int first = 1;
while (1) {
active_irq = gic_c_read_4(sc, GICC_IAR);
/*
* Immediatly EOIR the SGIs, because doing so requires the other
* bits (ie CPU number), not just the IRQ number, and we do not
* have this information later.
*/
if ((active_irq & 0x3ff) <= GIC_LAST_IPI)
gic_c_write_4(sc, GICC_EOIR, active_irq);
active_irq &= 0x3FF;
if (active_irq == 0x3FF) {
if (first)
printf("Spurious interrupt detected\n");
return;
}
arm_dispatch_intr(active_irq, frame);
first = 0;
}
}
static void
gic_eoi(device_t dev, u_int irq)
{
struct arm_gic_softc *sc = device_get_softc(dev);
gic_c_write_4(sc, GICC_EOIR, irq);
}
void
gic_mask_irq(device_t dev, u_int irq)
{
struct arm_gic_softc *sc = device_get_softc(dev);
gic_d_write_4(sc, GICD_ICENABLER(irq >> 5), (1UL << (irq & 0x1F)));
gic_c_write_4(sc, GICC_EOIR, irq);
}
void
gic_unmask_irq(device_t dev, u_int irq)
{
struct arm_gic_softc *sc = device_get_softc(dev);
gic_d_write_4(sc, GICD_ISENABLER(irq >> 5), (1UL << (irq & 0x1F)));
}
#ifdef SMP
static void
gic_ipi_send(device_t dev, cpuset_t cpus, u_int ipi)
{
struct arm_gic_softc *sc = device_get_softc(dev);
uint32_t val = 0, i;
for (i = 0; i < MAXCPU; i++)
if (CPU_ISSET(i, &cpus))
val |= arm_gic_map[i] << GICD_SGI_TARGET_SHIFT;
gic_d_write_4(sc, GICD_SGIR(0), val | ipi);
}
#endif
static device_method_t arm_gic_methods[] = {
/* Device interface */
DEVMETHOD(device_attach, arm_gic_attach),
/* pic_if */
DEVMETHOD(pic_dispatch, gic_dispatch),
DEVMETHOD(pic_eoi, gic_eoi),
DEVMETHOD(pic_mask, gic_mask_irq),
DEVMETHOD(pic_unmask, gic_unmask_irq),
#ifdef SMP
DEVMETHOD(pic_init_secondary, gic_init_secondary),
DEVMETHOD(pic_ipi_send, gic_ipi_send),
#endif
{ 0, 0 }
};
DEFINE_CLASS_0(gic, arm_gic_driver, arm_gic_methods,
sizeof(struct arm_gic_softc));
#define GICV2M_MSI_TYPER 0x008
#define MSI_TYPER_SPI_BASE(x) (((x) >> 16) & 0x3ff)
#define MSI_TYPER_SPI_COUNT(x) (((x) >> 0) & 0x3ff)
#define GICv2M_MSI_SETSPI_NS 0x040
#define GICV2M_MSI_IIDR 0xFCC
static int
gicv2m_attach(device_t dev)
{
struct gicv2m_softc *sc;
uint32_t typer;
int rid;
sc = device_get_softc(dev);
rid = 0;
sc->sc_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
if (sc->sc_mem == NULL) {
device_printf(dev, "Unable to allocate resources\n");
return (ENXIO);
}
typer = bus_read_4(sc->sc_mem, GICV2M_MSI_TYPER);
sc->sc_spi_start = MSI_TYPER_SPI_BASE(typer);
sc->sc_spi_count = MSI_TYPER_SPI_COUNT(typer);
device_printf(dev, "using spi %u to %u\n", sc->sc_spi_start,
sc->sc_spi_start + sc->sc_spi_count - 1);
mtx_init(&sc->sc_mutex, "GICv2m lock", "", MTX_DEF);
arm_register_msi_pic(dev);
return (0);
}
static int
gicv2m_alloc_msix(device_t dev, device_t pci_dev, int *pirq)
{
struct arm_gic_softc *psc;
struct gicv2m_softc *sc;
uint32_t reg;
int irq;
psc = device_get_softc(device_get_parent(dev));
sc = device_get_softc(dev);
mtx_lock(&sc->sc_mutex);
/* Find an unused interrupt */
KASSERT(sc->sc_spi_offset < sc->sc_spi_count, ("No free SPIs"));
irq = sc->sc_spi_start + sc->sc_spi_offset;
sc->sc_spi_offset++;
/* Interrupts need to be edge triggered, set this */
reg = gic_d_read_4(psc, GICD_ICFGR(irq >> 4));
reg |= (GICD_ICFGR_TRIG_EDGE | GICD_ICFGR_POL_HIGH) <<
((irq & 0xf) * 2);
gic_d_write_4(psc, GICD_ICFGR(irq >> 4), reg);
*pirq = irq;
mtx_unlock(&sc->sc_mutex);
return (0);
}
static int
gicv2m_alloc_msi(device_t dev, device_t pci_dev, int count, int *irqs)
{
struct arm_gic_softc *psc;
struct gicv2m_softc *sc;
uint32_t reg;
int i, irq;
psc = device_get_softc(device_get_parent(dev));
sc = device_get_softc(dev);
mtx_lock(&sc->sc_mutex);
KASSERT(sc->sc_spi_offset + count <= sc->sc_spi_count,
("No free SPIs for %d MSI interrupts", count));
/* Find an unused interrupt */
for (i = 0; i < count; i++) {
irq = sc->sc_spi_start + sc->sc_spi_offset;
sc->sc_spi_offset++;
/* Interrupts need to be edge triggered, set this */
reg = gic_d_read_4(psc, GICD_ICFGR(irq >> 4));
reg |= (GICD_ICFGR_TRIG_EDGE | GICD_ICFGR_POL_HIGH) <<
((irq & 0xf) * 2);
gic_d_write_4(psc, GICD_ICFGR(irq >> 4), reg);
irqs[i] = irq;
}
mtx_unlock(&sc->sc_mutex);
return (0);
}
static int
gicv2m_map_msi(device_t dev, device_t pci_dev, int irq, uint64_t *addr,
uint32_t *data)
{
struct gicv2m_softc *sc = device_get_softc(dev);
*addr = vtophys(rman_get_virtual(sc->sc_mem)) + 0x40;
*data = irq;
return (0);
}
static device_method_t arm_gicv2m_methods[] = {
/* Device interface */
DEVMETHOD(device_attach, gicv2m_attach),
/* MSI/MSI-X */
DEVMETHOD(pic_alloc_msix, gicv2m_alloc_msix),
DEVMETHOD(pic_alloc_msi, gicv2m_alloc_msi),
DEVMETHOD(pic_map_msi, gicv2m_map_msi),
{ 0, 0 }
};
DEFINE_CLASS_0(gicv2m, arm_gicv2m_driver, arm_gicv2m_methods,
sizeof(struct gicv2m_softc));

View File

@ -1,161 +0,0 @@
/*-
* Copyright (c) 2015 The FreeBSD Foundation
* All rights reserved.
*
* This software was developed by Andrew Turner under
* sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/types.h>
#include <sys/bus.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <machine/bus.h>
#include <arm64/arm64/gic.h>
#include <contrib/dev/acpica/include/acpi.h>
#include <dev/acpica/acpivar.h>
struct arm_gic_acpi_softc {
struct arm_gic_softc gic_sc;
struct resource_list res;
};
struct madt_table_data {
device_t parent;
ACPI_MADT_GENERIC_DISTRIBUTOR *dist;
ACPI_MADT_GENERIC_INTERRUPT *intr;
};
static void
madt_handler(ACPI_SUBTABLE_HEADER *entry, void *arg)
{
struct madt_table_data *madt_data;
madt_data = (struct madt_table_data *)arg;
switch(entry->Type) {
case ACPI_MADT_TYPE_GENERIC_INTERRUPT:
if (madt_data->intr != NULL) {
if (bootverbose)
device_printf(madt_data->parent,
"gic: Already have an interrupt table");
break;
}
madt_data->intr = (ACPI_MADT_GENERIC_INTERRUPT *)entry;
break;
case ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR:
if (madt_data->dist != NULL) {
if (bootverbose)
device_printf(madt_data->parent,
"gic: Already have a distributor table");
break;
}
madt_data->dist = (ACPI_MADT_GENERIC_DISTRIBUTOR *)entry;
break;
default:
break;
}
}
static void
arm_gic_acpi_identify(driver_t *driver, device_t parent)
{
struct madt_table_data madt_data;
ACPI_TABLE_MADT *madt;
vm_paddr_t physaddr;
device_t dev;
physaddr = acpi_find_table(ACPI_SIG_MADT);
if (physaddr == 0)
return;
madt = acpi_map_table(physaddr, ACPI_SIG_MADT);
if (madt == NULL) {
device_printf(parent, "gic: Unable to map the MADT\n");
return;
}
madt_data.parent = parent;
madt_data.dist = NULL;
madt_data.intr = NULL;
acpi_walk_subtables(madt + 1, (char *)madt + madt->Header.Length,
madt_handler, &madt_data);
if (madt_data.intr == NULL || madt_data.dist == NULL) {
device_printf(parent,
"No gic interrupt or distributor table\n");
goto out;
}
dev = BUS_ADD_CHILD(parent, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE,
"gic", -1);
if (dev == NULL) {
device_printf(parent, "add gic child failed\n");
goto out;
}
/* Add the MADT data */
BUS_SET_RESOURCE(parent, dev, SYS_RES_MEMORY, 0,
madt_data.dist->BaseAddress, PAGE_SIZE);
BUS_SET_RESOURCE(parent, dev, SYS_RES_MEMORY, 1,
madt_data.intr->BaseAddress, PAGE_SIZE);
out:
acpi_unmap_table(madt);
}
static int
arm_gic_acpi_probe(device_t dev)
{
device_set_desc(dev, "ARM Generic Interrupt Controller");
return (BUS_PROBE_NOWILDCARD);
}
static device_method_t arm_gic_acpi_methods[] = {
/* Device interface */
DEVMETHOD(device_identify, arm_gic_acpi_identify),
DEVMETHOD(device_probe, arm_gic_acpi_probe),
DEVMETHOD_END
};
DEFINE_CLASS_1(gic, arm_gic_acpi_driver, arm_gic_acpi_methods,
sizeof(struct arm_gic_acpi_softc), arm_gic_driver);
static devclass_t arm_gic_acpi_devclass;
EARLY_DRIVER_MODULE(gic, acpi, arm_gic_acpi_driver,
arm_gic_acpi_devclass, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);

View File

@ -1,332 +0,0 @@
/*-
* Copyright (c) 2015 The FreeBSD Foundation
* All rights reserved.
*
* This software was developed by Andrew Turner under
* sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/rman.h>
#include <machine/bus.h>
#include <dev/ofw/openfirm.h>
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
#include <arm64/arm64/gic.h>
static struct ofw_compat_data compat_data[] = {
{"arm,gic", true}, /* Non-standard, used in FreeBSD dts. */
{"arm,gic-400", true},
{"arm,cortex-a15-gic", true},
{"arm,cortex-a9-gic", true},
{"arm,cortex-a7-gic", true},
{"arm,arm11mp-gic", true},
{"brcm,brahma-b15-gic", true},
{"qcom,msm-qgic2", true},
{NULL, false}
};
struct gic_range {
uint64_t bus;
uint64_t host;
uint64_t size;
};
struct arm_gic_fdt_softc {
struct arm_gic_softc sc_gic;
pcell_t sc_host_cells;
pcell_t sc_addr_cells;
pcell_t sc_size_cells;
struct gic_range *sc_ranges;
int sc_nranges;
};
struct gic_devinfo {
struct ofw_bus_devinfo obdinfo;
struct resource_list rl;
};
static int
gic_fill_ranges(phandle_t node, struct arm_gic_fdt_softc *sc)
{
cell_t *base_ranges;
ssize_t nbase_ranges;
int i, j, k;
nbase_ranges = OF_getproplen(node, "ranges");
if (nbase_ranges < 0)
return (-1);
sc->sc_nranges = nbase_ranges / sizeof(cell_t) /
(sc->sc_addr_cells + sc->sc_host_cells + sc->sc_size_cells);
if (sc->sc_nranges == 0)
return (0);
sc->sc_ranges = malloc(sc->sc_nranges * sizeof(sc->sc_ranges[0]),
M_DEVBUF, M_WAITOK);
base_ranges = malloc(nbase_ranges, M_DEVBUF, M_WAITOK);
OF_getencprop(node, "ranges", base_ranges, nbase_ranges);
for (i = 0, j = 0; i < sc->sc_nranges; i++) {
sc->sc_ranges[i].bus = 0;
for (k = 0; k < sc->sc_addr_cells; k++) {
sc->sc_ranges[i].bus <<= 32;
sc->sc_ranges[i].bus |= base_ranges[j++];
}
sc->sc_ranges[i].host = 0;
for (k = 0; k < sc->sc_host_cells; k++) {
sc->sc_ranges[i].host <<= 32;
sc->sc_ranges[i].host |= base_ranges[j++];
}
sc->sc_ranges[i].size = 0;
for (k = 0; k < sc->sc_size_cells; k++) {
sc->sc_ranges[i].size <<= 32;
sc->sc_ranges[i].size |= base_ranges[j++];
}
}
free(base_ranges, M_DEVBUF);
return (sc->sc_nranges);
}
static int
arm_gic_fdt_probe(device_t dev)
{
if (!ofw_bus_status_okay(dev))
return (ENXIO);
if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data)
return (ENXIO);
device_set_desc(dev, "ARM Generic Interrupt Controller");
return (BUS_PROBE_DEFAULT);
}
static int
arm_gic_fdt_attach(device_t dev)
{
struct arm_gic_fdt_softc *sc = device_get_softc(dev);
phandle_t root, child;
struct gic_devinfo *dinfo;
device_t cdev;
int err;
err = arm_gic_attach(dev);
if (err != 0)
return (err);
root = ofw_bus_get_node(dev);
sc->sc_host_cells = 1;
OF_getencprop(OF_parent(root), "#address-cells", &sc->sc_host_cells,
sizeof(sc->sc_host_cells));
sc->sc_addr_cells = 2;
OF_getencprop(root, "#address-cells", &sc->sc_addr_cells,
sizeof(sc->sc_addr_cells));
sc->sc_size_cells = 2;
OF_getencprop(root, "#size-cells", &sc->sc_size_cells,
sizeof(sc->sc_size_cells));
/* If we have no children don't probe for them */
child = OF_child(root);
if (child == 0)
return (0);
if (gic_fill_ranges(root, sc) < 0) {
device_printf(dev, "could not get ranges\n");
return (ENXIO);
}
for (; child != 0; child = OF_peer(child)) {
dinfo = malloc(sizeof(*dinfo), M_DEVBUF, M_WAITOK | M_ZERO);
if (ofw_bus_gen_setup_devinfo(&dinfo->obdinfo, child) != 0) {
free(dinfo, M_DEVBUF);
continue;
}
resource_list_init(&dinfo->rl);
ofw_bus_reg_to_rl(dev, child, sc->sc_addr_cells,
sc->sc_size_cells, &dinfo->rl);
cdev = device_add_child(dev, NULL, -1);
if (cdev == NULL) {
device_printf(dev, "<%s>: device_add_child failed\n",
dinfo->obdinfo.obd_name);
resource_list_free(&dinfo->rl);
ofw_bus_gen_destroy_devinfo(&dinfo->obdinfo);
free(dinfo, M_DEVBUF);
continue;
}
device_set_ivars(cdev, dinfo);
}
bus_generic_probe(dev);
return (bus_generic_attach(dev));
}
static struct resource *
arm_gic_fdt_alloc_resource(device_t bus, device_t child, int type, int *rid,
rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
{
struct arm_gic_fdt_softc *sc = device_get_softc(bus);
struct gic_devinfo *di;
struct resource_list_entry *rle;
int j;
KASSERT(type == SYS_RES_MEMORY, ("Invalid resoure type %x", type));
/*
* Request for the default allocation with a given rid: use resource
* list stored in the local device info.
*/
if (RMAN_IS_DEFAULT_RANGE(start, end)) {
if ((di = device_get_ivars(child)) == NULL)
return (NULL);
if (type == SYS_RES_IOPORT)
type = SYS_RES_MEMORY;
rle = resource_list_find(&di->rl, type, *rid);
if (rle == NULL) {
if (bootverbose)
device_printf(bus, "no default resources for "
"rid = %d, type = %d\n", *rid, type);
return (NULL);
}
start = rle->start;
end = rle->end;
count = rle->count;
}
/* Remap through ranges property */
for (j = 0; j < sc->sc_nranges; j++) {
if (start >= sc->sc_ranges[j].bus && end <
sc->sc_ranges[j].bus + sc->sc_ranges[j].size) {
start -= sc->sc_ranges[j].bus;
start += sc->sc_ranges[j].host;
end -= sc->sc_ranges[j].bus;
end += sc->sc_ranges[j].host;
break;
}
}
if (j == sc->sc_nranges && sc->sc_nranges != 0) {
if (bootverbose)
device_printf(bus, "Could not map resource "
"%#lx-%#lx\n", start, end);
return (NULL);
}
return (bus_generic_alloc_resource(bus, child, type, rid, start, end,
count, flags));
}
static const struct ofw_bus_devinfo *
arm_gic_fdt_ofw_get_devinfo(device_t bus __unused, device_t child)
{
struct gic_devinfo *di;
di = device_get_ivars(child);
return (&di->obdinfo);
}
static device_method_t arm_gic_fdt_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, arm_gic_fdt_probe),
DEVMETHOD(device_attach, arm_gic_fdt_attach),
/* Bus interface */
DEVMETHOD(bus_add_child, bus_generic_add_child),
DEVMETHOD(bus_alloc_resource, arm_gic_fdt_alloc_resource),
DEVMETHOD(bus_release_resource, bus_generic_release_resource),
DEVMETHOD(bus_activate_resource,bus_generic_activate_resource),
/* ofw_bus interface */
DEVMETHOD(ofw_bus_get_devinfo, arm_gic_fdt_ofw_get_devinfo),
DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat),
DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model),
DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name),
DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node),
DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type),
DEVMETHOD_END
};
DEFINE_CLASS_1(gic, arm_gic_fdt_driver, arm_gic_fdt_methods,
sizeof(struct arm_gic_fdt_softc), arm_gic_driver);
static devclass_t arm_gic_fdt_devclass;
EARLY_DRIVER_MODULE(gic, simplebus, arm_gic_fdt_driver,
arm_gic_fdt_devclass, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);
EARLY_DRIVER_MODULE(gic, ofwbus, arm_gic_fdt_driver, arm_gic_fdt_devclass,
0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);
static struct ofw_compat_data gicv2m_compat_data[] = {
{"arm,gic-v2m-frame", true},
{NULL, false}
};
static int
arm_gicv2m_fdt_probe(device_t dev)
{
if (!ofw_bus_status_okay(dev))
return (ENXIO);
if (!ofw_bus_search_compatible(dev, gicv2m_compat_data)->ocd_data)
return (ENXIO);
device_set_desc(dev, "ARM Generic Interrupt Controller MSI/MSIX");
return (BUS_PROBE_DEFAULT);
}
static device_method_t arm_gicv2m_fdt_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, arm_gicv2m_fdt_probe),
/* End */
DEVMETHOD_END
};
DEFINE_CLASS_1(gicv2m, arm_gicv2m_fdt_driver, arm_gicv2m_fdt_methods,
sizeof(struct gicv2m_softc), arm_gicv2m_driver);
static devclass_t arm_gicv2m_fdt_devclass;
EARLY_DRIVER_MODULE(gicv2m, gic, arm_gicv2m_fdt_driver,
arm_gicv2m_fdt_devclass, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);

File diff suppressed because it is too large Load Diff

View File

@ -1,584 +0,0 @@
/*-
* Copyright (c) 1991 The Regents of the University of California.
* Copyright (c) 2002 Benno Rice.
* Copyright (c) 2014 The FreeBSD Foundation
* All rights reserved.
*
* This software was developed by Semihalf under
* the sponsorship of the FreeBSD Foundation.
*
* This code is derived from software contributed by
* William Jolitz (Berkeley) and Benno Rice.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* form: src/sys/powerpc/powerpc/intr_machdep.c, r271712 2014/09/17
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/proc.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/kernel.h>
#include <sys/ktr.h>
#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/mutex.h>
#include <sys/cpuset.h>
#include <sys/interrupt.h>
#include <sys/queue.h>
#include <sys/smp.h>
#include <machine/cpufunc.h>
#include <machine/intr.h>
#ifdef SMP
#include <machine/smp.h>
#endif
#include "pic_if.h"
#define MAX_STRAY_LOG 5
#define INTRNAME_LEN (MAXCOMLEN + 1)
#define NIRQS 1024 /* Maximum number of interrupts in the system */
static MALLOC_DEFINE(M_INTR, "intr", "Interrupt Services");
/*
* Linked list of interrupts that have been set-up.
* Each element holds the interrupt description
* and has to be allocated and freed dynamically.
*/
static SLIST_HEAD(, arm64_intr_entry) irq_slist_head =
SLIST_HEAD_INITIALIZER(irq_slist_head);
struct arm64_intr_entry {
SLIST_ENTRY(arm64_intr_entry) entries;
struct intr_event *i_event;
enum intr_trigger i_trig;
enum intr_polarity i_pol;
u_int i_hw_irq; /* Physical interrupt number */
u_int i_cntidx; /* Index in intrcnt table */
u_int i_handlers; /* Allocated handlers */
u_int i_cpu; /* Assigned CPU */
u_long *i_cntp; /* Interrupt hit counter */
};
/* Counts and names for statistics - see sys/sys/interrupt.h */
/* Tables are indexed by i_cntidx */
u_long intrcnt[NIRQS];
char intrnames[NIRQS * INTRNAME_LEN];
size_t sintrcnt = sizeof(intrcnt);
size_t sintrnames = sizeof(intrnames);
static u_int intrcntidx; /* Current index into intrcnt table */
static u_int arm64_nintrs; /* Max interrupts number of the root PIC */
static u_int arm64_nstray; /* Number of received stray interrupts */
static device_t root_pic; /* PIC device for all incoming interrupts */
static device_t msi_pic; /* Device which handles MSI/MSI-X interrupts */
static struct mtx intr_list_lock;
static void
intr_init(void *dummy __unused)
{
mtx_init(&intr_list_lock, "intr sources lock", NULL, MTX_SPIN);
}
SYSINIT(intr_init, SI_SUB_INTR, SI_ORDER_FIRST, intr_init, NULL);
/*
* Helper routines.
*/
/* Set interrupt name for statistics */
static void
intrcnt_setname(const char *name, u_int idx)
{
snprintf(&intrnames[idx * INTRNAME_LEN], INTRNAME_LEN, "%-*s",
INTRNAME_LEN - 1, name);
}
/*
* Find the interrupt descriptor in the list
* based on the hardware IRQ number.
*/
static __inline struct arm64_intr_entry *
intr_lookup_locked(u_int hw_irq)
{
struct arm64_intr_entry *intr;
mtx_assert(&intr_list_lock, MA_OWNED);
SLIST_FOREACH(intr, &irq_slist_head, entries) {
if (intr->i_hw_irq == hw_irq)
return (intr);
}
return (NULL);
}
/*
* Get intr structure for the given interrupt number.
* Allocate one if this is the first time.
*/
static struct arm64_intr_entry *
intr_allocate(u_int hw_irq)
{
struct arm64_intr_entry *intr;
/* Check if already allocated */
mtx_lock_spin(&intr_list_lock);
intr = intr_lookup_locked(hw_irq);
mtx_unlock_spin(&intr_list_lock);
if (intr != NULL)
return (intr);
/* Do not alloc another intr when max number of IRQs has been reached */
if (intrcntidx >= NIRQS)
return (NULL);
intr = malloc(sizeof(*intr), M_INTR, M_NOWAIT);
if (intr == NULL)
return (NULL);
/* The default CPU is 0 but can be changed later by bind or shuffle */
intr->i_cpu = 0;
intr->i_event = NULL;
intr->i_handlers = 0;
intr->i_trig = INTR_TRIGGER_CONFORM;
intr->i_pol = INTR_POLARITY_CONFORM;
intr->i_cntidx = atomic_fetchadd_int(&intrcntidx, 1);
intr->i_cntp = &intrcnt[intr->i_cntidx];
intr->i_hw_irq = hw_irq;
mtx_lock_spin(&intr_list_lock);
SLIST_INSERT_HEAD(&irq_slist_head, intr, entries);
mtx_unlock_spin(&intr_list_lock);
return intr;
}
static int
intr_assign_cpu(void *arg, int cpu)
{
#ifdef SMP
struct arm64_intr_entry *intr;
int error;
if (root_pic == NULL)
panic("Cannot assing interrupt to CPU. No PIC configured");
/*
* Set the interrupt to CPU affinity.
* Do not configure this in hardware during early boot.
* We will pick up the assignment once the APs are started.
*/
if (cpu != NOCPU) {
intr = arg;
if (!cold && smp_started) {
/*
* Bind the interrupt immediately
* if SMP is up and running.
*/
error = PIC_BIND(root_pic, intr->i_hw_irq, cpu);
if (error == 0)
intr->i_cpu = cpu;
} else {
/* Postpone binding until SMP is operational */
intr->i_cpu = cpu;
error = 0;
}
} else
error = 0;
return (error);
#else
return (EOPNOTSUPP);
#endif
}
static void
intr_pre_ithread(void *arg)
{
struct arm64_intr_entry *intr = arg;
PIC_PRE_ITHREAD(root_pic, intr->i_hw_irq);
}
static void
intr_post_ithread(void *arg)
{
struct arm64_intr_entry *intr = arg;
PIC_POST_ITHREAD(root_pic, intr->i_hw_irq);
}
static void
intr_post_filter(void *arg)
{
struct arm64_intr_entry *intr = arg;
PIC_POST_FILTER(root_pic, intr->i_hw_irq);
}
/*
* Register PIC driver.
* This is intended to be called by the very first PIC driver
* at the end of the successful attach.
* Note that during boot this can be called after first references
* to bus_setup_intr() so it is required to not use root_pic if it
* is not 100% safe.
*/
void
arm_register_root_pic(device_t dev, u_int nirq)
{
KASSERT(root_pic == NULL, ("Unable to set the pic twice"));
KASSERT(nirq <= NIRQS, ("PIC is trying to handle too many IRQs"));
arm64_nintrs = NIRQS; /* Number of IRQs limited only by array size */
root_pic = dev;
}
/* Register device which allocates MSI interrupts */
void
arm_register_msi_pic(device_t dev)
{
KASSERT(msi_pic == NULL, ("Unable to set msi_pic twice"));
msi_pic = dev;
}
int
arm_alloc_msi(device_t pci, device_t child, int count, int maxcount, int *irqs)
{
return (PIC_ALLOC_MSI(msi_pic, child, count, irqs));
}
int
arm_release_msi(device_t pci, device_t child, int count, int *irqs)
{
return (PIC_RELEASE_MSI(msi_pic, child, count, irqs));
}
int
arm_map_msi(device_t pci, device_t child, int irq, uint64_t *addr, uint32_t *data)
{
return (PIC_MAP_MSI(msi_pic, child, irq, addr, data));
}
int
arm_alloc_msix(device_t pci, device_t child, int *irq)
{
return (PIC_ALLOC_MSIX(msi_pic, child, irq));
}
int
arm_release_msix(device_t pci, device_t child, int irq)
{
return (PIC_RELEASE_MSIX(msi_pic, child, irq));
}
/*
* Finalize interrupts bring-up (should be called from configure_final()).
* Enables all interrupts registered by bus_setup_intr() during boot
* as well as unlocks interrups reception on primary CPU.
*/
int
arm_enable_intr(void)
{
struct arm64_intr_entry *intr;
if (root_pic == NULL)
panic("Cannot enable interrupts. No PIC configured");
/*
* Iterate through all possible interrupts and perform
* configuration if the interrupt is registered.
*/
SLIST_FOREACH(intr, &irq_slist_head, entries) {
/*
* XXX: In case we allowed to set up interrupt whose number
* exceeds maximum number of interrupts for the root PIC
* disable it and print proper error message.
*
* This can happen only when calling bus_setup_intr()
* before the interrupt controller is attached.
*/
if (intr->i_cntidx >= arm64_nintrs) {
/* Better fail when IVARIANTS enabled */
KASSERT(0, ("%s: Interrupt %u cannot be handled by the "
"registered PIC. Max interrupt number: %u", __func__,
intr->i_cntidx, arm64_nintrs - 1));
/* Print message and disable otherwise */
printf("ERROR: Cannot enable irq %u. Disabling.\n",
intr->i_cntidx);
PIC_MASK(root_pic, intr->i_hw_irq);
}
if (intr->i_trig != INTR_TRIGGER_CONFORM ||
intr->i_pol != INTR_POLARITY_CONFORM) {
PIC_CONFIG(root_pic, intr->i_hw_irq,
intr->i_trig, intr->i_pol);
}
if (intr->i_handlers > 0)
PIC_UNMASK(root_pic, intr->i_hw_irq);
}
/* Enable interrupt reception on this CPU */
intr_enable();
return (0);
}
int
arm_setup_intr(const char *name, driver_filter_t *filt, driver_intr_t handler,
void *arg, u_int hw_irq, enum intr_type flags, void **cookiep)
{
struct arm64_intr_entry *intr;
int error;
intr = intr_allocate(hw_irq);
if (intr == NULL)
return (ENOMEM);
/*
* Watch out for interrupts' numbers.
* If this is a system boot then don't allow to overfill interrupts
* table (the interrupts will be deconfigured in arm_enable_intr()).
*/
if (intr->i_cntidx >= NIRQS)
return (EINVAL);
if (intr->i_event == NULL) {
error = intr_event_create(&intr->i_event, (void *)intr, 0,
hw_irq, intr_pre_ithread, intr_post_ithread,
intr_post_filter, intr_assign_cpu, "irq%u", hw_irq);
if (error)
return (error);
}
error = intr_event_add_handler(intr->i_event, name, filt, handler, arg,
intr_priority(flags), flags, cookiep);
if (!error) {
intrcnt_setname(intr->i_event->ie_fullname, intr->i_cntidx);
intr->i_handlers++;
if (!cold && intr->i_handlers == 1) {
if (intr->i_trig != INTR_TRIGGER_CONFORM ||
intr->i_pol != INTR_POLARITY_CONFORM) {
PIC_CONFIG(root_pic, intr->i_hw_irq, intr->i_trig,
intr->i_pol);
}
PIC_UNMASK(root_pic, intr->i_hw_irq);
}
}
return (error);
}
int
intr_irq_remove_handler(device_t dev, u_int irq, void *cookie)
{
struct arm64_intr_entry *intr;
int error;
intr = intr_handler_source(cookie);
error = intr_event_remove_handler(cookie);
if (!error) {
intr->i_handlers--;
if (intr->i_handlers == 0)
PIC_MASK(root_pic, intr->i_hw_irq);
intrcnt_setname(intr->i_event->ie_fullname, intr->i_cntidx);
}
return (error);
}
int
intr_irq_config(u_int hw_irq, enum intr_trigger trig, enum intr_polarity pol)
{
struct arm64_intr_entry *intr;
mtx_lock_spin(&intr_list_lock);
intr = intr_lookup_locked(hw_irq);
mtx_unlock_spin(&intr_list_lock);
if (intr == NULL)
return (EINVAL);
intr->i_trig = trig;
intr->i_pol = pol;
if (!cold && root_pic != NULL)
PIC_CONFIG(root_pic, intr->i_hw_irq, trig, pol);
return (0);
}
void
arm_dispatch_intr(u_int hw_irq, struct trapframe *tf)
{
struct arm64_intr_entry *intr;
mtx_lock_spin(&intr_list_lock);
intr = intr_lookup_locked(hw_irq);
mtx_unlock_spin(&intr_list_lock);
if (intr == NULL)
goto stray;
(*intr->i_cntp)++;
if (!intr_event_handle(intr->i_event, tf))
return;
stray:
if (arm64_nstray < MAX_STRAY_LOG) {
arm64_nstray++;
printf("Stray IRQ %u\n", hw_irq);
if (arm64_nstray >= MAX_STRAY_LOG) {
printf("Got %d stray IRQs. Not logging anymore.\n",
MAX_STRAY_LOG);
}
}
if (intr != NULL)
PIC_MASK(root_pic, intr->i_hw_irq);
}
void
intr_irq_handler(struct trapframe *tf)
{
critical_enter();
PIC_DISPATCH(root_pic, tf);
critical_exit();
#ifdef HWPMC_HOOKS
if (pmc_hook && (PCPU_GET(curthread)->td_pflags & TDP_CALLCHAIN))
pmc_hook(PCPU_GET(curthread), PMC_FN_USER_CALLCHAIN, tf);
#endif
}
#ifdef SMP
static void
arm_intr_smp_init(void *dummy __unused)
{
struct arm64_intr_entry *intr;
int error;
if (root_pic == NULL)
panic("Cannot assing interrupts to CPUs. No PIC configured");
mtx_lock_spin(&intr_list_lock);
SLIST_FOREACH(intr, &irq_slist_head, entries) {
mtx_unlock_spin(&intr_list_lock);
error = PIC_BIND(root_pic, intr->i_hw_irq, intr->i_cpu);
if (error != 0)
intr->i_cpu = 0;
mtx_lock_spin(&intr_list_lock);
}
mtx_unlock_spin(&intr_list_lock);
}
SYSINIT(arm_intr_smp_init, SI_SUB_SMP, SI_ORDER_ANY, arm_intr_smp_init, NULL);
/* Attempt to bind the specified IRQ to the specified CPU. */
int
intr_irq_bind(u_int hw_irq, int cpu)
{
struct arm64_intr_entry *intr;
mtx_lock_spin(&intr_list_lock);
intr = intr_lookup_locked(hw_irq);
mtx_unlock_spin(&intr_list_lock);
if (intr == NULL)
return (EINVAL);
return (intr_event_bind(intr->i_event, cpu));
}
void
arm_setup_ipihandler(driver_filter_t *filt, u_int ipi)
{
arm_setup_intr("ipi", filt, NULL, (void *)((uintptr_t)ipi | 1<<16), ipi,
INTR_TYPE_MISC | INTR_EXCL, NULL);
arm_unmask_ipi(ipi);
}
void
arm_unmask_ipi(u_int ipi)
{
PIC_UNMASK(root_pic, ipi);
}
void
arm_init_secondary(void)
{
PIC_INIT_SECONDARY(root_pic);
}
/* Sending IPI */
void
ipi_all_but_self(u_int ipi)
{
cpuset_t other_cpus;
other_cpus = all_cpus;
CPU_CLR(PCPU_GET(cpuid), &other_cpus);
CTR2(KTR_SMP, "%s: ipi: %x", __func__, ipi);
PIC_IPI_SEND(root_pic, other_cpus, ipi);
}
void
ipi_cpu(int cpu, u_int ipi)
{
cpuset_t cpus;
CPU_ZERO(&cpus);
CPU_SET(cpu, &cpus);
CTR2(KTR_SMP, "ipi_cpu: cpu: %d, ipi: %x", cpu, ipi);
PIC_IPI_SEND(root_pic, cpus, ipi);
}
void
ipi_selected(cpuset_t cpus, u_int ipi)
{
CTR1(KTR_SMP, "ipi_selected: ipi: %x", ipi);
PIC_IPI_SEND(root_pic, cpus, ipi);
}
#endif

View File

@ -1,176 +0,0 @@
#-
# Copyright (c) 1998 Doug Rabson
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# from: src/sys/kern/bus_if.m,v 1.21 2002/04/21 11:16:10 markm Exp
# $FreeBSD$
#
#include <sys/bus.h>
#include <sys/cpuset.h>
#include <machine/frame.h>
INTERFACE pic;
CODE {
static int pic_bind_default(device_t dev, u_int irq, u_int cpu)
{
return (EOPNOTSUPP);
}
static void pic_translate_code_default(device_t dev, u_int irq,
int code, enum intr_trigger *trig, enum intr_polarity *pol)
{
*trig = INTR_TRIGGER_CONFORM;
*pol = INTR_POLARITY_CONFORM;
}
static void pic_pre_ithread(device_t dev, u_int irq)
{
PIC_MASK(dev, irq);
PIC_EOI(dev, irq);
}
static void pic_post_ithread(device_t dev, u_int irq)
{
PIC_UNMASK(dev, irq);
}
static void pic_post_filter(device_t dev, u_int irq)
{
PIC_EOI(dev, irq);
}
};
METHOD int bind {
device_t dev;
u_int irq;
u_int cpu;
} DEFAULT pic_bind_default;
METHOD void translate_code {
device_t dev;
u_int irq;
int code;
enum intr_trigger *trig;
enum intr_polarity *pol;
} DEFAULT pic_translate_code_default;
METHOD void config {
device_t dev;
u_int irq;
enum intr_trigger trig;
enum intr_polarity pol;
};
METHOD void dispatch {
device_t dev;
struct trapframe *tf;
};
METHOD void enable {
device_t dev;
u_int irq;
u_int vector;
};
METHOD void pre_ithread {
device_t dev;
u_int irq;
} DEFAULT pic_pre_ithread;
METHOD void post_ithread {
device_t dev;
u_int irq;
} DEFAULT pic_post_ithread;
METHOD void post_filter {
device_t dev;
u_int irq;
} DEFAULT pic_post_filter;
METHOD void eoi {
device_t dev;
u_int irq;
};
METHOD void ipi {
device_t dev;
u_int cpu;
};
METHOD void mask {
device_t dev;
u_int irq;
};
METHOD void unmask {
device_t dev;
u_int irq;
};
METHOD void init_secondary {
device_t dev;
};
METHOD void ipi_send {
device_t dev;
cpuset_t cpus;
u_int ipi;
};
METHOD int alloc_msi {
device_t dev;
device_t pci_dev;
int count;
int *irqs;
};
METHOD int alloc_msix {
device_t dev;
device_t pci_dev;
int *irq;
};
METHOD int map_msi {
device_t dev;
device_t pci_dev;
int irq;
uint64_t *addr;
uint32_t *data;
};
METHOD int release_msi {
device_t dev;
device_t pci_dev;
int count;
int *irqs;
};
METHOD int release_msix {
device_t dev;
device_t pci_dev;
int irq;
};

View File

@ -25,15 +25,10 @@ arm64/arm64/disassem.c optional ddb
arm64/arm64/dump_machdep.c standard
arm64/arm64/elf_machdep.c standard
arm64/arm64/exception.S standard
arm64/arm64/gic.c optional !intrng
arm64/arm64/gicv3_its.c optional intrng
arm64/arm64/gic_acpi.c optional !intrng acpi
arm64/arm64/gic_fdt.c optional !intrng fdt
arm64/arm64/gic_v3.c standard
arm64/arm64/gic_v3_fdt.c optional fdt
arm64/arm64/gic_v3_its.c optional !intrng
arm64/arm64/identcpu.c standard
arm64/arm64/intr_machdep.c optional !intrng
arm64/arm64/in_cksum.c optional inet | inet6
arm64/arm64/locore.S standard no-obj
arm64/arm64/machdep.c standard
@ -42,7 +37,6 @@ arm64/arm64/minidump_machdep.c standard
arm64/arm64/mp_machdep.c optional smp
arm64/arm64/nexus.c standard
arm64/arm64/ofw_machdep.c optional fdt
arm64/arm64/pic_if.m optional !intrng
arm64/arm64/pmap.c standard
arm64/arm64/stack_machdep.c optional ddb | stack
arm64/arm64/support.S standard